0.1 + 0.2 !== 0.3

345 阅读2分钟

0.1 + 0.2 !== 0.3

0.1 + 0.2;
// 0.30000000000000004

为什么?

因为精度丢失,所以 0.1 + 0.2 !== 0.3

能说再具体一些吗?

呃.....

具体

首先,十进制的0.1和0.2都会被转换成二进制,但由于浮点数用二进制表达时是无穷的

为什么浮点数用二进制表达时是无穷的?

详解二进制浮点数 :

浮点数并不能表示所有实数,比如1.375可以被精确表示,因为 [公式] 。但是在例1中,1.41.1两个数都不能被精确表示,用[4]的链接可以将浮点数字面量转换成真实存储的值,可以看到1.4被近似成了1.399999999999999,1.1被近似成了1.10000000000000008所以两数相减得到的不是0.3而是0.2999999999999998

两个双精度数之间的最小相对误差是 2 -52 约等于 2.22 x 10 -16 ,所以只能保证15位有效数字,第16位只是部分精确。单精度则只能保证6位有效数字,第7位部分精确。所以在例2中 4.0 + 1e16 = 1.0000000000000004e16,恰巧第16位有效数字是部分精确的,4可以被精确表示,但是 5.0 + 1e16 = 1.0000000000000004e16,因为最后一位并不能表示5,所以出现了浮点数误差。4.0 + 1e17 的结果中的4已经在第17位,超出了双精度浮点数的最大有效位数,就被忽略了,所以有 4.0 + 1e17 = 1e17 => 4.0 + 1e17 - 1e17 = 0.0。

标准的 64 位双精度浮点数的小数部分最多支持 53 位二进制位,所以浮点数小数位的限制而截断的二进制数字,进行运算后,再转换为十进制,就会产生误差。

这种问题根本原因是在于:计算机都是0或1标识,对于某浮点准确值,是通过不断增加位数去逼近该值。浮点数实现这种方式就是移位运算,所以不管是在表示还是运算时,都会出现误差。

基础知识补充

JavaScript Number 类型实质是一个64位的浮点数

其中,最高的1位是符号位,接着11位是指数位,剩下的52位是有效数字。

符号位决定数值正负,指数位决定数值大小,有效位决定数值精度。

总结

0.1 + 0.2 !== 0.3 是因为精度丢失导致的。

因为,JavaScript 的 Number 类型是双精度浮点数(64位)表示的,而浮点数不能精确表示所有的实数,有些只能无限逼近,所以会存在误差。

这种问题根本原因是在于:计算机都是0或1标识,对于某浮点准确值,是通过不断增加位数去逼近该值。浮点数实现这种方式就是移位运算,所以不管是在表示还是运算时,都会出现误差。

参考

JavaScript Number范围及超出范围运算方法

详解二进制浮点数