Day16 精密

像计算机这样仪器,做这样的四则运算
0.1+0.2 = 0.30000000000000004
-9007199254740991-8 = -9007199254741000
19.99*100 = 1998.9999999999998
99.98/10 = 9.998000000000001
……

由于部分语言采用IEEE 754标准表示数字精度(大部分为64位)
有0舍1入的情况导致数值不准确。

当数字处于Number​.MAX_SAFE_INTEGER与Number.MIN_SAFE_INTEGER之间计算则能正确显示
以下函数通过将小数转换为整数,再进行四则运算来规避精度丢失的问题。


    /** 
     * 加法运算,避免数据相加小数点后产生多位数和计算精度损失。 
     * 
     * @param num1 加数1 
     * @param num2 加数2 
     */
    function numAdd (num1, num2) {
      var baseNum, baseNum1, baseNum2;
      try {
        baseNum1 = num1.toString().split(".")[1].length;
      } catch (e) {
        baseNum1 = 0;
      }
      try {
        baseNum2 = num2.toString().split(".")[1].length;
      } catch (e) {
        baseNum2 = 0;
      }
      baseNum = Math.pow(10, Math.max(baseNum1, baseNum2));
      // 这样直接乘会有乘法精度的问题,例如
      // console.log(4274.77*100);//输出427477.00000000006
      //return (num1 * baseNum + num2 * baseNum) / baseNum;
      return (numMulti(num1, baseNum) + numMulti(num2, baseNum)) / baseNum;
    };
    /** 
      * 减法运算,避免数据相减小数点后产生多位数和计算精度损失。 
      * 
      * @param num1 被减数 
      * @param num2 减数 
      */
    function numSub (num1, num2) {
      var baseNum, baseNum1, baseNum2;
      var precision;// 精度 
      try {
        baseNum1 = num1.toString().split(".")[1].length;
      } catch (e) {
        baseNum1 = 0;
      }
      try {
        baseNum2 = num2.toString().split(".")[1].length;
      } catch (e) {
        baseNum2 = 0;
      }
      baseNum = Math.pow(10, Math.max(baseNum1, baseNum2));
      precision = (baseNum1 >= baseNum2) ? baseNum1 : baseNum2;
      //return ((num1 * baseNum - num2 * baseNum) / baseNum).toFixed(precision);
      return (numMulti(num1, baseNum) - numMulti(num2, baseNum) / baseNum).toFixed(precision);
    };
    /** 
      * 乘法运算,避免数据相乘小数点后产生多位数和计算精度损失。 
      * 
      * @param num1 被乘数 
      * @param num2 乘数 
      */
    function numMulti (num1, num2) {
      var baseNum = 0;
      try {
        baseNum += num1.toString().split(".")[1].length;
      } catch (e) {
      }
      try {
        baseNum += num2.toString().split(".")[1].length;
      } catch (e) {
      }
      return Number(num1.toString().replace(".", "")) * Number(num2.toString().replace(".", "")) / Math.pow(10, baseNum);
    };
    /** 
      * 除法运算,避免数据相除小数点后产生多位数和计算精度损失。 
      * 
      * @param num1 被除数 
      * @param num2 除数 
      */
    function numDiv (num1, num2) {
      var baseNum1 = 0, baseNum2 = 0;
      var baseNum3, baseNum4;
      try {
        baseNum1 = num1.toString().split(".")[1].length;
      } catch (e) {
        baseNum1 = 0;
      }
      try {
        baseNum2 = num2.toString().split(".")[1].length;
      } catch (e) {
        baseNum2 = 0;
      }
      with (Math) {
        baseNum3 = Number(num1.toString().replace(".", ""));
        baseNum4 = Number(num2.toString().replace(".", ""));
        return (baseNum3 / baseNum4) * pow(10, baseNum2 - baseNum1);
      }
    };

参考:

  • JS魔法堂:彻底理解0.1 + 0.2 === 0.30000000000000004的背后
  • CDN:Number.MIN_SAFE_INTEGER
  • CDN:Number​.MAX_SAFE_INTEGER

你可能感兴趣的:(Day16 精密)