浮点精度
bug:
小数计算有可能出现精度误差
例如:
0.1 + 0.2 = 0.30000000000000004
0.12 - 0.04 = 0.07999999999999999
0.1 * 0.7 = 0.06999999999999999
原因:
0.1 + 0.2 这个看似简单的问题,众所周知,能被计算机读懂的是二进制,而不是我们经常看见的十进制,所以我们先把0.1 + 0.2转换为十进制,
0.1 => 0.0001 1001 1001 1001…(无限循环)
0.2 => 0.0011 0011 0011 0011…(无限循环)
双精度浮点数的小数部分最多支持 52 位,所以两者相加之后得到这么一串 0.0100110011001100110011001100110011001100110011001100 因浮点数小数位的限制而截断的二进制数字,这时候,我们再把它转换为十进制,就成了 0.30000000000000004。
执行过程:
计算机在计算的时候,会先把数值转换为二进制,然后在进行相加,得到的二进制结果,在转化为十进制,这个时候结果就会变成后面多了很多位数的数字;
解决:
方法一:
function formatFloat(f,digit){
let m = Math.pow(10, digit);
num = Math.round(f * m) / m;
return num;
}
f是计算表达式,digit是需要乘以10的多少次方
例如:
formatFloat(0.1+0.2,2); // 0.3
tip:
digit数必须大于等于 结果小数位数(不知道位数设置远大于即可)
0.1+0.2 // digit >= 1
0.12-0.04 // digit >= 2
0.1*0.7 // digit >= 1
方法二:
function add(num1, num2) {
const num1Digits = (num1.toString().split('.')[1] || '').length;
const num2Digits = (num2.toString().split('.')[1] || '').length;
const baseNum = Math.pow(10, Math.max(num1Digits, num2Digits));
return (num1 * baseNum + num2 * baseNum) / baseNum; // 数据处理逻辑
}
tip:
以上方法能适用于大部分场景。遇到科学计数法如 2.3e+1(当数字精度大于21时,数字会强制转为科学计数法形式显示)时还需要特别处理一下。
方法三:
function floatSub(num1, num2) {
var r1, r2, m, n;
try {
r1 = num1.toString().split('.')[1].length;
} catch (e) {
r1 = 0;
}
try {
r2 = num2.toString().split('.')[1].length;
} catch (e) {
r2 = 0;
}
m = Math.pow(10, Math.max(r1, r2));
n = r1 >= r2 ? r1 : r2;
n > 10 ? (n = 10) : (n = n);
let str_ = (Math.round(num1 * m - num2 * m) / m).toFixed(n);
return str_;
}
插件:
https://github.com/dt-fe/number-precision
参考网址:
https://blog.csdn.net/u013935095/article/details/81119953
https://github.com/camsong/blog/issues/9
]]>20200826T062940Z20200826T080213Z39.96441650390625116.318754897597758.3325958251953118333131121@163.com