14

预期结果:

(1.175).toFixed(2) = 1.18 and
(5.175).toFixed(2) = 5.18

但在 JS 中显示:

(1.175).toFixed(2) = 1.18 but 
*(5.175).toFixed(2) = 5.17*

如何纠正问题?

4

6 回答 6

11

这不是一个错误。它与事实数字不是以十进制存储而是在IEEE754中(因此5.175完全存储)有关。

如果你想在一个特定的方向(向上)四舍五入并且你一直有这个精度的数字,你可以使用这个技巧:

(5.175 + 0.00001).toFixed(2)
于 2014-01-13T12:54:14.890 回答
7

你总是可以尝试使用round,而不是toFixed。

Math.round(5.175*100)/100

如果你愿意,你甚至可以尝试把它放在一些原型方法中。

创建了一个在 Number 上实现简单原型的jsBin 。

Number.prototype.toFixed = function(decimals) {
 return Math.round(this * Math.pow(10, decimals)) / (Math.pow(10, decimals)); 
};
于 2014-01-13T12:56:19.870 回答
2

这是因为数字存储为IEEE754

我建议您使用 Math 类(round、floor 或 ceil 方法,具体取决于您的需要)。

我刚刚创建了一个可以轻松解决您的问题的类 MathHelper:

var MathHelper = (function () {
    this.round = function (number, numberOfDecimals) {
        var aux = Math.pow(10, numberOfDecimals);
        return Math.round(number * aux) / aux;
    };
    this.floor = function (number, numberOfDecimals) {
        var aux = Math.pow(10, numberOfDecimals);
        return Math.floor(number * aux) / aux;
    };
    this.ceil = function (number, numberOfDecimals) {
        var aux = Math.pow(10, numberOfDecimals);
        return Math.ceil(number * aux) / aux;
    };

    return {
        round: round,
        floor: floor,
        ceil: ceil
    }
})();

用法:

MathHelper.round(5.175, 2)

演示:http: //jsfiddle.net/v2Dj7/

于 2014-05-29T14:36:04.220 回答
0

实际上,我认为这Number.prototype.toFixed. ECMA-262 20.1.3.3 10-a中给出的算法说要四舍五入作为决胜局。正如其他人所提到的,由于实现中的浮点不精确,可能没有什么可以打破的。但这并不正确:)

至少这种行为在 FF、Chrome、Opera、Safari 中是一致的。(其他的没试过。)

FWIW,您实际上可以根据 JS 规范实现自己的版本,toFixed并且其行为与您期望的一样。请参阅http://jsfiddle.net/joenudell/7qahrb6d/

于 2015-07-13T21:24:50.873 回答
0

Kippie 您的解决方案有问题之一

39133.005.toFixed(2) => 39133 

var Calc = function () {
    var self = this;

this.float2Array = function(num) {
    var floatString = num.toString(),
        exp = floatString.indexOf(".") - (floatString.length - 1),
        mant = floatString.replace(".", "").split("").map(function (i) { return parseInt(i); });
    return { exp: exp, mant: mant };
};

this.round2 = function (num, dec, sep) {
    var decimal = !!dec ? dec : 2,
    separator = !!sep ? sep : '',
    r = parseFloat(num),
    exp10 = Math.pow(10, decimal);
    r = Math.round(r * exp10) / exp10;

    var rr = Number(r).toFixed(decimal).toString().split('.');

    var b = rr[0].replace(/(\d{1,3}(?=(\d{3})+(?:\.\d|\b)))/g, "\$1" + separator);
    r = (rr[1] ? b + '.' + rr[1] : b);

    return r;
};

this.toFixed10 = function (f, num) {
    var prepareInt = self.float2Array(f),
        naturalInt = prepareInt.mant,
        places = Math.abs(prepareInt.exp),
        result = prepareInt.mant.slice(),
        resultFixedLenth;

    // if number non fractional or has zero fractional part
    if (f.isInt()) {
        return f.toFixed(num);
    }
    // if the number of decimal places equals to required rounding
    if (places === num) {
        return Number(f).toString();
    }
    //if number has trailing zero (when casting to string type float 1.0050 => "1.005" => 005 <0050)
    if (places < num) {
        return Number(f).round2(num);
    }

    for (var e = naturalInt.length - (places > num ? (places - num) : 0), s = 0; e >= s; e--) {
        if (naturalInt.hasOwnProperty(e)) {
            if (naturalInt[e] > 4 && naturalInt[e - 1] < 9) {
                result[e] = 0;
                result[e - 1] = naturalInt[e - 1] + 1;
                break;
            } else if (naturalInt[e] > 4 && naturalInt[e - 1] === 9) {
                result[e] = 0;
                result[e - 1] = 0;
                result[e - 2] = naturalInt[e - 2] < 9 ? naturalInt[e - 2] + 1 : 0;
            } else if (e === 0 && naturalInt[e] === 9 && naturalInt[e + 1] === 9) {
                result[e] = 0;
                result.unshift(1);
            } else {
                break;
            }
        }
    }

    if (places - num > 0) {
        resultFixedLenth = result.slice(0, -(places - num));
    } else {
        for (var i = 0, l = num - places; i < l; i++) {
            result.push(0);
        }
        resultFixedLenth = result;
    }

    return (parseInt(resultFixedLenth.join("")) / Math.pow(10, num)).round2(num);
};
this.polyfill = function() {
    if (!Array.prototype.map) {
        Array.prototype.map = function (callback, thisArg) {
            var T, A, k;
            if (this == null) { throw new TypeError(' this is null or not defined'); }
            var O = Object(this), len = O.length >>> 0;
            if (typeof callback !== 'function') { throw new TypeError(callback + ' is not a function'); }
            if (arguments.length > 1) { T = thisArg; }

            A = new Array(len);
            k = 0;
            while (k < len) {
                var kValue, mappedValue;
                if (k in O) {
                    kValue = O[k];
                    mappedValue = callback.call(T, kValue, k, O);
                    A[k] = mappedValue;
                }
                k++;
            }
            return A;
        };
    }
};

this.init = function () {
    self.polyfill();
    Number.prototype.toFixed10 = function (decimal) {
        return calc.toFixed10(this, decimal);
    }
    Number.prototype.round2 = function (decimal) {
        return calc.round2(this, decimal);
    }
    Number.prototype.isInt = function () {
        return (Math.round(this) == this);
    }
}
}, calc = new Calc(); calc.init();

这很好用)

于 2016-01-03T01:47:15.910 回答
0
obj = {
    round(val) {
      const delta = 0.00001
      let num = val
      if (num - Math.floor(num) === 0.5) {
        num += delta
      }
      return Math.round(num + delta)
    },
  fixed(val, count = 0) {
      const power = Math.pow(10, count)
      let res = this.round(val * power) / power
      let arr = `${res}`.split('.')
      let addZero = ''
      for (let i = 0; i < count; i++) {
        addZero += '0'
      }
      if (count > 0) {
        arr[1] = ((arr[1] || '') + addZero).substr(0, count)
      }
      return arr.join('.')
  }
}
obj.fixed(5.175, 2)

//“5.18”

于 2017-07-07T03:01:57.000 回答