C++ 将一个双倍值乘以10,会发生什么情况

C++ 将一个双倍值乘以10,会发生什么情况,c++,floating-point,numbers,precision,C++,Floating Point,Numbers,Precision,我最近一直想知道浮点数的乘法。 让我们假设我有一个数字,例如3.1415,保证3位精度。 现在,我把这个值乘以10,得到31.415X,其中X是一个我不能理解的数字 由于精度有限,请定义 现在,我能确定,五个get被精确地带到了数字上吗? 如果一个数字被证明是精确到3位数,我就不会期望这样了 五总是弹出那里,但在学习了很多C++案例之后,我注意到它总是发生。 然而,从我的观点来看,这没有任何意义,因为浮点数是以2为基数存储的,所以乘10是不可能的,它总是乘10的倍数 我问这个问题是因为我想创建一

我最近一直想知道浮点数的乘法。 让我们假设我有一个数字,例如3.1415,保证3位精度。 现在,我把这个值乘以10,得到31.415X,其中X是一个我不能理解的数字 由于精度有限,请定义

现在,我能确定,五个get被精确地带到了数字上吗? 如果一个数字被证明是精确到3位数,我就不会期望这样了 五总是弹出那里,但在学习了很多C++案例之后,我注意到它总是发生。 然而,从我的观点来看,这没有任何意义,因为浮点数是以2为基数存储的,所以乘10是不可能的,它总是乘10的倍数

我问这个问题是因为我想创建一个函数来计算类型的精度。我想出了这样的办法:

template <typename T>
unsigned accuracy(){
        unsigned acc = 0;
        T num = (T)1/(T)3;
        while((unsigned)(num *= 10) == 3){
                acc++;
                num -= 3;
        }
        return acc;
}

现在,这适用于我使用过的任何类型,但我仍然不确定第一个不精确的数字是否总是以不变的形式进行携带。

我将专门讨论IEEE754 double,因为我认为这是您想要的

double被定义为符号位、11位指数和52位尾数,它们连接起来形成64位值:

sign|exponent|mantissa
指数位以有偏格式存储,这意味着我们存储双精度的实际指数+1023。全零指数和全一指数是特殊的,因此我们最终能够表示从2^-1022到2^+1023的指数

这是一个常见的误解,即整数值不能用双精度表示,但实际上我们可以通过正确设置尾数和指数来精确地存储[0,2^53]中的任何整数,事实上范围[2^52,2^53]只能存储该范围内的整数值。因此,10很容易精确地存储在双精度中

当涉及到双倍乘法时,我们实际上有两个这种形式的数字:

A = (-1)^sA*mA*2^(eA-1023)
B = (-1)^sB*mB*2^(eB-1023)
其中sA、mA、eA是A的符号、尾数和指数,类似地是B的符号、尾数和指数

如果我们乘以这些:

A*B = (-1)^(sA+sB)*(mA*mB)*2^((eA-1023)+(eB-1023))
我们可以看到,我们只是对指数求和,然后乘以尾数。这实际上对精度并不坏!我们可能会溢出指数位,从而得到一个无穷大,但除此之外,我们只需要将中间尾数结果取整回52位,但最坏的情况是,这只会改变新m中最低有效位安提萨

最终,你将看到的误差将与结果的大小成正比。但是,双倍的误差与它们的大小成正比,所以这是我们能得到的最安全的。在你的数字中,近似误差的方法是|大小|*2^-53。在你的例子中,由于10是精确的,唯一的误差将出现在表示中它将有一个~2^-51的误差,因此结果也是如此


作为经验法则,当考虑精度问题时,我考虑双倍的小数精度为15位。

< P>我将详细讨论IEEE75 4双倍,因为这是我想问的。< /P> double被定义为符号位、11位指数和52位尾数,它们连接起来形成64位值:

sign|exponent|mantissa
指数位以有偏格式存储,这意味着我们存储双精度的实际指数+1023。全零指数和全一指数是特殊的,因此我们最终能够表示从2^-1022到2^+1023的指数

这是一个常见的误解,即整数值不能用双精度表示,但实际上我们可以通过正确设置尾数和指数来精确地存储[0,2^53]中的任何整数,事实上范围[2^52,2^53]只能存储该范围内的整数值。因此,10很容易精确地存储在双精度中

当涉及到双倍乘法时,我们实际上有两个这种形式的数字:

A = (-1)^sA*mA*2^(eA-1023)
B = (-1)^sB*mB*2^(eB-1023)
其中sA、mA、eA是A的符号、尾数和指数,类似地是B的符号、尾数和指数

如果我们乘以这些:

A*B = (-1)^(sA+sB)*(mA*mB)*2^((eA-1023)+(eB-1023))
我们可以看到,我们只是对指数求和,然后乘以尾数。这实际上对精度并不坏!我们可能会溢出指数位,从而得到一个无穷大,但除此之外,我们只需要将中间尾数结果取整回52位,但最坏的情况是,这只会改变新m中最低有效位安提萨

最终,你将看到的误差将与结果的大小成正比。但是,双倍的误差与它们的大小成正比,所以这是我们能得到的最安全的。在你的数字中,近似误差的方法是|大小|*2^-53。在你的例子中,由于10是精确的,唯一的误差将出现在表示中它将有一个~2^-51的误差,因此结果也是如此

作为经验法则,当考虑精度问题时,我考虑双倍的小数精度为15位数。

现在,我能确定吗,tha 这五个get不是被精确的数字覆盖了吗

通常不会。只有当您知道系统使用的精确表示格式,并且知道正确的输出可以用该格式精确表示时,才能确定输出的精度

若你们想要任何有理输入的精确结果,那个么你们不能使用有限精度

函数似乎试图计算浮点类型表示1/3的准确度。此精度对于评估表示其他数字的精度不有用

