在使用toFixed函数会出现精度缺失问题,如下图
在2.55与1.45保留1位小数时,正常情况下应该为2.6与1.5,而toFixed函数得出的是2.5与1.4。这和计算机中小数存储有关。
小数运算不精确其实与下面三方面有关:
1、存储
2、运算
3、显示
其实这三个方面都不精确。
存储
计算机中其实没有办法存储一个精确的小数,如下
0.2.toString(2);
// 结果
'0.001100110011001100110011001100110011001100110011001101'
0.2通过toString转化为二进制,如上,其实这是一个无线循环的小数,但是计算机不能存储无限小数,它就会截取,但是这个截取也不是简单的截取,所以最终存储的数据就会出现有大有小的情况。比如通过toPrecision函数确定精度。
0.2.toPrecision(30);
// 结果
'0.200000000000000011102230246252'
0.3.toPrecision(30);
// 结果
'0.299999999999999988897769753748'
它实际得到的是一个比0.2大的数据,而0.3得到的是一个小于本身的数据。
运算
运算有可能精确,也有可能更不精确,比如
0.2 + 0.3 = 0.5
因为0.2存储的时候稍微大一些,0.3存储的时候稍微小一些,但是两个相加,进位抵消变为精确的数据,但是0.2 - 0.3 得到的就不是一个精确的数据。
0.3 - 0.2 = 0.09999999998
显示
显示的时候做了近似处理,当输入0.20000000000000000001110,计算机显示的是0.2,当输入0.199999999999999999999显示的也是0.2,对于计算机而言0.20000000000000000001110 === 0.199999999999999999999是成立的。
所以toFixed函数不精确主要是存储截取的不精确和运算的不精确。
针对这个问题,可以采用第三方插件库,比如decimal.js,核心计算逻辑是将数字转成字符串,在进行一位一位的运算。