浮点问题

浮点精度
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.comdesktop.mac0

posted on 2020-08-26 16:18  执着的烙印  阅读(246)  评论(0编辑  收藏  举报

导航