在javascript中添加浮点值

时间:2014-02-11 04:17:55

标签: javascript floating-point

我遇到了条件0.1 + 0.2 !== 0.3的问题。我尝试了0.0001 + 0.0002,这不等于0.03。据我所知,我们可以使用toFixed来解决这个问题。但有没有解决方案来动态解决这个问题?因为我们使用0.1 + 0.2 toFixed(2)0.0001 + 0.0002使用toFixed(4)

4 个答案:

答案 0 :(得分:2)

您可以扩展Math以包含用于进行数学运算的函数。下面需要两个浮点数,确定最大小数位数然后根据数学然后使用最大小数位数进行固定。

Math.addFloats = function (f1,f2){
   //Helper function to find the number of decimal places
   function findDec(dec){
     var count = 0;
     while(dec%1){
       dec*=10;
       count++;
     }
     return count;
   }
   //Determine the greatest number of decimal places
   var dec1 = findDec(f1);
   var dec2 = findDec(f2);
   var fixed = dec1>dec2 ? dec1 : dec2;

   //do the math then do a toFixed, could do a toPrecision also
   var n = (f1+f2).toFixed(fixed);
   return +n;
}
console.log( Math.addFloats(0.1,0.2) == 0.3 ); //evaluates to true
console.log( Math.addFloats(1/3,1/7) ); //prints 0.47619047619047616
console.log( 1/3 + 1/7 ); //prints 0.47619047619047616

没有对它进行全面测试,但做了一些初步测试表明它可以动态工作,可能会修改它来做其他数学运算,但可能需要在进行除数/倍数等时更改小数计数检查

注意:对于电子表示法,这似乎不能很好地计算小数位数,即2e-14得到的结果如30,应该是14

编辑:将findDec函数更改为查找小数位的this answers version似乎更好地确定不同类型数字的正确小数位数

   function findDec(f1){
      function isInt(n){
         return typeof n === 'number' && 
            parseFloat(n) == parseInt(n, 10) && !isNaN(n);
      }
      var a = Math.abs(f1);
      f1 = a, count = 1;
      while(!isInt(f1) && isFinite(f1)){
         f1 = a * Math.pow(10,count++);
      }
      return count-1;
    }

答案 1 :(得分:0)

(a)如果你正在处理(比如说)美元,那么最好的解决方案是使用整数来做所有事情。 (这只适用于你从不处理一分钱的部分。)

(b)在任何语言中,将双打/浮点数视为“实际值的良好近似值”,绝不与==进行比较。而是写一个帮手

double nearlyEqual(x,y,tolerance=0.00001) { return abs(x-y) < tolerance*max(abs(x),abs(y)); }

(警告:未经测试的代码)。

答案 2 :(得分:0)

非常感谢@Patrick。我创建了一个新代码,根据您的代码添加多个浮点数。它是:

/**
 * Find the number of decimal places
 * @method findDec
 * @param {Float|Number} dec
 * @return {Number}
 */
var findDec = function (dec) {
    var count = 0;
    while (dec % 1) {
        dec *= 10;
        count++;
    }

    return count;
};

/**
 * Find the greatest number of decimal places
 * @method findFixed
 * @param {Float|Number} dec
 * @return {Number}
 */
var findFixed = function () {
    var fixed = [];
    for (var i = 0, arg; arg = arguments[i]; i++) {
        fixed.push(findDec(arg));
    }

    return Math.max.apply(this, fixed)
};

/**
 * Calculate total
 * @method findFixed
 * @param {Float|Number}
 * @return {Float|Number}
 */
var calculate = function () {
    var total = 0;

    for (var i = 0, arg; arg = arguments[i]; i++) {
        total += arg;
    }

    return total;
}

/**
 * Add float number
 * @method addNumber
 * @param {Float|Number}
 * @return {Float|Number}
 */
Math.addNumber = function() {
    //Determine the greatest number of decimal places
    var fixed = findFixed.apply(this, arguments);
    var total = calculate.apply(this, arguments);

    //do the math then do a toFixed, could do a toPrecision also
    return +total.toFixed(fixed);
}

答案 3 :(得分:0)

使用带有这样的自定义的Number.prototype:

Number.prototype.lenDecimalPoint = function(val){
            var decStr = val.toString().match(/\.\d*/);
            if(decStr && decStr.length > 0) {
                return decStr[0].replace().replace('.','').length;
            } else {
                return 0;
            }
        }

    Number.prototype.getVal = function(val, stdDec10Val){
            var dec10ValLog = Math.log10(stdDec10Val);
            var thisValDecPoint = this.lenDecimalPoint(val);
            var thisValStr = val.toString();
            thisValStr = thisValStr.replace('/^0\./','');
            thisValStr = thisValStr.replace('.','');
            thisValStr += Math.pow(10 ,dec10ValLog - thisValDecPoint).toString().replace('1','');
            return Number(thisValStr);
        }

    Number.prototype.getDec10Val = function(val1, val2){
            var thisDecPoint = this.lenDecimalPoint(val1);
            var newNumValDecPoint = this.lenDecimalPoint(val2);
            var decPoint = thisDecPoint > newNumValDecPoint ? thisDecPoint : newNumValDecPoint;
            return Math.pow(10,decPoint);
        }

    Number.prototype.add = function(newVal) {

            newVal = Number(newVal)

            var dec10Val = this.getDec10Val(this, newVal);
            var thisIntVal = this.getVal(this, dec10Val);
            var newIntVal = this.getVal(newVal,dec10Val);

            return Number(((thisIntVal) + (newIntVal))/dec10Val);
        }
    Number.prototype.sub = function(newVal) {

            newVal = Number(newVal)

            var dec10Val = this.getDec10Val(this, newVal);
            var thisIntVal = this.getVal(this, dec10Val);
            var newIntVal = this.getVal(newVal,dec10Val);

            return Number(((thisIntVal) - (newIntVal))/dec10Val);
        }
    Number.prototype.div = function(newVal) {

            newVal = Number(newVal)

            var dec10Val = this.getDec10Val(this, newVal);
            var thisIntVal = this.getVal(this, dec10Val);
            var newIntVal = this.getVal(newVal,dec10Val);

            return Number(((thisIntVal) / (newIntVal)));
        }
    Number.prototype.mul = function(newVal) {

            newVal = Number(newVal)

            var dec10Val = this.getDec10Val(this, newVal);
            var thisIntVal = this.getVal(this, dec10Val);
            var newIntVal = this.getVal(newVal,dec10Val);


            return Number((thisIntVal * newIntVal)/Math.pow(dec10Val,2));
        }

用法:

(0.1).add(0.3)