美文网首页
js 浮点数计算

js 浮点数计算

作者: 王果果 | 来源:发表于2022-07-28 11:29 被阅读0次

    在做项目的时候,涉及到金额加减时,经常会出现计算精度的问题,常见例子如下:

         加法        
    
              0.1 + 0.2 = 0.30000000000000004
    
              0.7 + 0.1 = 0.7999999999999999
    
              0.2 + 0.4 = 0.6000000000000001
    
         减法
    
              1.5 - 1.2 = 0.30000000000000004
    
               0.3 - 0.2 = 0.09999999999999998
    
         乘法
    
               0.8 * 3 = 2.4000000000000004
    
               35.41 * 100 = 3540.9999999999995
    
          除法
    
               0.3 / 0.1 = 2.9999999999999996
    
               0.69 / 10 = 0.06899999999999999
    

    在遇到浮点数运算后出现的精度问题时,起初想等加完之后使用toFixed(2)来解决的,toFixed()方法可把Number四舍五入为指定小数位数的数字

    测试发现还是存在一定误差

    为什么会产生

    JavaScript中所有数字包括整数和小数都只有一种类型 — Number。它的实现遵循 IEEE 754 标准,使用64位固定长度来表示,也就是标准的 double 双精度浮点数,

    这样的存储结构优点是可以归一化处理整数和小数,节省存储空间。

    64位比特又可分为三个部分:

    符号位S:第 1 位是正负数符号位(sign),0代表正数,1代表负数

    指数位E:中间的 11 位存储指数(exponent),用来表示次方数

    尾数位M:最后的 52 位是尾数(mantissa),超出的部分自动进一舍零

    然后当javaScript运算时,会先把十进制的0.1和0.2会被转换成二进制的,但是由于浮点数用二进制表示时是无穷的:

       0.1 -> 0.0001 1001 1001 1001...(1100循环)
    
       0.2 -> 0.0011 0011 0011 0011...(0011循环)
    

    IEEE 754 标准的 64 位双精度浮点数的小数部分最多支持53位二进制位,所以两者相加之后得到二进制为:

       0.0100110011001100110011001100110011001100110011001100
    

    因浮点数小数位的限制而截断的二进制数字,再转换为十进制,就成了0.30000000000000004。所以在进行算术计算时会产生误差。

    如何解决

    大概思路就是把浮点数转化成整数(乘以10的n次幂)去加减,然后在降级处理(除以10的n次幂)

    例如: 0.1 + 0.2 == 0.3 //false

           (0.1*10 + 0.2*10)/10 == 0.3 //true
    

    本以为这样就能完美解决了,尴尬的事情出行了

     18.4 * 100 = 1839.9999999998 
    

    所以最终决定把数值先toString之后通过split方法切割小数点,把小数点位数补成两位后,通过字符串拼接的方式拼接起来然后转成数值进行加减,最后在除以100即可。

    代码如下:

    //补全位数
    function operation(num) {
    //如果是整数的话默认补两位小数
    if (num) {
    num = num.slice(0,2);
    return num.length === 1 ? num = num + '0' : num;
    } else {
    return '00'
    }
    }
    //处理浮点数想加
    var addNUm = function (num1,num2) {

      var array1 = num1.toString().split("."),//转化成字符串并已小数点切割 
      array2 = num2.toString().split(".");
      //如果是整数的话默认补两位小数
      array1[1] = operation(array1[1]);
      array2[1] = operation(array2[1]);
      //把整数部分和小数部分拼接起来然后在转成数字类型
      var num1 = Number(array1[0] + array1[1]),
      num2 = Number(array2[0] + array2[1]);
      //整数想加之后除以100
     return (num1 + num2) / 100;
    

    }

    addNUm(0.1,0.2);

    相关文章

      网友评论

          本文标题:js 浮点数计算

          本文链接:https://www.haomeiwen.com/subject/hdxxwrtx.html