Javascript toFixed function

前端 未结 6 1702
春和景丽
春和景丽 2020-12-30 04:51

The expected result of:

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

But in JS showing:

相关标签:
6条回答
  • 2020-12-30 05:24
    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"

    0 讨论(0)
  • 2020-12-30 05:32

    It's not a bug. It's related to the fact numbers aren't stored in decimal but in IEEE754 (so 5.175 isn't exactly stored).

    If you want to round in a specific direction (up) and you consistently have numbers of this precision, you might use this trick :

    (5.175 + 0.00001).toFixed(2)
    
    0 讨论(0)
  • 2020-12-30 05:32

    It's because the numbers are stored as IEEE754.

    I would recommend you to use the Math class (round, floor or ceil methods, depending on your needing).

    I've just created a class MathHelper that can easily solve your problem:

    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
        }
    })();
    

    Usage:

    MathHelper.round(5.175, 2)
    

    Demo: http://jsfiddle.net/v2Dj7/

    0 讨论(0)
  • 2020-12-30 05:34

    Kippie your solution has problems one of them

    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();
    

    this works good)

    0 讨论(0)
  • 2020-12-30 05:35

    You could always try using round, instead of toFixed.

    Math.round(5.175*100)/100

    You could even try putting it in some prototype method if you want.

    Created a jsBin that implements a simple prototype on Number.

    Number.prototype.toFixed = function(decimals) {
     return Math.round(this * Math.pow(10, decimals)) / (Math.pow(10, decimals)); 
    };
    
    0 讨论(0)
  • 2020-12-30 05:40

    Actually I think this is a bug in the implementation of Number.prototype.toFixed. The algorithm given in ECMA-262 20.1.3.3 10-a says to round up as a tie-breaker. As others have mentioned, there probably isn't a tie to break due to floating point imprecisions in the implementation. But that doesn't make it right :)

    At least this behavior is consistent across FF, Chrome, Opera, Safari. (Haven't tried others.)

    FWIW, you can actually implement your own version of toFixed per the spec in JS and that behaves as you would expect. See http://jsfiddle.net/joenudell/7qahrb6d/.

    0 讨论(0)
提交回复
热议问题