Formatting a number with exactly two decimals in JavaScript

后端 未结 30 2241
广开言路
广开言路 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 07:04

    This is an old topic but still top-ranked Google results and the solutions offered share the same floating point decimals issue. Here is the (very generic) function I use, thanks to MDN:

    function round(value, exp) {
      if (typeof exp === 'undefined' || +exp === 0)
        return Math.round(value);
    
      value = +value;
      exp = +exp;
    
      if (isNaN(value) || !(typeof exp === 'number' && exp % 1 === 0))
        return NaN;
    
      // Shift
      value = value.toString().split('e');
      value = Math.round(+(value[0] + 'e' + (value[1] ? (+value[1] + exp) : exp)));
    
      // Shift back
      value = value.toString().split('e');
      return +(value[0] + 'e' + (value[1] ? (+value[1] - exp) : -exp));
    }
    

    As we can see, we don't get these issues:

    round(1.275, 2);   // Returns 1.28
    round(1.27499, 2); // Returns 1.27
    

    This genericity also provides some cool stuff:

    round(1234.5678, -2);   // Returns 1200
    round(1.2345678e+2, 2); // Returns 123.46
    round("123.45");        // Returns 123
    

    Now, to answer the OP's question, one has to type:

    round(10.8034, 2).toFixed(2); // Returns "10.80"
    round(10.8, 2).toFixed(2);    // Returns "10.80"
    

    Or, for a more concise, less generic function:

    function round2Fixed(value) {
      value = +value;
    
      if (isNaN(value))
        return NaN;
    
      // Shift
      value = value.toString().split('e');
      value = Math.round(+(value[0] + 'e' + (value[1] ? (+value[1] + 2) : 2)));
    
      // Shift back
      value = value.toString().split('e');
      return (+(value[0] + 'e' + (value[1] ? (+value[1] - 2) : -2))).toFixed(2);
    }
    

    You can call it with:

    round2Fixed(10.8034); // Returns "10.80"
    round2Fixed(10.8);    // Returns "10.80"
    

    Various examples and tests (thanks to @t-j-crowder!):

    function round(value, exp) {
      if (typeof exp === 'undefined' || +exp === 0)
        return Math.round(value);
    
      value = +value;
      exp = +exp;
    
      if (isNaN(value) || !(typeof exp === 'number' && exp % 1 === 0))
        return NaN;
    
      // Shift
      value = value.toString().split('e');
      value = Math.round(+(value[0] + 'e' + (value[1] ? (+value[1] + exp) : exp)));
    
      // Shift back
      value = value.toString().split('e');
      return +(value[0] + 'e' + (value[1] ? (+value[1] - exp) : -exp));
    }
    function naive(value, exp) {
      if (!exp) {
        return Math.round(value);
      }
      var pow = Math.pow(10, exp);
      return Math.round(value * pow) / pow;
    }
    function test(val, places) {
      subtest(val, places);
      val = typeof val === "string" ? "-" + val : -val;
      subtest(val, places);
    }
    function subtest(val, places) {
      var placesOrZero = places || 0;
      var naiveResult = naive(val, places);
      var roundResult = round(val, places);
      if (placesOrZero >= 0) {
        naiveResult = naiveResult.toFixed(placesOrZero);
        roundResult = roundResult.toFixed(placesOrZero);
      } else {
        naiveResult = naiveResult.toString();
        roundResult = roundResult.toString();
      }
      $("")
        .append($("").text(JSON.stringify(val)))
        .append($("").text(placesOrZero))
        .append($("").text(naiveResult))
        .append($("").text(roundResult))
        .appendTo("#results");
    }
    test(0.565, 2);
    test(0.575, 2);
    test(0.585, 2);
    test(1.275, 2);
    test(1.27499, 2);
    test(1234.5678, -2);
    test(1.2345678e+2, 2);
    test("123.45");
    test(10.8034, 2);
    test(10.8, 2);
    test(1.005, 2);
    test(1.0005, 2);
    table {
      border-collapse: collapse;
    }
    table, td, th {
      border: 1px solid #ffffd;
    }
    td, th {
      padding: 4px;
    }
    th {
      font-weight: normal;
      font-family: sans-serif;
    }
    td {
      font-family: monospace;
    }
    Input Places Naive Thorough

提交回复
热议问题