现在每日的 Javascript 提问时间,已经成为了部门前端开发人员的下午茶。这次的问题是:
请问下面的代码会弹出 true or false ?
<script type="text/javascript">
var n1 = 0.1;
var n2 = 0.2;
var n3 = 0.4;
var n4 = 0.8;
alert((n1+n2+n3+n4) === (n1+n2)+(n3+n4));
</script>
这是个很「诡异」的问题。乍看之下应该都是 true,不过「现实是残酷的」,这段代码在各浏览器中的运行结果如上图。
下面的解释还是能让人接受的:「简单来说就是二进制的浮点数难以正确处理十进制的小数」。
其实浮点数的精度问题,在大部分的开发语言中都能碰到(原谅我绝对了)。比如 PHP 中执行
<?php
$a = 0.100000000000000000000000000000001;
var_dump($a + 0.000000000000000001 == $a + 0.000000000000000002);
?>
以及 Java 中运行这样的代码
public static void main(String[] args) {
System.out.print(0.1 + 0.2);
}
也会出现类似的问题(虽然例子可能有点极端,不过已经能够说明问题)。
那么,该如何解决该问题?「解铃还需经理人」,小马 同学在讲解答案的时候,给出了部分解决代码
Math.formatFloat = function(f, digit) {
var m = Math.pow(10, digit);
return parseInt(f * m, 10) / m;
}
alert(Math.formatFloat(0.1 + 0.2, 1)); // 0.3
玉伯的补充:
关于精度问题,一般涉及到小数点时,如果不是0.5, 0.25 这种反复乘以 2 会等于 1 的小
数,其它小数都无法无二进制精确表示,由此造成了误差。比如 10 进制的 0.1, 用二进
制表示是 0.0001100110011001100110........... 无限循环了。
对于进制方面更深一层的了解,请 参阅这里 。
那么,下面的测试
alert((0.1 + 0.2 + 0.4 + 0.8) === ((0.1 + 0.2) + (0.4 + 0.8))); // 已经知道是false
alert((0.1 + 0.2 + 0.4 + 0.8) === ((0.1 + 0.8) + (0.2 + 0.4)));
alert((0.25 + 0.75 + 0.05 + 1.0) === (0.25 + (0.75 + 0.05) + 1.0));
alert((0.25 + 0.75 + 0.05 + 1.0) === ((0.25 + 0.75) + (0.05 + 1.0)));
alert((0.25 + 0.75 + 0.05 + 1.0) === ((1.0 + 0.75) + (0.05 + 0.25)));
其它的 alert 结果是什么?