为什么某些浮点计算会像他们那样转变? (例如123456789f +1 = 123456792)

时间:2017-11-18 14:54:06

标签: floating-point precision floating-accuracy

我试图更好地理解浮点运算,出现和累积的出现错误,以及为什么结果与他们的结果完全一致。以下是我正在研究的3个例子:

1。) 0.1 + 0.1 +0.1 +0.1 +0.1 +0.1 +0.1 +0.1 +0.1 +0.1 -1.0 = -1.1102230246251565E-16 又名< em> 0.1 10 次给我一个略小于 1.0 的数字。但是, 0.1 表示(作为双精度)略大于 0.1 。此外* 0.1 * 3 *略大于 0.3 ,但* 0.1 * 8 *略小于 0.8

2。) 123456789f + 1 = 123456792和123456789f +4 = 123456800。

这些结果是什么?对我来说,这一切仍然有点神秘。

1 个答案:

答案 0 :(得分:4)

典型的现代处理器和编程语言使用IEEE-754算法(或多或少),float的32位二进制浮点和double的64位二进制浮点。在double中,使用了53位有效数字。这意味着,当十进制数字转换为double时,它将转换为某个数字 s f •2 e < / em> ,其中 s 是一个符号(+1或-1), f 是一个无符号整数,可用53位表示,并且< em> e 是介于-1074和971之间的整数。 (或者,如果转换的数字太大,结果可能是+无穷大或无穷大。)(那些知道浮点格式的人可能会抱怨指数恰好在-1023和1023之间,但我已经改变了有意义使它成为一个整数。我描述的是数学值,而不是编码。)

将.1转换为double会产生3602879701896397/36028797018963968,因为在所需形式的所有数字中,最接近.1的数字。分母为2 -55 ,因此 e 为-55。

当我们添加其中两个时,我们得到7205759403792794/36028797018963968。没关系,分子仍小于2 53 ,因此它符合格式。

当我们添加第三个3602879701896397/36028797018963968时,数学结果为10808639105689191/36028797018963968。不幸的是,分子太大了;它大于2 53 (9007199254740992)。因此浮点硬件无法返回该数字。它必须以某种方式使它适合。

如果我们将分子和分母除以2,我们有5404319552844595.5 / 18014398509481984.它具有相同的值,但分子不是整数。为了使其适合,硬件将其舍入为整数。当分数正好是1/2时,规则是舍入以使结果均匀,因此硬件返回5404319552844596/18014398509481984。

接下来,我们获取当前金额5404319552844596/18014398509481984,并再次添加3602879701896397/36028797018963968。这次总和是7205759403792794.5 / 18014398509481984.在这种情况下,硬件向下舍入,返回7205759403792794/18014398509481984。

然后我们添加7205759403792794/18014398509481984和3602879701896397/36028797018963968,总和为9007199254740992.5 / 18014398509481984。注意,分子不仅具有分数而且大于2 53 。所以我们必须再次减少它,产生4503599627370496.25 / 9007199254740992.将分子舍入为整数产生4503599627370496 / 9007199254740992.

这正好是1/2。此时,舍入错误恰好被取消了;添加.1五次准确收益.5。

当我们添加4503599627370496/9007199254740992和3602879701896397/36028797018963968时,结果正好是5404319552844595.25 / 9007199254740992.硬件向下舍入并返回5404319552844595 / 9007199254740992.

现在你可以看到我们将反复向下舍入。要将3602879701896397/36028797018963968添加到累加和,硬件必须将其分子除以4以使其匹配。这意味着小数部分总是为.25,它将向下舍入。所以接下来的四个总和也是向下舍入的。我们最终得到9007199254740991/9007199254740992,这个数字不到1个。

使用float而不是double,分子必须符合24位,因此必须小于2 24 (16777216)。因此,即使在任何算术运算之前,123456789也太大了。它必须表示为15432099•2 3 ,即123456792.加1的精确数学结果是15432099.125•2 3 ,并将有效数舍入为整数15432099•2 3 ,所以没有变化。但是,如果你加4,结果是15432099.5•2 3 ,那轮到15432100•2 3