0

我一直在用 java 编码,最近开始用 javascript 编码(准确地说是 node.js)。让我发疯的一件事是对十进制数进行加法运算;

考虑以下代码

var a=0.1, b=0.2, c=0.3;
var op1 = (a+b)+c;
var op2 = (b+c)+a;

令我惊讶的是,我发现了op1 != op2!console.logging op1 和 op2 打印出以下内容:

console.log(op1); 0.6000000000000001
console.log(op2); 0.6

这根本不符合逻辑。这对我来说似乎是一个错误,因为 javascript 根本无法忽略算术规则。有人可以解释为什么会这样吗?

4

4 回答 4

3

这是浮点错误的情况。

唯一可以用浮点数精确表示的分数是那些可以写成整数分数的分数,分母是 2 的幂。

例如,0.5 可以精确表示,因为它可以写成 1/2。0.3 不能。

在这种情况下,变量和表达式中的舍入误差恰好结合在一起,在第一种情况下会产生错误,但在第二种情况下不会。

这两种方式都没有在幕后准确表示,但是当您输出值时,它会将其四舍五入为 16 位精度。在一种情况下,它四舍五入到一个稍大的数字,而在另一种情况下,它四舍五入到预期值。

您应该吸取的教训是,您永远不应该依赖具有精确值的浮点数,尤其是在进行一些算术运算之后。

于 2012-04-26T17:39:48.923 回答
0

这不是 javascript 问题,而是使用浮点数时每种编程语言的标准问题。您的样本数 0.1、0.2 和 0.3 不能表示为有限小数,而是重复小数,因为它们中有除数 5:0.1 = 1/(2*5) 等等。如果您只使用除数为 2 的小数(如 a=0.5、b=0.25 和 c=0.125),一切都很好。

于 2012-04-26T17:48:42.350 回答
0

发生这种情况是因为并非所有浮点数都可以用二进制准确表示

将所有数字乘以某个数字(例如,如果您处理 2 个小数点,则为 100)。

然后对较大的结果进行算术运算。

算术完成后,除以开始时乘以的相同因子。

http://jsfiddle.net/SjU9d/

a = 10 * a;
b = 10 * b;
c = 10 * c;

op1 = (a+b)+c;
op2 = (b+c)+a;

op1 = op1 / 10;
op2 = op2 / 10;
于 2012-04-26T17:55:20.307 回答
0

使用浮点数时,您可能希望在比较之前设置数字的精度。

(0.1 + 0.2).toFixed(1) == 0.3

但是,在少数情况下,toFixed 在浏览器中的行为方式不同。这是对 toFixed 的修复。

http://bateru.com/news/2012/03/reimplementation-of-number-prototype-tofixed/

于 2012-04-26T18:21:25.717 回答