js数值计算精度再次入坑

js数值类型计算一直有一个坑,就是关于计算精度的问题。在js中计算 0.1+0.2、0.3-0.1等运算时,会出现很惊人的一大串数值,相信很多人都遇到过

0.1+0.2  //0.30000000000000004
0.3-0.1  //0.19999999999999998复制代码

关于产生这个问题的原因,网上已经有很多说明了,大体就是js浮点类型精度的问题导致的,因此在计算的时候我们通常会采取一些方法,截取所需要的值。

回到正题,这次遇到的坑也是精度问题,但是不是加减法而是乘法,一个浮点数乘以10,结果也是惊人的长————————

0.68*10  //6.800000000000001复制代码

可能很多人遇到过乘法精度问题,但是我确实是第一次遇到这种问题。问题产生的背景是,后端返回一个浮点数m,前端在此基础上乘10,转换为“m折”字样展现在页面上。需求很简单,但是却有一个隐藏的坑。

其实要解决这个坑并不难,网上也有很多办法,此处列举几个:

1)toFixed方法

浮点数*10然后调用toFixed方法可以解决此问题,但是也有一个问题,就是会存在四舍五入的问题,如果要求准确的展示后台返回的数值,这个方法就会有缺陷。

(0.68*10).toFixed(2)  //此时没问题,结果为6.80
(0.0686*10).toFixed(2)  //小数位数多的时候就会有四舍五入问题,此时结果为0.69复制代码

(2)将浮点数乘以10的倍数,再除以相应的10的倍数

这个方法也很常用,就是将浮点数转化为整数,在除以相应的倍数转换为浮点数。这个方法基本可以覆盖很大部分问题,但是一种方法不试用,就是浮点数的位数不确定的时候,无法准确判断乘以10的准确倍数。

0.68*1000/100   //此时结果正常,结果为6.8

假如返回的浮点数不确定位数,但是依旧按乘1000/100方式计算
0.00000068*1000/100   //结果又很给力了, 结果为0.000006799999999999999复制代码

(3)利用Math相关方法转换

此方法主要是利用Math.round和Math.pow方法对数据进行处理,借用网上的一个方法

function myFixed(a, b) {
  return Math.round(a * Math.pow(10, b)) / Math.pow(10, b);
}
console.log(0.68*10);              //6.800000000000001
console.log(myFixed(0.68*10, 2));  //6.8复制代码

4)字符串转换方法

最后说一下我们填坑的方法,因为此处对数值的应用只是将其转化为折扣数值,可以说是不需要进行运算处理的,因此采用了一个直截了当的字符串截取的方法,直接上代码:

//此方法考虑数值都是大于等于0的数值,并且对0和大于1的数值进行了展示(理论上折扣券不会出现0和大于1的情况)
function discounts(discountNumber){  
    if (!discountNumber && discountNumber !== 0) {
        return  
    }  
    const expPoint = /\./
    let countString = String(discountNumber)  
    let discountString = ''  
    if(countString < 1 && expPoint.test(countString)){    
        let discountArr = countString.split('.')[1].split('')    
        if(discountArr.length === 1){      
            discountString = discountArr[0]    
        }else{      
            let discountStringFirst = discountArr[0]      
            let discountStringSecond = discountArr.slice(1).join('')      
            discountString = discountStringFirst + '.' + discountStringSecond
        }
    }else{    
        discountString = countString * 10  
    }  
    return discountString
}

discounts(0)     //0
discounts(0.3)   //3
discounts(0.68)  //6.8
discounts(0.9)   //9
discounts(1)     //10
discounts(1.02)  //10.2复制代码

到此问题得到了解决,并且基本能覆盖到所有正常情况。

最后要说的是,关于数值计算精度问题在开发中一定要小心,稍有不慎就会掉入超长浮点数的坑里,在此也是记录并且告诉下自己,避免后面再次入坑。


转载于:https://juejin.im/post/5d00f01e518825382565c473

猜你喜欢

转载自blog.csdn.net/weixin_34026276/article/details/93169125