因为浮点数是以2为基数存储的

虽然这很常见,但并非普遍如此。例如,有些系统使用base-10

现在,我能确定,五个get被精确地带到了数字上吗

通常不会。只有当您知道系统使用的精确表示格式,并且知道正确的输出可以用该格式精确表示时,才能确定输出的精度

若你们想要任何有理输入的精确结果,那个么你们不能使用有限精度

函数似乎试图计算浮点类型表示1/3的准确度。此精度对于评估表示其他数字的精度不有用

因为浮点数是以2为基数存储的


虽然这很常见,但并非普遍如此。例如,有些系统使用base-10。

让我们假设对于单精度,3.1415是

0x40490E56

在IEEE 754格式中,这是一种非常流行但不是唯一使用的格式

0100000001001001000011001010110 10000000 1001001000011001010110

所以二进制部分是1.1001001000011001010110

11001001000011001010110 1100 1001 0000 1110 0101 0110 0xC90E56*10=0x7DA8F5C

就像在小学学习十进制一样,你以后会担心小数点/二进制点,你只需要做一个乘法

01111.101101010001111010111100

要进入IEEE 754格式,需要将其转换为1.5尾数格式 这是一个3的移位

1.11110101000111101011

但是看看从100切下的三个位,特别是1,这意味着取决于取整模式,在本例中,让我们取整

1.11110101000111101100

0111011010101000111011100

0x7BA1EC

现在,如果我已经计算出答案:

0x41FB51EC

0 1000001111110110101000111101100

我们移动了点3,指数反映了尾数与我们计算的相符。我们确实丢失了右侧的一个原始非零位,但这是不是太多了


双精度,扩展,以同样的方式工作,只是更多的指数和尾数位,更高的精度和范围。但归根结底,它只不过是我们在小学里学到的。就数学而言,格式要求1。尾数,所以你必须用小学数学来调整基数的指数,以得到该形式。让我们假设单精度为3.1415

0x40490E56

在IEEE 754格式中,这是一种非常流行但不是唯一使用的格式

0100000001001001000011001010110 10000000 1001001000011001010110

所以二进制部分是1.1001001000011001010110

11001001000011001010110 1100 1001 0000 1110 0101 0110 0xC90E56*10=0x7DA8F5C

就像在小学学习十进制一样,你以后会担心小数点/二进制点,你只需要做一个乘法

01111.101101010001111010111100

要进入IEEE 754格式,需要将其转换为1.5尾数格式 这是一个3的移位

1.11110101000111101011

但是看看从100切下的三个位,特别是1,这意味着取决于取整模式,在本例中,让我们取整

1.11110101000111101100

0111011010101000111011100

0x7BA1EC

现在,如果我已经计算出答案:

0x41FB51EC

0 1000001111110110101000111101100

我们移动了点3,指数反映了尾数与我们计算的相符。我们确实丢失了右侧的一个原始非零位,但这是不是太多了


双精度,扩展,以同样的方式工作,只是更多的指数和尾数位,更高的精度和范围。但归根结底,这只不过是我们在小学学到的。就数学而言,格式要求1。尾数,所以你必须用小学数学来调整基数的指数,使其达到那种形式。

这不是完全正确的……浮点数是以2为底存储的。。。。它们存储为基2上的1和基2指数。例如,0.5可以精确表示,但0.1不能。相关/可能重复:这不完全正确…浮点数以2为基数存储。。。。它们存储为基2上的1和基2指数。例如0.5可以精确表示,但0.1不能。相关/可能重复:首选术语
r浮点数的分数与指数部分是“有效位”。“尾数”是表示对数分数部分的一个旧词。有效位是线性的,将10%添加到1会增加10%表示的值。尾数是对数加10%到1乘以10^.1表示的值。IEEE二进制64的有效位是53位,而不是52位。52存储在有效位字段中,但1通过指数字段进行编码。binary64操作中的错误数与结果½ULP的大小成正比,而不仅仅与结果的大小成正比。换句话说,误差有一个已知的界限,它与结果的大小成正比,但这并不意味着误差与它成正比。误差可以是零或从零到界的任何值。“在您的情况下,由于10是精确的,唯一的误差将出现在pi的表示中。它将有~2^-51的误差,因此结果也将是正确的。”似乎不正确。问题作者以3.1415为例,它不是π,但我们假设它们的意思是π。然后,在将π转换为浮点格式时会出现一个错误,在进行10的浮点乘法时会出现第二个错误。这些错误可能会复合或恰好取消。初始误差的界值为2^-52 ULP,约3为2^-51,界值为½ULP。乘以10将误差相乘,再加上一个。浮点数的分数与指数部分的首选术语是“有效位”。“尾数”是表示对数分数部分的旧词。有效位是线性的,将10%添加到1会增加10%表示的值。尾数是对数加10%到1乘以10^.1表示的值。IEEE二进制64的有效位是53位,而不是52位。52存储在有效位字段中,但1通过指数字段进行编码。binary64操作中的错误数与结果½ULP的大小成正比,而不仅仅与结果的大小成正比。换句话说,误差有一个已知的界限,它与结果的大小成正比,但这并不意味着误差与它成正比。误差可以是零或从零到界的任何值。“在您的情况下,由于10是精确的,唯一的误差将出现在pi的表示中。它将有~2^-51的误差,因此结果也将是正确的。”似乎不正确。问题作者以3.1415为例,它不是π,但我们假设它们的意思是π。然后,在将π转换为浮点格式时会出现一个错误,在进行10的浮点乘法时会出现第二个错误。这些错误可能会复合或恰好取消。初始误差的界值为2^-52 ULP,约3为2^-51,界值为½ULP。乘以10将使误差相乘,再加上一个误差。