为什么具有精确值的浮点数的总和仍取决于顺序?

时间:2018-06-01 02:27:04

标签: javascript floating-point floating-accuracy

假设我有3个浮点数,可以用浮点数精确表示:

var a=0.1000000000000000055511151231257827021181583404541015625;
var b=0.200000000000000011102230246251565404236316680908203125;
var c=0.299999999999999988897769753748434595763683319091796875;
console.log(a+b+c==c+b+a);

它们是实际值0.1,0.2,并且存储在float中的0.3。我认为a + b + c应该等于c + b + a,因为a,b和c都已经四舍五入并且是精确值,它们的总和不应该依赖于顺序,但现在我测试的不是:< / p>

1+2+3 == 3+2+1
0.5+0.375+0.25 == 0.25+0.375+0.5

是什么原因?

注意:我不是在询问Is floating point math broken?,因为0.1000000000000000055511151231257827021181583404541015625已经是浮点数的准确值(某些浮点数可以表示没有舍入错误,例如0.5,0.75和0.375,请参阅:{ {3}})。

我的假设是:a,b和c没有舍入错误,因此它们的总和也应该没有舍入错误,就像

一样
repeat

但是现在a + b + c不是这样的,我的假设在这里有什么不对?

2 个答案:

答案 0 :(得分:3)

总和不完全

您认为精确值的总和是精确的假设是错误的。

浮点运算使用为格式固定的一些数字位数(例如float的24位二进制数字)。两个24位数字的数学和可能有25位数,因此需要舍入来表示24位数(和指数)。

此外,当添加具有不同指数的两个数字时,一个数字相对于另一个数字偏移。由于偏移,总和可能有额外的数字,并且必须再次舍入。

当您以不同的顺序添加数字时,生成的舍入可能会有所不同。

不精确和的例子

这些示例使用三位二进制有效数字。

在此示例中,添加进入新列:

 1.10 • 23
 1.01 • 23
――――――――――
10.11 • 23 Exact sum, too many digits, must be rounded.
11.0  • 23 Sum rounded to three digits.
1.10  • 24 Rounded sum, exponent adjusted to normalize significand.

在此示例中,数字具有不同的指数,并且对此进行调整会将数字转换为新列:

 1.11 • 23
 1.01 • 25   Different exponent requires adjustment.

 0.0111 • 25 Adjusted to match exponent.
 1.01   • 25
――――――――――――
 1.1011 • 25 Exact sum, too many digits, must be rounded.
 1.11   • 25 Rounded sum.

非关联和的例子

现在我们可以看看以不同的方式添加三个数字,并看到产生了不同的总和。

我们将比较(1.10•2 0 + 1.10•2 0 )+ 1.00•2 4 )至1.10•2 0 +(1.10•2 0 + 1.00•2 4 )。

对于第一个表达,我们添加第一个和第二个操作数,然后是第三个:

Add first and second operands:
 1.10 • 20 First operand.
 1.10 • 20 Second operand.
――――――――――
11.00 • 20 Exact sum, too many digits, must be rounded.
11.0  • 20 Rounded sum, must be normalized.
1.10  • 21 Normalized, rounded sum.

Add previous result and third operand:
 1.10 • 21 Previous result.
 1.00 • 24 Third operand.

Exponents do not match, so adjust and then add:
 0.00110 • 24 Previous result adjusted to match exponent.
 1.00    • 24 Third operand.
――――――――――――
 1.00110 • 24 Exact sum, too many digits, must be rounded.
 1.01    • 24 Rounded sum.

对于第二个表达式,我们添加第二个和第三个操作数,然后是第一个:

Add second and third:
 1.10    • 20 Second operand.
 1.00    • 24 Third operand.

Exponents do not match, so adjust, then add:
 0.000110 • 24 Second operand adjusted to match exponent.
 1.00     • 24 Third operand.
――――――――――――――
 1.000110 • 24 Exact sum, too many digits, must be rounded.
 1.00     • 24 Rounded sum.

Add first operand and previous result:
 1.10     • 20 First operand.
 1.00     • 24 Previous result.

Exponents do not match, so adjust and then add:
 0.000110 • 24 First operand adjusted to match exponent.
 1.00     • 24 Previous result.
―――――――――――――
 1.000110 • 24 Exact sum, too many digits, must be rounded.
 1.00     • 24 Rounded sum.

第一个表达式产生1.01•2 4 ,而第二个表达式产生1.00•2 4 。因此,添加操作数的顺序会影响结果。

答案 1 :(得分:0)

我的假设是加法的中间值可能有不同的舍入点误差。例如,a + b可能会导致舍入错误。并且b + c可能没有,或者在添加最终值时,结果值可能会导致不同类型的浮点错误。添加括号使操作顺序和中间值更清晰:

(a + b) + c

(c + b) + a