问题:
在项目中两值计算时(涉及到浮点数计算),得到的值不是预期的,原因是js运算中精度丢失。
常见案例:
0.1 + 0.2 // 结果为 0.30000000000000004
0.3 - 0.1 // 结果为 0.19999999999999996
0.1 * 0.2 // 结果为 0.020000000000000004
0.3 / 0.1 // 结果为 2.9999999999999996
0.1 + 0.2 === 0.3 // 结果为 false
精度丢失的原因:
因为计算机是采用二进制而不是十进制,所以当十进制的数字转化成二进制则变成了无限不循环的数,但是计算机可支持最大尾数位是52位,所以在模仿十进制的四舍五入后就造成了数据的精度缺失,导致计算错误。
解决方法:
先将运算值 x 10^n 转换成整数进行运算,最后将结果还原
// 计算转换成整数需乘的值
integerOperation(val1, val2){
// 获取数值1的小数位的长度
const val1DecimalIndex = val1.toString().indexOf(".");
const len1 = val1DecimalIndex === -1 ? 0 : val1.toString().length - val1DecimalIndex - 1;
// 获取数值2的小数位的长度
const val2DecimalIndex = val2.toString().indexOf(".");
const len2 = val2DecimalIndex === -1 ? 0 : val2.toString().length - val2DecimalIndex - 1;
// 获取大的小数位数
const p = Math.max(len1, len2);
// 避免最终求出结果的长度大于最大长度的时候导致精度丢失 开启下面
// p += p - Math.min(len1, len2);
// Math.pow() 计算一个数的指定次幂的方法 10的p次方
return Math.pow(10, p);
}
// 加法运算
add(val1, val2){
const p = this.integerOperation(val1, val2);
return ((val1 * p) + (val2 * p)) / p;
},
// 减法运算
subtract(val1, val2){
const p = this.integerOperation(val1, val2);
return ((val1 * p) - (val2 * p)) / p;
},
// 乘法运算
multiply(val1, val2){
const p = this.integerOperation(val1, val2);
return ((val1 * p) * (val2 * p)) / (p * p);
},
// 除法运算
multiply(val1, val2){
const p = this.integerOperation(val1, val2);
return ((val1 * p) / (val2 * p)) / (p * p);
},
PS:该方案不能解决所有的情况,如特定情况,可以使用专门的高精度数学库,如 Decimal.js、Big.js 或 BigNumber.js 等,以获得更精确的计算结果。