各位老司机应该知道,很多时候做小数运算的时候会出现小数溢出。常见的场景是做价格运算,测试经常报bug。
于是针对这个奇特的问题,开始了寻根之旅。
举个例子:0.2+0.1=0.30000000000000004
为什么会这样?
其实很多其他计算机语言都有这个问题。计算机中的所有运算都会经过二进制转换再计算的。
0.2的二进制是
0.2 * 2 = 0.4 取整数位 0 得 0.0
0.4 * 2 = 0.8 取整数位 0 得 0.00
0.8 * 2 = 1.6 取整数位 1 得 0.001
0.6 * 2 = 1.2 取整数位 1 得 0.0011
0.2 * 2 = 0.4 取整数位 0 得 0.00110
(n)….
太长了 于是直接在控制台上打印
var num = 0.2;
num.toString(2)
// "0.001100110011001100110011001100110011001100110011001101"
同理算出 0.1的二进制为
// "0.0001100110011001100110011001100110011001100110011001101"
两个二进制相加得出
// "0.0100110011001100110011001100110011001100110011001100111"
根据这个IEEE754的标准 就会把最后的 1 舍去变成
0.0100110011001100110011001100110011001100110011001101
然后转成十进制得出结果是 0.30000000000000004
再举个例子 0.1+0.3 = 0.4
为什么这两个数不会产生溢出呢?
算出 0.1的二进制为
// "0.0001100110011001100110011001100110011001100110011001101"
算出 0.4的二进制为
// "0.01100110011001100110011001100110011001100110011001101"
两个二进制相加得出
// "0.1000000000000000000000000000000000000000000000000000001"
根据这个IEEE754的标准 就会把最后的第52位进一舍零,得到
"0.1000000000000000000000000000000000000000000000000000"
剩下0.1 转换十进制为0.5
找了网上的一张图,其实还不是完全看懂指数位是什么。。。。