视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
JS浮点数运算结果不精确的Bug解决
2020-11-27 21:52:52 责编:小采
文档

【2】IEEE754标准的位双精度浮点数的小数部分最多支持53位二进制,多余的二进制数字被截断,所以两者相加之后的二进制之和是

0.0100110011001100110011001100110011001100110011001101

【3】将截断之后的二进制数字再转换为十进制,就成了0.30000000000000004,所以在计算时产生了误差

六. 解决办法

【1】引用类库

  • Math.js 
  • decimal.js   
  • big.js
  • 【2】思路一:在知道小数位个数的前提下,可以考虑通过将浮点数放大倍数到整型(最后再除以相应倍数),再进行运算操作,这样就能得到正确的结果了  

    0.1 + 0.2 ——> (0.1 * 10 + 0.2 * 10) / 10 // 0.3
    0.8 * 3 ——> ( 0.8 * 100 * 3) / 100         //2.4

    【3】自定义一个转换和处理函数 

     // f代表需要计算的表达式,digit代表小数位数
     Math.formatFloat = function (f, digit) {
     // Math.pow(指数,幂指数)
     var m = Math.pow(10, digit);
     // Math.round() 四舍五入
     return Math.round(f * m, 10) / m;
     }
     console.log(Math.formatFloat(0.3 * 8, 1)); // 2.4
     console.log(Math.formatFloat(0.35 * 8, 2)); // 2.8

    【4】加法函数  

     /**
     ** 加法函数,用来得到精确的加法结果
     ** 说明:javascript的加法结果会有误差,在两个浮点数相加的时候会比较明显。这个函数返回较为精确的加法结果。
     ** 调用:accAdd(arg1,arg2)
     ** 返回值:arg1加上arg2的精确结果
     **/
     function accAdd(arg1, arg2) {
     var r1, r2, m, c;
     try {
     r1 = arg1.toString().split(".")[1].length;
     } catch (e) {
     r1 = 0;
     }
     try {
     r2 = arg2.toString().split(".")[1].length;
     } catch (e) {
     r2 = 0;
     }
     c = Math.abs(r1 - r2);
     m = Math.pow(10, Math.max(r1, r2));
     if (c > 0) {
     var cm = Math.pow(10, c);
     if (r1 > r2) {
     arg1 = Number(arg1.toString().replace(".", ""));
     arg2 = Number(arg2.toString().replace(".", "")) * cm;
     } else {
     arg1 = Number(arg1.toString().replace(".", "")) * cm;
     arg2 = Number(arg2.toString().replace(".", ""));
     }
     } else {
     arg1 = Number(arg1.toString().replace(".", ""));
     arg2 = Number(arg2.toString().replace(".", ""));
     }
     return (arg1 + arg2) / m;
     }
    
     //给Number类型增加一个add方法,调用起来更加方便。
     Number.prototype.add = function (arg) {
     return accAdd(arg, this);
     };

    【5】减法函数

     /**
     ** 减法函数,用来得到精确的减法结果
     ** 说明:javascript的减法结果会有误差,在两个浮点数相减的时候会比较明显。这个函数返回较为精确的减法结果。
     ** 调用:accSub(arg1,arg2)
     ** 返回值:arg1加上arg2的精确结果
     **/
     function accSub(arg1, arg2) {
     var r1, r2, m, n;
     try {
     r1 = arg1.toString().split(".")[1].length;
     } catch (e) {
     r1 = 0;
     }
     try {
     r2 = arg2.toString().split(".")[1].length;
     } catch (e) {
     r2 = 0;
     }
     m = Math.pow(10, Math.max(r1, r2)); //last modify by deeka //动态控制精度长度
     n = (r1 >= r2) ? r1 : r2;
     return ((arg1 * m - arg2 * m) / m).toFixed(n);
     }
    
     // 给Number类型增加一个mul方法,调用起来更加方便。
     Number.prototype.sub = function (arg) {
     return accMul(arg, this);
     };

    【6】乘法函数

     /**
     ** 乘法函数,用来得到精确的乘法结果
     ** 说明:javascript的乘法结果会有误差,在两个浮点数相乘的时候会比较明显。这个函数返回较为精确的乘法结果。
     ** 调用:accMul(arg1,arg2)
     ** 返回值:arg1乘以 arg2的精确结果
     **/
     function accMul(arg1, arg2) {
     var m = 0,
     s1 = arg1.toString(),
     s2 = arg2.toString();
     try {
     m += s1.split(".")[1].length;
     } catch (e) {}
     try {
     m += s2.split(".")[1].length;
     } catch (e) {}
     return Number(s1.replace(".", "")) * Number(s2.replace(".", "")) / Math.pow(10, m);
     }
    
     // 给Number类型增加一个mul方法,调用起来更加方便。
     Number.prototype.mul = function (arg) {
     return accMul(arg, this);
     };

    【7】除法函数

     /** 
     ** 除法函数,用来得到精确的除法结果
     ** 说明:javascript的除法结果会有误差,在两个浮点数相除的时候会比较明显。这个函数返回较为精确的除法结果。
     ** 调用:accDiv(arg1,arg2)
     ** 返回值:arg1除以arg2的精确结果
     **/
     function accDiv(arg1, arg2) {
     var t1 = 0,
     t2 = 0,
     r1, r2;
     try {
     t1 = arg1.toString().split(".")[1].length;
     } catch (e) {}
     try {
     t2 = arg2.toString().split(".")[1].length;
     } catch (e) {}
     with(Math) {
     r1 = Number(arg1.toString().replace(".", ""));
     r2 = Number(arg2.toString().replace(".", ""));
     return (r1 / r2) * pow(10, t2 - t1);
     }
     }
    
     //给Number类型增加一个div方法,调用起来更加方便。
     Number.prototype.div = function (arg) {
     return accDiv(this, arg);
     };

    总结

    下载本文
    显示全文
    专题