js封装加减乘除四则运算解决精度丢失的问题

在这里插入图片描述
JS 数字丢失精度的原因: 计算机的二进制实现和位数限制有些数无法有限表示。
意义:
1位用来表示符号位
11位用来表示指数
52位表示尾数

大整数的精度丢失和浮点数本质上是一样的,尾数位最大是 52 位,因此 JS 中能精准表示的最大整数是 Math.pow(2, 53),十进制即 :9007199254740992。

大于 9007199254740992 的可能会丢失精度
在这里插入图片描述

注意的是toFixed()坑
在这里插入图片描述
文章的最下边 有个封装方法,适用所有场合,并完全符合数学中的四舍五入规则。

解决

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <script>
    
      // 自己实现 num为xxx , n为2(会在2后面补上00.即2.00)
	  // Math.pow(x, y); 返回的是x的y次方
      // 2的5次方 2 * 2 * 2 * 2 * 2
      // 5的2次方 也叫平方 5 * 5
      // 5的3次方 也叫立方 5 * 5 * 5
      const toFixed = (num, n) => {
        if (num < 0) {
          num = -num;
        } else {
          return -(parseInt(num * Math.pow(10, n) + 0.5, 10) / Math.pow(10, n));
        }
        return parseInt(num * Math.pow(10, n) + 0.5, 10) / Math.pow(10, n);
      };
      
      // 两个浮点数求和
      const Add = (num1, num2) => {
        let r1, r2, m;
        try {
          r1 = `${num1}`.split('.')[1].length;
        } catch (e) {
          r1 = 0;
        }
        try {
          r2 = `${num2}`.split('.')[1].length;
        } catch (e) {
          r2 = 0;
        }
        m = Math.pow(10, Math.max(r1, r2));
        return Math.round(num1 * m + num2 * m) / m;
      };

      // 两个浮点数相减
      const Sub = (num1, num2) => {
        let r1, r2, m, n;
        try {
          r1 = `${num1}`.split('.')[1].length;
        } catch (e) {
          r1 = 0;
        }
        try {
          r2 = `${num2}`.split('.')[1].length;
        } catch (e) {
          r2 = 0;
        }
        m = Math.pow(10, Math.max(r1, r2));
        n = r1 >= r2 ? r1 : r2;
        return toFixed(Math.round(num1 * m - num2 * m) / m, n);
      };


      // 两个浮点数相乘
      const Mul = (num1, num2) => {
        let m = 0,
          s1 = `${num1}`,
          s2 = `${num2}`;
        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)
        );
      };


      // 两个浮点数相除
      const Div = (num1, num2) => {
        let t1, t2, r1, r2;
        try {
          t1 = `${num1}`.split('.')[1].length;
        } catch (e) {
          t1 = 0;
        }
        try {
          t2 = `${num2}`.toString().split('.')[1].length;
        } catch (e) {
          t2 = 0;
        }
        r1 = Number(`${num1}`.replace('.', ''));
        r2 = Number(`${num2}`.toString().replace('.', ''));
        return (r1 / r2) * Math.pow(10, t2 - t1);
      };
      module.exports = {
        toFixed,
        Add,
        Sub,
        Mul,
        Div
      };

    </script>
  </body>
</html>

这个和这个一样,只不过一个是html,一个是js

下面这个封装方法,适用所有场合,并完全符合数学中的四舍五入规则

// val要保留的数据,places保留位数,type返回类型(1数字,2字符串)
function keepDecimals(val, places, type) {
       let num = val + ''; // console.log(num, 'a') 字符串 0.015
       let numStart = num.split('.')[0] ; // console.log(numStart, 'b' ) // 字符串 0
       let numEnd = num.split('.')[1]; // console.log(numEnd, 'c') // 字符串 015
       let powVal = Math.pow(10, places); // console.log(powVal,'d') // 数字类型 100
       if (numEnd) {
           console.log(numEnd,'e') // 字符串 015
           num = Math.round(num * powVal) / powVal + '';
           // console.log(num, 'f') // 字符串 0.02
           if (num.split('.')[1]&&num.split('.')[1].length < places) { 
           //	console.log(num,'g')
               for (let n = 0; n < places - num.split('.')[1].length; n++) {
                   num += '0' ; 
                   // console.log(num,'h')
               }
           }
       } else { 
         // console.log(num, 'i')
           num = numStart + '.';
           // console.log(num, 'j')
           for (let n = 0; n < places; n++) {
               num += '0';
               // console.log(num, 'k')
           }
       } 
       // console.log(num, 'L', num*1, num+'') 
       return type==1?num=num*1:num=num+''
      //  或者直接 return num ; 
      // 毕竟这个类型其实无所谓,尝试了一下,拿到的都是 字符换。
      // 计算的时候都要转成数字类型。直接乘 1 
      // 即: return num *1
   }
   let num = keepDecimals(0.015, 2, 2); 
   // console.log(num) 
   亲测有效,最后这个得到的结果都是字符串 类型的,当然这个type 值也可以不传,并且你要是想得到一个数字类型的值,在最后的结果后边直接 乘 1 就行(隐式转换)
  // let num = keepDecimals(7.665666, 2)*1; console.log(num)  // 数字类型 7.67

总的来说看你要啥类型的

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/lzfengquan/article/details/124296508