【JS】浮点数计算精度受损问题(浮点数化为整数计算后再还原的弊端)

浮点数的精度受损,相信大家都有了解过,但是我相信多数还是和我一样没有深入研究过,一知半解。

在此博客之前,我对浮点数的加减计算都是先将浮点数乘上10的n次方化为整数,计算后,再除去10的n次方。

我觉得整数计算肯定不会出现什么精度受损的问题。

事实上,整数计算确实不会出现什么问题。但是,问题出在了化整的时候。

举个例子:

// 乘法 =====================
0.07 * 100 = 7.000000000000001
19.9 * 100 = 1989.9999999999998
0.8 * 3 = 2.4000000000000004
35.41 * 100 = 3540.9999999999995

也就是说,我用0.07乘上10的倍数取整的时候结果却是一个浮点数,那将浮点数进行计算操作,结果肯定也是浮点数。

看到这里,我不知道你们心情怎么样,反正我是一身冷汗了,因为化整的操作,我用的相当纯熟和频繁。

所以,强烈建议大家以后不要用化整这种办法来操作浮点数了

解决办法:

1、浮点数相加(需要配合浮点数相乘的函数使用):

function add(a, b) {
    var c, d, e;
    try {
        c = a.toString().split(".")[1].length;
    } catch (f) {
        c = 0;
    }
    try {
        d = b.toString().split(".")[1].length;
    } catch (f) {
        d = 0;
    }
    return e = Math.pow(10, Math.max(c, d)), (mul(a, e) + mul(b, e)) / e;
}

2、浮点数相减(需要配合浮点数相乘的函数使用):

function sub(a, b) {
    var c, d, e;
    try {
        c = a.toString().split(".")[1].length;
    } catch (f) {
        c = 0;
    }
    try {
        d = b.toString().split(".")[1].length;
    } catch (f) {
        d = 0;
    }
    return e = Math.pow(10, Math.max(c, d)), (mul(a, e) - mul(b, e)) / e;
}

3、浮点数相乘

function mul(a, b) {
    var c = 0,
        d = a.toString(),
        e = b.toString();
    try {
        c += d.split(".")[1].length;
    } catch (f) {}
    try {
        c += e.split(".")[1].length;
    } catch (f) {}
    return Number(d.replace(".", "")) * Number(e.replace(".", "")) / Math.pow(10, c);
}

4、浮点数相除

function div(a, b) {
    var c, d, e = 0,
        f = 0;
    try {
        e = a.toString().split(".")[1].length;
    } catch (g) {}
    try {
        f = b.toString().split(".")[1].length;
    } catch (g) {}
    return c = Number(a.toString().replace(".", "")), d = Number(b.toString().replace(".", "")), mul(c / d, Math.pow(10, f - e));
}

 

当然,如果只是很简单的计算,觉得上边的代码比较繁杂,这里也提供一个简单的函数,来计算加减(本人测试未出现精度受损问题)

function add(a, b) {   //浮点数相加
    var r1, r2, m, n;
    try { r1 = a.toString().split(".")[1].length } catch (e) { r1 = 0 }
    try { r2 = b.toString().split(".")[1].length } catch (e) { r2 = 0 }
    m = Math.pow(10, Math.max(r1, r2));
    n = 2;//n为保留几位小数
    return ((a * m + b * m) / m).toFixed(n);
}

function sub(a, b) {  //浮点数相减
    var r1, r2, m, n;
    try { r1 = a.toString().split(".")[1].length } catch (e) { r1 = 0 }
    try { r2 = b.toString().split(".")[1].length } catch (e) { r2 = 0 }
    m = Math.pow(10, Math.max(r1, r2));
    n = 2;//n为保留几位小数
    return ((a * m - b * m) / m).toFixed(n);
}

如果帮到你的话,希望能随手给个小小的赞,如果能在评论区赞美我一番的话,那我可真的是三生有幸,四通八达,五谷丰登,六脉神剑了啊~~   哈哈哈哈哈哈

参考文档:

http://xieyufei.com/2018/03/07/JS-Decimal-Accuracy.html

https://www.cnblogs.com/Stephenchao/p/5743805.html

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值