Formatting a number with exactly two decimals in JavaScript

后端 未结 30 2095
广开言路
广开言路 2020-11-21 06:29

I have this line of code which rounds my numbers to two decimal places. But I get numbers like this: 10.8, 2.4, etc. These are not my idea of two decimal places so how I can

相关标签:
30条回答
  • 2020-11-21 06:48

    With these examples you will still get an error when trying to round the number 1.005 the solution is to either use a library like Math.js or this function:

    function round(value: number, decimals: number) {
        return Number(Math.round(value + 'e' + decimals) + 'e-' + decimals);
    }
    
    0 讨论(0)
  • 2020-11-21 06:48

    I got some ideas from this post a few months back, but none of the answers here, nor answers from other posts/blogs could handle all the scenarios (e.g. negative numbers and some "lucky numbers" our tester found). In the end, our tester did not find any problem with this method below. Pasting a snippet of my code:

    fixPrecision: function (value) {
        var me = this,
            nan = isNaN(value),
            precision = me.decimalPrecision;
    
        if (nan || !value) {
            return nan ? '' : value;
        } else if (!me.allowDecimals || precision <= 0) {
            precision = 0;
        }
    
        //[1]
        //return parseFloat(Ext.Number.toFixed(parseFloat(value), precision));
        precision = precision || 0;
        var negMultiplier = value < 0 ? -1 : 1;
    
        //[2]
        var numWithExp = parseFloat(value + "e" + precision);
        var roundedNum = parseFloat(Math.round(Math.abs(numWithExp)) + 'e-' + precision) * negMultiplier;
        return parseFloat(roundedNum.toFixed(precision));
    },
    

    I also have code comments (sorry i forgot all the details already)...I'm posting my answer here for future reference:

    9.995 * 100 = 999.4999999999999
    Whereas 9.995e2 = 999.5
    This discrepancy causes Math.round(9.995 * 100) = 999 instead of 1000.
    Use e notation instead of multiplying /dividing by Math.Pow(10,precision).
    
    0 讨论(0)
  • 2020-11-21 06:48

    I found a very simple way that solved this problem for me and can be used or adapted:

    td[row].innerHTML = price.toPrecision(price.toFixed(decimals).length
    
    0 讨论(0)
  • 2020-11-21 06:49

    Put the following in some global scope:

    Number.prototype.getDecimals = function ( decDigCount ) {
       return this.toFixed(decDigCount);
    }
    

    and then try:

    var a = 56.23232323;
    a.getDecimals(2); // will return 56.23
    

    Update

    Note that toFixed() can only work for the number of decimals between 0-20 i.e. a.getDecimals(25) may generate a javascript error, so to accomodate that you may add some additional check i.e.

    Number.prototype.getDecimals = function ( decDigCount ) {
       return ( decDigCount > 20 ) ? this : this.toFixed(decDigCount);
    }
    
    0 讨论(0)
  • 2020-11-21 06:49

    I'm fix the problem the modifier. Support 2 decimal only.

    $(function(){
      //input number only.
      convertNumberFloatZero(22); // output : 22.00
      convertNumberFloatZero(22.5); // output : 22.50
      convertNumberFloatZero(22.55); // output : 22.55
      convertNumberFloatZero(22.556); // output : 22.56
      convertNumberFloatZero(22.555); // output : 22.55
      convertNumberFloatZero(22.5541); // output : 22.54
      convertNumberFloatZero(22222.5541); // output : 22,222.54
    
      function convertNumberFloatZero(number){
    	if(!$.isNumeric(number)){
    		return 'NaN';
    	}
    	var numberFloat = number.toFixed(3);
    	var splitNumber = numberFloat.split(".");
    	var cNumberFloat = number.toFixed(2);
    	var cNsplitNumber = cNumberFloat.split(".");
    	var lastChar = splitNumber[1].substr(splitNumber[1].length - 1);
    	if(lastChar > 0 && lastChar < 5){
    		cNsplitNumber[1]--;
    	}
    	return Number(splitNumber[0]).toLocaleString('en').concat('.').concat(cNsplitNumber[1]);
      };
    });
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>

    0 讨论(0)
  • 2020-11-21 06:50

    In general, decimal rounding is done by scaling: round(num * p) / p

    Naive implementation

    Using the following function with halfway numbers, you will get either the upper rounded value as expected, or the lower rounded value sometimes depending on the input.

    This inconsistency in rounding may introduce hard to detect bugs in the client code.

    function naiveRound(num, decimalPlaces) {
        var p = Math.pow(10, decimalPlaces);
        return Math.round(num * p) / p;
    }
    
    console.log( naiveRound(1.245, 2) );  // 1.25 correct (rounded as expected)
    console.log( naiveRound(1.255, 2) );  // 1.25 incorrect (should be 1.26)

    Better implementations

    By converting the number to a string in the exponential notation, positive numbers are rounded as expected. But, be aware that negative numbers round differently than positive numbers.

    In fact, it performs what is basically equivalent to "round half up" as the rule, you will see that round(-1.005, 2) evaluates to -1 even though round(1.005, 2) evaluates to 1.01. The lodash _.round method uses this technique.

    /**
     * Round half up ('round half towards positive infinity')
     * Uses exponential notation to avoid floating-point issues.
     * Negative numbers round differently than positive numbers.
     */
    function round(num, decimalPlaces) {
        num = Math.round(num + "e" + decimalPlaces);
        return Number(num + "e" + -decimalPlaces);
    }
    
    // test rounding of half
    console.log( round(0.5, 0) );  // 1
    console.log( round(-0.5, 0) ); // 0
    
    // testing edge cases
    console.log( round(1.005, 2) );   // 1.01
    console.log( round(2.175, 2) );   // 2.18
    console.log( round(5.015, 2) );   // 5.02
    
    console.log( round(-1.005, 2) );  // -1
    console.log( round(-2.175, 2) );  // -2.17
    console.log( round(-5.015, 2) );  // -5.01

    If you want the usual behavior when rounding negative numbers, you would need to convert negative numbers to positive before calling Math.round(), and then convert them back to negative numbers before returning.

    // Round half away from zero
    function round(num, decimalPlaces) {
        num = Math.round(Math.abs(num) + "e" + decimalPlaces) * Math.sign(num);
        return Number(num + "e" + -decimalPlaces);
    }
    

    There is a different purely mathematical technique to perform round-to-nearest (using "round half away from zero"), in which epsilon correction is applied before calling the rounding function.

    Simply, we add the smallest possible float value (= 1.0 ulp; unit in the last place) to the number before rounding. This moves to the next representable value after the number, away from zero.

    /**
     * Round half away from zero ('commercial' rounding)
     * Uses correction to offset floating-point inaccuracies.
     * Works symmetrically for positive and negative numbers.
     */
    function round(num, decimalPlaces) {
        var p = Math.pow(10, decimalPlaces);
        var e = Number.EPSILON * num * p;
        return Math.round((num * p) + e) / p;
    }
    
    // test rounding of half
    console.log( round(0.5, 0) );  // 1
    console.log( round(-0.5, 0) ); // -1
    
    // testing edge cases
    console.log( round(1.005, 2) );  // 1.01
    console.log( round(2.175, 2) );  // 2.18
    console.log( round(5.015, 2) );  // 5.02
    
    console.log( round(-1.005, 2) ); // -1.01
    console.log( round(-2.175, 2) ); // -2.18
    console.log( round(-5.015, 2) ); // -5.02

    This is needed to offset the implicit round-off error that may occur during encoding of decimal numbers, particularly those having "5" in the last decimal position, like 1.005, 2.675 and 16.235. Actually, 1.005 in decimal system is encoded to 1.0049999999999999 in 64-bit binary float; while, 1234567.005 in decimal system is encoded to 1234567.0049999998882413 in 64-bit binary float.

    It is worth noting that the maximum binary round-off error is dependent upon (1) the magnitude of the number and (2) the relative machine epsilon (2^-52).

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