在Stackoverflow上面有这样一个提问
浮点运算的问题
在JavaScript中进行纯小数运算偶尔会得到不正确的结果:
> 0.1 + 0.2 == 0.3
false
> 0.1 + 0.2
0.30000000000000004
很多人马上就开始认为JavaScript设计的不成熟,设计上有缺陷。
实际上这并不是JavaScript仅有的问题,C/C++/Java甚至Matlab都有这个问题,参见: why 0.3-0.2-0.1 not equal to zero。
这只是JavaScript遵循IEEE 754标准所产生的必然结果。IEEE 754标准中的浮点数并不能精确地表达小数(比如说0.1),
- 你需要足够的内存来保留5个数字
- 你需要使用一个取值范围来确保精度。
在硬件层面,除法是转换成乖法来表示的,比如: Z = X/Y 会变成 Z = X * (1/Y);
JavaScript中的小数采用的是双精度(64位)表示的,由三部分组成: 符 + 阶码 + 尾数,在十进制中的 1/10,在十进制中可以简单写为 0.1 ,但在二进制中,他得写成:0.0001100110011001100110011001100110011001100110011001…..(后面全是 1001 循环)。因为浮点数只有52位有效数字,从第53位开始,就舍入了。这样就造成了“浮点数精度损失”问题。 (参考: 出处1, 出处2)
所以你在处理小数运算时要非常小心。
怎么解决
就像标准中提到的,我们可以采用一个精确范围来比较是否相等
x = 0.2;
y = 0.3;
equal = (Math.abs(x - y) < 0.000001)
第二种方法是使用JavaScript内置的函数toPrecision或toFixed来保留一定的精度:
(0.1 + 0.2).toPrecision(10) == 0.3
> true
(0.1 + 0.2).toFixed(10) == 0.3
> true
醉了!
果然等于0.30000000000000004
这bug有点吓人啊,以后写程序小心小心
@bawanag #2
这种问题在实际中遇到的概率非常非常小,通常只要计算中有一个为含整数部的数字即可避免出现纯双精度小数的情况。
如:
public static void main(String[] args) { System.out.println(0.1+0.2); }
0.30000000000000004
以前写了《代码之谜》系列
good
人收到复古风的官方个德国法国代购大股东
@bawanag #2
这不是Bug. 使用二进制必然存在的问题.
@bawanag #2
sb程序员才会认为这是bug.
@华世丰 #9
别管什么原因导致的,是不是必然,计算出来的东西和预计的东西不一样就是BUG。SB才会认为错的东西是对的。
(0.1 + 0.2).toFixed(10) == 0.3是true 但(0.1 + 0.2).toFixed(10) === 0.3是false
1 = 3*(1/3) = 3*0.33333333333 = 0.99999999999
@池片死 #10
0.1 + 0.2 結果是 0.30000000000000004 是「正確」的沒錯啊。
JS 語言定義就是如此,當只寫 0.1 的時候 JS 預設採用 IEEE 754 來描述你的 0.1,在這個條件下 0.1 + 0.2 的結果必然就是 0.30000000000000004。
如果你預計的答案是 0.3,那代表你用錯方法,而不是該語言的 bug。
...
有点意思
看评论原来大家读书都没认真学。。这几乎是程序入门第一课了。。。。
今天遇到了,感觉想不出除了控制精度以外的解决方法