zoukankan      html  css  js  c++  java
  • JavaScript计算进度问题小计

    十进制小数转为二进制小数方法

    拿 9527.8125 举例如何将之转化为二进制小数

    1.针对整数部分9527,采取除2取余,逆序排列

    9527 / 2 = 4763 ... 1
    4763 / 2 = 2381 ... 1
    2381  / 2 = 1190 ... 1   ↑
    1190 / 2 = 595 ... 0   | 逆序排列
    595 / 2 = 297 ... 1    |
    297  / 2 = 148 ... 1     |
    148  / 2 = 74 ... 0
    74 / 2 = 37 ... 1
    37/ 2 = 18... 1
    18 / 2 = 9 ... 1
    9/ 2 = 4 ... 1
    4 / 2 = 2 ... 0
    2 / 2 = 1 ... 0
    1 / 2 = 2 ... 1
    

     得整数部分的二进制为10011110110111.

    2.针对小数部分0.8125,采取乘2取整,顺序排序

    0.8125 * 2 = 1.625  |
    0.625 * 2 = 1.25    | 顺序排列
    0.25 * 2 = 0.5      |
    0.5 * 2 = 1         ↓
    

     得小数部分的二进制为1001.

    3.将前面两部分的结果相加,结果为10011110110111.1001;

    小心,二进制小数会丢失了精度

    根据上面的知识,将十进制0.1转为二进制;

    0.1 * 2 = 0.2
    0.2 * 2 = 0.4 // 注意这里
    0.4 * 2 = 0.8
    0.8 * 2 = 1.6
    0.6 * 2 = 1.2
    0.2 * 2 = 0.4 // 注意这里,循环开始
    0.4 * 2 = 0.8
    0.8 * 2 = 1.6
    0.6 * 2 = 1.2
    ...
    

     可以发现有限十进制小数0.1转成无限二进制小数0.00011001100...,可以看到精度在转化过程中丢失了!

    由此得出结论能转为有限二进制小数的最后一位必然以5结尾(因为只有0.5*2才能变成整数),其他结尾的都会丢失精度。

     推导 0.1 + 0.2 为何等于 0.30000000000000004

    可以参考双精度浮点数

    推荐阅读JavaScript浮点数陷阱及解法

    阅读后得到以下公式

    // 0.1 和 0.2 都转化成二进制后再进行运算
    0.00011001100110011001100110011001100110011001100110011010 +
    0.0011001100110011001100110011001100110011001100110011010 =
    0.0100110011001100110011001100110011001100110011001100111
    
    // 转成十进制正好是 0.30000000000000004

     解决方法小计1

    //
    Number.prototype['add'] = function (...arg) {
        var r1, r2, m, result = this;
        arg.forEach(value => {
            try { r1 = result.toString().split(".")[1].length } catch (e) { r1 = 0 }
            try { r2 = value.toString().split(".")[1].length } catch (e) { r2 = 0 }
            m = Math.pow(10, Math.max(r1, r2));
            result = Math.round(result * m + value * m) / m;
        });
        return result;
    };
    //
    Number.prototype['sub'] = function (...arg) {
        var r1, r2, m, result = this;
        arg.forEach(value => {
            try { r1 = result.toString().split(".")[1].length } catch (e) { r1 = 0 }
            try { r2 = value.toString().split(".")[1].length } catch (e) { r2 = 0 }
            m = Math.pow(10, Math.max(r1, r2));
            var n = (r1 >= r2) ? r1 : r2;
            result = (Math.round(result * m - value * m) / m).toFixed(n);
        });
        return result;
    };
    //
    Number.prototype['mul'] = function (...arg) {
        var result = this;
        arg.forEach(value => {
            var m = 0, s1 = result.toString(), s2 = value.toString();
            try { m += s1.split(".")[1].length } catch (e) { }
            try { m += s2.split(".")[1].length } catch (e) { }
            result = Number(s1.replace(".", "")) * Number(s2.replace(".", "")) / Math.pow(10, m);
        });
        return result;
    };
    //
    Number.prototype['subtraction'] = function (...arg) {
        var result = this;
        arg.forEach(value => {
            var t1 = 0, t2 = 0, r1, r2;
            try { t1 = result.toString().split(".")[1].length } catch (e) { }
            try { t2 = value.toString().split(".")[1].length } catch (e) { }
            r1 = Number(result.toString().replace(".", ""));
            r2 = Number(value.toString().replace(".", ""));
            result = (r1 / r2) * Math.pow(10, t2 - t1);
        });
        return result;
    };

     解决方法小计2

    • 传统使用,引入math.js
        <!DOCTYPE HTML>
        <html>
        <head>
          <script src="https://unpkg.com/mathjs@7.0.1/dist/math.min.js" type="text/javascript"></script>
        </head>
        <body>
          <script type="text/javascript">
            const ans = math.add(0.1, 0.2)     //  0.30000000000000004
            console.log(math.format(ans, {precision: 14})) // '0.3'
            console.log(math.sqrt(4).toString()) // 2
          </script>
        </body>
        </html>
    • es module
      	npm install mathjs
      
      import { create, all } from 'mathjs'
      const config = { 
        number: 'BigNumber',
        precision: 20
      }
      const math = create(all, config);
      export default {
        methods: {
            //开方
          numberSqrt: function(arg1){
              return math math.sqrt(arg1)
          },
          //
          numberExcept: function (arg1, arg2) {
            return math.divide(arg1, arg2);
          },
          //
          numberRide: function (arg1, arg2) {      
            return math.multiply(arg1, arg2);
          },
          //
          numberAdd:function (arg1,arg2) {
          return math.add(arg1, arg2);
          }
          //
          numberSub:function (arg1,arg2) {
          return math.add(arg1, -arg2);
          }
        }
      }
  • 相关阅读:
    SQL解发器与SQL游标实例
    动态调用JS
    HDU_5729_rmq+二分
    struts2 在MyEclipse中 的配置
    Struts 1.2 中如何测试Action
    OGNL使用小结【转】
    JUnit中assertEquals和assertSame方法的不同
    struts2 ActionContext
    ser文件与Java对象序列化
    测试Action组件代码(StrutsTestCase)
  • 原文地址:https://www.cnblogs.com/wuxu-dl/p/15246472.html
Copyright © 2011-2022 走看看