66 题: 舍入到最多2位小数(仅在必要时)

在...创建的问题 Tue, Apr 30, 2019 12:00 AM

我想最多舍入2位小数,但只在必要时

输入:

 
10
1.7777777
9.1

输出:

 
10
1.78
9.1

我怎样才能在JavaScript中执行此操作?

    
2278
  1. 我在这里作为解决方案提供了许多技术,因此你可以比较:小提琴
    2013-11-18 09:45:13Z
  2. 似乎没有人知道 Number.EPSILON 。使用Math.round( num * 100 + Number.EPSILON ) / 100
    2017-01-18 09:59:30Z
  3. 对于新读者,除非您有字符串类型结果,否则不能执行此操作。二进制内部数字表示的浮点数学意味着总是数字不能表示为小数。
    2018-02-20 01:42:05Z
  4. @ cronvel你能解释在这里使用Number.EPSILON的原因吗?
    2018-10-19 03:10:40Z
  5. 醇>
    30答案                              30 跨度>                         

    使用Math.round(num * 100) / 100

        
    2869
    2013-03-14 20:13:38Z
    1. 虽然这适用于大多数情况,但它不适用于1.005,最终会变为1而不是1.01
      2013-06-13 14:33:57Z
    2. @ James Wow真的很奇怪 - 我在Chrome开发控制台工作,我注意到1.005 * 100 = 100.49999999999999。 Math.round(100.49999999999999)的计算结果为100,而Math.round(100.5)的计算结果为101.IE9做同样的事情。这是由于 javascript中的浮点奇怪
      2013-07-26 17:32:41Z
    3. 一个简单的解决方法。 2 d.p.,使用Math.round((num + 0.00001) * 100) / 100。试试Math.round((1.005 + 0.00001) * 100) / 100Math.round((1.0049 + 0.00001) * 100) / 100
      2013-10-09 07:01:53Z
    4. @ mrkschan为什么这样做,并且所有数字都是万无一失的?
      2014-03-03 04:45:37Z
    5. 对于那些没有得到它的人来说,这种技术称为缩放。基本上这里的答案是将小数点上的两个数字转换成一个整数,以避免所有疯狂的浮点问题,然后将其转换回原来的数字除以100并得到你的回答2dp。
      2014-11-14 18:15:19Z
    6. 醇>

    如果值是文本类型:

     
    parseFloat("123.456").toFixed(2);
    

    如果值是数字:

     
    var numb = 123.23454;
    numb = numb.toFixed(2);
    

    有一个缺点,像1.5这样的值会给出“1.50”作为输出。 @minitech建议修复:

     
    var numb = 1.5;
    numb = +numb.toFixed(2);
    // Note the plus sign that drops any "extra" zeroes at the end.
    // It changes the result (which is a string) into a number again (think "0 + foo"),
    // which means that it uses only as many digits as necessary.
    

    似乎Math.round是更好的解决方案。 但事实并非如此!在某些情况下,它会 NOT 正确舍入:

     
    Math.round(1.005 * 1000)/1000 // Returns 1 instead of expected 1.01!
    
    在某些情况下,

    toFixed()也会 NOT 正确舍入(在Chrome v.55.0.2883.87中测试)!

    示例:

     
    parseFloat("1.555").toFixed(2); // Returns 1.55 instead of 1.56.
    parseFloat("1.5550").toFixed(2); // Returns 1.55 instead of 1.56.
    // However, it will return correct result if you round 1.5551.
    parseFloat("1.5551").toFixed(2); // Returns 1.56 as expected.
    
    1.3555.toFixed(3) // Returns 1.355 instead of expected 1.356.
    // However, it will return correct result if you round 1.35551.
    1.35551.toFixed(2); // Returns 1.36 as expected.
    

    我想,这是因为1.555实际上就像浮动1.55499994那样后现场。

    解决方案1 ​​是使用带有所需舍入算法的脚本,例如:

     
    function roundNumber(num, scale) {
      if(!("" + num).includes("e")) {
        return +(Math.round(num + "e+" + scale)  + "e-" + scale);
      } else {
        var arr = ("" + num).split("e");
        var sig = ""
        if(+arr[1] + scale > 0) {
          sig = "+";
        }
        return +(Math.round(+arr[0] + "e" + sig + (+arr[1] + scale)) + "e-" + scale);
      }
    }
    

    https://plnkr.co/edit/uau8BlS1cqbvWPCHJeOy?p=preview

    解决方案2 是为了避免前端计算并从后端服务器中提取舍入值。

        
    2692
    2017-05-26 19:39:33Z
    1. 这一个(toFixed)方法很好,对我有用,但它特别符合“仅”的原始请求必要时”。 (它的结果是1.5到1.50,这打破了规范。)
      2013-04-28 20:09:27Z
    2. 对于“必要时”要求,请执行以下操作:parseFloat(number.toFixed(decimalPlaces)); @PerLundberg
      2013-12-30 02:23:19Z
    3. parseFloat("55.555").toFixed(2)在Chrome开发者控制台中返回"55.55"
      2014-04-06 16:02:33Z
    4. 使用toFixed而不是Math.round没有任何优势; toFixed导致完全相同的舍入问题(尝试使用5.555和1.005),但就像500x(没有开玩笑)慢于Math.round ...似乎@MarkG答案在这里更准确。
      2014-05-20 16:49:34Z
    5. toFixed不“有时”返回一个字符串,它总是返回一个字符串。
      2014-06-25 20:39:42Z
    6. 醇>

    您可以使用

     
    function roundToTwo(num) {    
        return +(Math.round(num + "e+2")  + "e-2");
    }
    

    我在 MDN 一>。他们的方式避免了1.005的问题,即提到

     
    roundToTwo(1.005)
    1.01
    roundToTwo(10)
    10
    roundToTwo(1.7777777)
    1.78
    roundToTwo(9.1)
    9.1
    roundToTwo(1234.5678)
    1234.57
    
        
    398
    2018-02-12 16:11:16Z
    1. @ Redsandro,+(val)是使用Number(val)的强制等效物。将“e-2”连接到一个数字会产生一个需要转换回数字的字符串。
      2014-02-28 19:11:48Z
    2. 请注意,对于那些会产生NaN的大小浮点数,例如+“1e-21 + 2”将无法正确解析。
      2014-05-20 17:13:40Z
    3. 你已经“解决了”1.005'问题',但引入了一个新问题:现在,在Chrome控制台中,roundToTwo(1.0049999999999999)出现了1.01(不可避免地,自1.0049999999999999 == 1.005以来) )。在我看来,如果你输入num = 1.005'显然''应该'舍入到1.00,你得到的浮点数,因为num的确切值小于1.005。当然,在我看来,字符串'1.005''显然''应该'舍入到1.01。事实上,不同的人似乎对这里的实际正确行为有不同的直觉,这是其复杂性的一部分。
      2014-08-14 21:56:46Z
    4. 1.00499999999999991.005之间没有(浮点)数字,因此根据定义,它们是相同的数字。这被称为dedekind cut。
      2015-02-18 00:48:55Z
    5. @ Azmisov是对的。 1.00499 < 1.005true,1.0049999999999999 < 1.005评估为false
      2015-09-23 10:55:29Z
    6. 醇>

    MarkG的回答我是正确的。这是任意数量小数位的通用扩展名。

     
    Number.prototype.round = function(places) {
      return +(Math.round(this + "e+" + places)  + "e-" + places);
    }
    

    用法:

     
    var n = 1.7777;    
    n.round(2); // 1.78
    

    单元测试:

     
    it.only('should round floats to 2 places', function() {
    
      var cases = [
        { n: 10,      e: 10,    p:2 },
        { n: 1.7777,  e: 1.78,  p:2 },
        { n: 1.005,   e: 1.01,  p:2 },
        { n: 1.005,   e: 1,     p:0 },
        { n: 1.77777, e: 1.8,   p:1 }
      ]
    
      cases.forEach(function(testCase) {
        var r = testCase.n.round(testCase.p);
        assert.equal(r, testCase.e, 'didn\'t get right number');
      });
    })
    
        
    131
    2013-11-01 07:40:59Z
    1. Pierre对MarkG的回答提出了一个严重的问题。
      2014-06-18 16:23:40Z
    2. 注意:如果您不想更改Number.prototype - 只需将其写为函数:function round(number, decimals) { return +(Math.round(number + "e+" + decimals) + "e-" + decimals); }
      2014-11-08 17:28:47Z
    3. 一种很酷的扩展方式。您可以检查十进制是否为负,然后反转e +和e-。那么n = 115; n.round(-2);会产生100
      2016-03-23 06:28:36Z
    4. 尝试n:1e + 19 - 它返回NaN
      2017-12-18 20:59:20Z
    5. 此算法总是向上舍入(而不是从零开始)。因此,如果是负数,则输出不是您所期望的:(-1.005).round(2) === -1
      2018-02-14 10:51:04Z
    6. 醇>

    可以使用.toFixed(NumberOfDecimalPlaces)

     
    var str = 10.234.toFixed(2); // => '10.23'
    var number = Number(str); // => 10.23
    
        
    78
    2017-05-18 16:28:29Z
    1. 为什么这不是最佳答案? (编辑:哦,因为它转换为字符串:)
      2014-11-07 01:05:08Z
    2. 也因为它添加了尾随零,这不是原始问题所要求的。
      2014-12-05 18:38:27Z
    3. 但尾随的零很容易用正则表达式去掉,即`Number(10.10000.toFixed(2).replace(/0 + $/,''))`= &GT; 10.1
      2016-02-18 21:31:37Z
    4. @ daniel 最佳答案是相同的(截至现在)但它没有正确地 alsways ,请尝试+(1.005).toFixed(2),它返回1而不是1.01
      2016-11-01 19:34:15Z
    5. @ ChadMcElligott:你的正则表达式不适用于整数:Number(9).toFixed(2).replace(/0+$/, '') =&gt; “9”。
      2017-05-18 09:41:17Z
    6. 醇>

    这个问题很复杂。

    假设我们有一个函数roundTo2DP(num),它将float作为参数并返回一个四舍五入到小数位的值。每个表达式应该评估什么?

    • roundTo2DP(0.014999999999999999)
    • roundTo2DP(0.0150000000000000001)
    • roundTo2DP(0.015)

    '明显'的答案是第一个例子应该舍入到0.01(因为它接近0.01而不是0.02),而另外两个应该舍入到0.02(因为0.0150000000000000001接近0.02而不是0.01,因为0.015是它们恰好位于它们之间,并且有一个数学约定,这些数字会被四舍五入。)

    您可能已经猜到的问题是,roundTo2DP 不可能实施以提供明显的答案,因为传递给它的所有三个数字都是相同的数字 。 IEEE 754二进制浮点数(JavaScript使用的类型)不能精确地表示大多数非整数数字,因此上面的所有三个数字文字都会四舍五入到附近的有效浮点数。这个数字恰好是

    0.01499999999999999944488848768742172978818416595458984375

    接近0.01而不是0.02。

    你可以看到所有三个数字都是山姆e在浏览器控制台,Node shell或其他JavaScript解释器上。只是比较它们:

     
    > 0.014999999999999999 === 0.0150000000000000001
    true

    所以当我写m = 0.0150000000000000001时,我最终得到的 m 的精确值接近0.01而不是0.02。然而,如果我将m转换为String ...

     
    > var m = 0.0150000000000000001;
    > console.log(String(m));
    0.015
    > var m = 0.014999999999999999;
    > console.log(String(m));
    0.015

    ...我得到0.015,它应该舍入到0.02,这显然我之前说过的所有这些数字完全相等的56位小数位数。那么黑暗魔法是什么呢?

    答案可以在ECMAScript规范的 7.1.12.1:ToString应用于数字类型 。这里规定了将一些数字 m 转换为String的规则。关键部分是第5点,其中生成一个整数 s ,其数字将用于 m 的字符串表示中:

      

    n k s 为整数,使 k ≥1,10 k -1 s &lt; 10 k s的数值×10 n - k m k 尽可能小。请注意,k是 s 的十进制表示中的位数, s 不能被10整除,而 s的最低位数不一定是由这些标准唯一确定的。

    这里的关键部分是要求“ k 尽可能小”。该要求相当于要求,在给定编号m时,String(m)的值必须具有最小可能的位数,同时仍满足Number(String(m)) === m的要求。由于我们已经知道0.015 === 0.0150000000000000001,现在很清楚为什么String(0.0150000000000000001) === '0.015'必须是真的。

    当然,这个讨论都没有直接回答roundTo2DP(m) 应该返回的内容。如果m的确切值是0.01499999999999999944488848768742172978818416595458984375,但它的字符串表示是'0.015',那么什么是正确的答案 - 数学,实际,哲学或其他什么 - 当我们将它四舍五入到小数点后两位?

    没有一个正确的答案。这取决于您的用例。您可能希望在以下情况下尊重字符串表示并向上舍入:

    • 所表示的值本质上是离散的,例如一种3位小数位的货币,如第纳尔。在这种情况下,像0.015 这样的数字的 true 0.015,并且它在二进制浮点中获得的0.0149999999 ...表示是舍入误差。 (当然,许多人会合理地争辩说,你应该使用十进制库来处理这些值,并且从不将它们首先表示为二进制浮点数。)
    • 该值由用户输入。在这种情况下,再次输入的确切十进制数比最接近的二进制浮点表示更“真”。

    另一方面,您可能希望尊重二进制浮点值,并在您的值来自固有的连续比例时向下舍入 - 例如,如果它是来自传感器的读数。

    这两种方法需要不同的代码。为了尊重Number的String表示,我们可以(通过相当多一些相当微妙的代码)实现我们自己的舍入,它直接作用于String表示,逐位,使用您在学校时使用的相同算法被教导如何围绕数字。下面是一个例子,它尊重OP要求通过在小数点后剥去尾随零来“仅在必要时”将数字表示为2位小数的要求;当然,您可能需要根据您的确切需求进行调整。

     
    /**
     * Converts num to a decimal string (if it isn't one already) and then rounds it
     * to at most dp decimal places.
     *
     * For explanation of why you'd want to perform rounding operations on a String
     * rather than a Number, see http://stackoverflow.com/a/38676273/1709587
     *
     * @param {(number|string)} num
     * @param {number} dp
     * @return {string}
     */
    function roundStringNumberWithoutTrailingZeroes (num, dp) {
        if (arguments.length != 2) throw new Error("2 arguments required");
    
        num = String(num);
        if (num.indexOf('e+') != -1) {
            // Can't round numbers this large because their string representation
            // contains an exponent, like 9.99e+37
            throw new Error("num too large");
        }
        if (num.indexOf('.') == -1) {
            // Nothing to do
            return num;
        }
    
        var parts = num.split('.'),
            beforePoint = parts[0],
            afterPoint = parts[1],
            shouldRoundUp = afterPoint[dp] >= 5,
            finalNumber;
    
        afterPoint = afterPoint.slice(0, dp);
        if (!shouldRoundUp) {
            finalNumber = beforePoint + '.' + afterPoint;
        } else if (/^9+$/.test(afterPoint)) {
            // If we need to round up a number like 1.9999, increment the integer
            // before the decimal point and discard the fractional part.
            finalNumber = Number(beforePoint)+1;
        } else {
            // Starting from the last digit, increment digits until we find one
            // that is not 9, then stop
            var i = dp-1;
            while (true) {
                if (afterPoint[i] == '9') {
                    afterPoint = afterPoint.substr(0, i) +
                                 '0' +
                                 afterPoint.substr(i+1);
                    i--;
                } else {
                    afterPoint = afterPoint.substr(0, i) +
                                 (Number(afterPoint[i]) + 1) +
                                 afterPoint.substr(i+1);
                    break;
                }
            }
    
            finalNumber = beforePoint + '.' + afterPoint;
        }
    
        // Remove trailing zeroes from fractional part before returning
        return finalNumber.replace(/0+$/, '')
    }
    

    使用示例:

     
    > roundStringNumberWithoutTrailingZeroes(1.6, 2)
    '1.6'
    > roundStringNumberWithoutTrailingZeroes(10000, 2)
    '10000'
    > roundStringNumberWithoutTrailingZeroes(0.015, 2)
    '0.02'
    > roundStringNumberWithoutTrailingZeroes('0.015000', 2)
    '0.02'
    > roundStringNumberWithoutTrailingZeroes(1, 1)
    '1'
    > roundStringNumberWithoutTrailingZeroes('0.015', 2)
    '0.02'
    > roundStringNumberWithoutTrailingZeroes(0.01499999999999999944488848768742172978818416595458984375, 2)
    '0.02'
    > roundStringNumberWithoutTrailingZeroes('0.01499999999999999944488848768742172978818416595458984375', 2)
    '0.01'

    上面的函数可能你想用什么来避免用户看到他们输入的数字被错误地舍入。

    (作为替代方案,您也可以尝试 round10 库,该库提供类似功能的库一种完全不同的实现。)

    但是,如果你有第二种数字 - 从连续尺度中取得的值,那么没有理由认为具有较少小数位的近似十进制表示比具有更多数字的那些更准确 ?在这种情况下,我们想要尊重String表示,因为该表示(如规范中所述)已经是排序的;我们不想错误地说“0.014999999 ... 375轮到0.015,最高为0.02,所以0.014999999 ... 375轮到0.02”。

    在这里,我们可以简单地使用内置的 toFixed 方法。注意通过在Number()返回的字符串上调用toFixed,我们得到一个其字符串表示没有尾随零的数字(由于JavaScript计算数字的字符串表示的方式,在本回答前面讨论过)。

     
    /**
     * Takes a float and rounds it to at most dp decimal places. For example
     *
     *     roundFloatNumberWithoutTrailingZeroes(1.2345, 3)
     *
     * returns 1.234
     *
     * Note that since this treats the value passed to it as a floating point
     * number, it will have counterintuitive results in some cases. For instance,
     * 
     *     roundFloatNumberWithoutTrailingZeroes(0.015, 2)
     *
     * gives 0.01 where 0.02 might be expected. For an explanation of why, see
     * http://stackoverflow.com/a/38676273/1709587. You may want to consider using the
     * roundStringNumberWithoutTrailingZeroes function there instead.
     *
     * @param {number} num
     * @param {number} dp
     * @return {number}
     */
    function roundFloatNumberWithoutTrailingZeroes (num, dp) {
        var numToFixedDp = Number(num).toFixed(dp);
        return Number(numToFixedDp);
    }
    
        
    65
    2017-06-01 20:07:48Z
    1. 这在某些边缘情况下不起作用:尝试( jsfiddle )与roundStringNumberWithoutTrailingZeroes(362.42499999999995, 2)。预期结果(如PHP echo round(362.42499999999995, 2)):362.43。实际结果:362.42
      2017-12-06 14:11:43Z
    2. @ Dr.GianluigiZaneZanettini Huh。奇怪的。我不确定为什么PHP的round给出了362.43。这似乎是直觉错误,因为362.42499999999995小于362.425(在数学和代码中 - 362.42499999999995 < 362.425在JS和PHP中都是如此)。从362.43 - 362.42499999999995 > 362.42499999999995 - 362.42开始,PHP的答案也不会最小化原始浮点数和舍入浮点数之间的距离。根据 php.net/manual/en/function.round.php , PHP的round遵循C99标准;我将不得不冒险进入C领域,了解发生了什么。
      2017-12-06 14:39:04Z
    3. 看了在PHP的源代码中实现舍入,我不知道它在做什么。这是一个非常复杂的实现,包括宏,分支和字符串转换以及硬编码魔术精度值的分支。我不知道除了“PHP的答案是明显错误的,我们应该提交错误报告”之外该说些什么。顺便问一下,你怎么找到号码362.42499999999995?
      2017-12-06 22:29:26Z
    4. @ Dr.GianluigiZaneZanettini我创建了一个错误报告: bugs.php.net/bug.php?id=75644
      2017-12-06 22:48:54Z
    5. 我实际上认为PHP是正确的,因为362.42499999999995以“5”结尾,所以数字必须“向上”,而不是“向下”。我有意义吗?无论如何,谢谢你的努力!我发现该数字对价格应用了%折扣。
      2017-12-07 16:25:11Z
    6. 醇>

    考虑.toFixed().toPrecision()

    http://www.javascriptkit.com/javatutors/formatnumber.shtml

        
    64
    2013-06-05 12:25:59Z
    1. toFixed将小数点添加到每个值,无论如何。
      2012-08-06 17:22:53Z
    2. 这两个都没用了
      2012-08-06 17:23:40Z
    3. 不幸的是,这两个函数都会添加@stinkycheeseman似乎不想要的额外小数位。
      2012-08-06 17:24:18Z
    4. 2012-08-06 17:30:41Z
    5. 他们返回字符串而不是数字,所以他们格式化而不是计算..
      2016-07-14 09:59:33Z
    6. 醇>

    精确的舍入方法。来源: Mozilla

     
    (function(){
    
        /**
         * Decimal adjustment of a number.
         *
         * @param   {String}    type    The type of adjustment.
         * @param   {Number}    value   The number.
         * @param   {Integer}   exp     The exponent (the 10 logarithm of the adjustment base).
         * @returns {Number}            The adjusted value.
         */
        function decimalAdjust(type, value, exp) {
            // If the exp is undefined or zero...
            if (typeof exp === 'undefined' || +exp === 0) {
                return Math[type](value);
            }
            value = +value;
            exp = +exp;
            // If the value is not a number or the exp is not an integer...
            if (isNaN(value) || !(typeof exp === 'number' && exp % 1 === 0)) {
                return NaN;
            }
            // Shift
            value = value.toString().split('e');
            value = Math[type](+(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));
        }
    
        // Decimal round
        if (!Math.round10) {
            Math.round10 = function(value, exp) {
                return decimalAdjust('round', value, exp);
            };
        }
        // Decimal floor
        if (!Math.floor10) {
            Math.floor10 = function(value, exp) {
                return decimalAdjust('floor', value, exp);
            };
        }
        // Decimal ceil
        if (!Math.ceil10) {
            Math.ceil10 = function(value, exp) {
                return decimalAdjust('ceil', value, exp);
            };
        }
    })();
    

    示例:

     
    // Round
    Math.round10(55.55, -1); // 55.6
    Math.round10(55.549, -1); // 55.5
    Math.round10(55, 1); // 60
    Math.round10(54.9, 1); // 50
    Math.round10(-55.55, -1); // -55.5
    Math.round10(-55.551, -1); // -55.6
    Math.round10(-55, 1); // -50
    Math.round10(-55.1, 1); // -60
    Math.round10(1.005, -2); // 1.01 -- compare this with Math.round(1.005*100)/100 above
    // Floor
    Math.floor10(55.59, -1); // 55.5
    Math.floor10(59, 1); // 50
    Math.floor10(-55.51, -1); // -55.6
    Math.floor10(-51, 1); // -60
    // Ceil
    Math.ceil10(55.51, -1); // 55.6
    Math.ceil10(51, 1); // 60
    Math.ceil10(-55.59, -1); // -55.5
    Math.ceil10(-59, 1); // -50
    
        
    62
    2017-05-26 19:46:02Z
    1. 有人把它放在GitHub和npm上: github的.com /jhohlfeld /round10
      2016-06-03 21:51:08Z
    2. Nah,Math.round10(3544.5249, -2)返回3544.52而不是3544.53
      2016-09-21 16:29:55Z
    3. @ Matija Wolfram alpha 也说3544.52。您希望最小化当前数字和舍入近似值之间的误差。最接近3544.5249到2位小数是3544.52(误差= 0.0049)。如果是3544.53,则误差为0.0051。你正在进行连续的舍入,即Math.round10(Math.round10(3544.5249,-3), - 2),它会产生更大的舍入误差,因此不可取。
      2016-09-21 17:33:19Z
    4. @ Matija,从数学的角度来看,3544.5249舍入为3544.52,而不是3544.53,所以这段代码是正确的。如果你想要它在这个四舍五入到3544.53和像这样的情况(即使很难是不正确的),做这样的事情:number += 0.00011
      2016-11-16 15:03:41Z
    5. @ Matija:我认为该功能可以正常工作。也许你想迭代四舍五入:Math.round10( Math.round10(3544.5249, -3) , -2)
      2017-07-22 14:31:22Z
    6. 醇>

    此处找到的答案都不正确。 @stinkycheeseman要求四舍五入,你们都把这个数字四舍五入。

    要整理,请使用:

     
    Math.ceil(num * 100)/100;
    
        
    58
    2013-07-02 08:18:35Z
    1. 示例输入和输出显示虽然问题是'向上舍入......'但实际上是'圆形到......'。
      2013-07-05 04:18:10Z
    2. @ stinkycheeseman指出了一个特定情况下的错误,他不想总是像ceil一样向上舍入,他只想要0.005来舍入到0.01
      2013-08-23 10:17:40Z
    3. 测试时发现奇怪的错误Math.ceil(1.1 * 100)/100; -it返回1.11,因为根据全新的现代浏览器Firefox,Chrome,Safari和Opera,1.1 * 100是110.00000000000001 ...... IE,旧时尚,仍然认为1.1*100=1100
      2013-10-21 11:57:24Z
    4. @ skobaljic try Math.ceil(num.toFixed(4) * 100) / 100
      2013-12-11 23:07:57Z
    5. @ treeface Math.ceil((1.1).toFixed(4) * 100) / 100也将在Firefox中返回1.11,现代浏览器问题/错误是乘法,人们应该知道它(我在那个时候参与了一个彩票游戏例子)。
      2014-01-09 09:43:48Z
    6. 醇>

    您应该使用:

     
    Math.round( num * 100 + Number.EPSILON ) / 100
    

    似乎没有人知道 Number.EPSILON

    另外值得注意的是,这不像某些人所说的那样 JavaScript怪异

    这就是浮点数在计算机中的工作方式。与99%的编程语言一样,JavaScript没有自制的浮点数;它依赖于CPU /FPU。计算机使用二进制,而在二进制中,没有任何数字,如0.1,但仅仅是二进制近似。为什么?出于同样的原因,1/3不能用十进制写:它的值是0.33333333 ......无穷大的三分之一。

    Number.EPSILON 。该数字是1和双精度浮点数中存在的 next 数之间的差值。 就是这样:1和1 + Number.EPSILON之间没有数字。

    修改强>

    正如评论中所提到的,让我们澄清一点:只有当round的值是算术运算的结果时才添加Number.EPSILON,因为它可以吞下一些浮点误差delta。

    当值来自直接来源(例如:文字,用户输入或传感器)时,它没有用。

        
    50
    2017-12-08 12:29:55Z
    1. 在Internet Explorer中未定义Number.EPSILON。
      2017-02-10 19:09:36Z
    2. @ palota你可以定义一个真正的数字,比如EPSILON cronvel提到
      2017-05-24 15:25:10Z
    3. 这是正确的答案!问题本身与浮点数如何在内部工作有关,而不是与javascript
      有关
      2017-05-24 15:26:04Z
    4. 实际上,你必须在乘以100之前添加epsilon。Math.round( (num + Number.EPSILON) * 100) / 100。我也同意这是正确舍入的正确方法(虽然这不是这个问题中的问题)。
      2017-11-05 15:30:37Z
    5. - 1; 为什么我应该使用这种任意咒语?它会做什么?它的结果与其他答案有何不同?为什么Number.EPSILON是有用的或相关的价值?坦率地说,这个答案是错误的,荒谬的;在大多数情况下,添加Number.EPSILON不会改变结果,但在唯一的情况下我可以构造它有效的地方,其中num是0.004999999999999999,它使结果直接错误,导致num到当它被正确舍入为0时,舍入为0.01。
      2017-12-06 22:01:37Z
    6. 醇>

    这是一种简单的方法:

     
    Math.round(value * 100) / 100
    

    你可能希望继续为你做一个单独的功能:

     
    function roundToTwo(value) {
        return(Math.round(value * 100) / 100);
    }
    

    然后你只需传入值。

    您可以通过添加第二个参数来增强它以舍入到任意数量的小数。

     
    function myRound(value, places) {
        var multiplier = Math.pow(10, places);
    
        return (Math.round(value * multiplier) / multiplier);
    }
    
        
    45
    2013-06-05 12:25:44Z
    1. 此解决方案有误,请参阅 stackoverflow.com/questions/38322372 /... 如果输入156893.145并使用上述函数将其舍入,则得到156893.14而不是156893.15 !!!
      2016-07-14 09:48:14Z
    2. @ saimiris_devel,你已经设法找到一个实例,其中JavaScript f中数字的数字表示苦恼的。你说错了是正确的。但是 - 这是因为你的样本数乘以100已经被打破(15689314.499999998)。实际上,一个功能齐全的答案需要一个专门开发的库来考虑JavaScript处理实数的不一致性。否则,您可能会使给出此问题的任何答案无效。
      2018-11-10 23:39:29Z
    3. 醇>
     
    +(10).toFixed(2); // = 10
    +(10.12345).toFixed(2); // = 10.12
    
    (10).toFixed(2); // = 10.00
    (10.12345).toFixed(2); // = 10.12
    
        
    36
    2014-06-25 10:27:07Z
    1. 如果您使用数字的字符串表示并对其进行舍入,则不会总是得到相同的结果。例如,+(0.015).toFixed(2) == 0.01
      2016-07-30 17:17:08Z
    2. 醇>

    对我而言 Math.round()没有给出正确答案。我发现 toFixed(2)的作品更好。 以下是两者的示例:

     
    console.log(Math.round(43000 / 80000) * 100); // wrong answer
    
    console.log(((43000 / 80000) * 100).toFixed(2)); // correct answer
        
    36
    2018-05-24 00:32:34Z
    1. 重要的是要注意toFixed不执行舍入,并且Math.round只舍入到最接近的整数。因此,为了保留小数,我们需要将原始数乘以10的幂数,其中零的小数表示所需的小数位数,然后将结果除以相同的数字。在你的情况下:Math.round(43000/80000 * 100 * 100)/100.最后可以应用固定(2)以确保结果中总有两个小数(在需要的地方有尾随零) - 完美右对齐垂直呈现的一系列数字:)
      2018-05-01 14:26:35Z
    2. 另外要注意的是.toFIxed()输出一个字符串,而不是一个数字。
      2018-06-26 16:19:23Z
    3. 这仍然无法解决1.005的舍入问题。 (1.005).toFixed(2)仍然是1.00
      2018-10-26 15:46:11Z
    4. 醇>

    2017,点击 只需使用本机代码.toFixed()

     
    number = 1.2345;
    number.toFixed(2) // "1.23"
    

    如果您需要严格并在需要时添加数字,则可以使用replace

     
    number = 1; // "1"
    number.toFixed(5).replace(/\.?0*$/g,'');
    
        
    33
    2017-12-17 09:56:22Z
    1. toFixed方法返回一个字符串。如果你想要一个数字结果,你需要将toFixed的结果发送到parseFloat。
      2017-11-07 20:04:24Z
    2. @ Zambonilli如果有必要,可以乘以1。但是因为固定数字大多数情况是用于显示而不是用于计算字符串是正确的格式
      2017-11-08 13:05:43Z
    3. - 1;不仅在你之前多年答案提出了toFixed,而且它不能满足问题中“只在必要时”的条件; (1).toFixed(2)给出了"1.00",其中提问者需要"1"
      2017-12-07 00:02:49Z
    4. 好了。我也为该案例添加了一些解决方案
      2017-12-14 17:05:28Z
    5. 如果您正在使用lodash,那就更容易了:_.round(number,decimalPlace)删除了我的上一条评论,因为它有问题。但是,Lodash _.round可以工作。 1.005,小数位为2,转换为1.01。
      2018-07-31 17:40:59Z
    6. 醇>

    使用此功能Number(x).toFixed(2);

        
    33
    2018-12-10 13:00:10Z
    1. 再次将它全部包装在Number中,如果你不希望它以字符串形式返回:Number(Number(x).toFixed(2));
      2015-09-12 05:17:22Z
    2. Number调用不是必需的,x.toFixed(2)可以正常工作。
      2018-12-14 16:09:36Z
    3. @ bgusach需要调用数字,因为语句x.toFixed(2)返回字符串而不是数字。要再次转换为数字,我们需要使用Number
      进行换行
      2019-03-15 06:26:59Z
    4. 使用此方法时,(1).toFixed(2)返回1.00,但在这种情况下提问者需要1
      2019-06-07 20:40:40Z
    5. 醇>

    尝试轻量级解决方案:

     
    function round(x, digits){
      return parseFloat(x.toFixed(digits))
    }
    
     round(1.222,  2) ;
     // 1.22
     round(1.222, 10) ;
     // 1.222
    
        
    31
    2014-10-20 10:21:12Z
    1. 任何人都知道这和return Number(x.toFixed(digits))之间有什么区别吗?
      2015-09-12 05:16:08Z
    2. @ JoeRocc ...应该没有任何区别,因为.toFixed()只允许数字反正。
      2015-09-12 10:16:25Z
    3. 此答案与此页面上多次提到的问题相同。尝试round(1.005, 2)并查看1而不是1.01的结果。
      2016-08-05 06:54:53Z
    4. 似乎更像是舍入算法的问题? - 不止一个人会想象: en.wikipedia.org/wiki/Rounding .. round(0.995, 2) => 0.99; round(1.006, 2) => 1.01; round(1.005, 2) => 1
      2018-02-07 05:35:17Z
    5. 醇>

    有几种方法可以做到这一点。像我这样的人,Lodash的变种

     
    function round(number, precision) {
        var pair = (number + 'e').split('e')
        var value = Math.round(pair[0] + 'e' + (+pair[1] + precision))
        pair = (value + 'e').split('e')
        return +(pair[0] + 'e' + (+pair[1] - precision))
    }
    

    用法:强>

     
    round(0.015, 2) // 0.02
    round(1.005, 2) // 1.01
    

    如果你的项目使用jQuery或lodash,你也可以在库中找到合适的round方法。

    更新1

    我删除了变体n.toFixed(2),因为它不正确。谢谢@ avalanche1

        
    28
    2017-06-22 13:48:11Z
    1. 第二个选项将返回一个正好有两个小数点的字符串。该问题仅在必要时才会要求小数点。在这种情况下,第一个选项更好。
      2016-07-05 13:36:31Z
    2. @ MarcosLima Number.toFixed()将返回一个字符串,但前面带有加号,JS解释器将字符串转换为数字。这是一种语法糖。
      2016-07-05 14:04:45Z
    3. 在Firefox上,alert((+1234).toFixed(2))显示“1234.00”。
      2016-07-05 14:11:54Z
    4. 在Firefox上,alert(+1234.toFixed(2))抛出SyntaxError: identifier starts immediately after numeric literal。我坚持使用第一个选项。
      2016-07-05 15:19:06Z
    5. 所有变体都为0.015
      提供了错误的解决方案
      2017-01-25 12:37:40Z
    6. 醇>

    MarkG和Lavamantis提供了一个比被接受的解决方案更好的解决方案。很遗憾他们没有得到更多的赞成!

    这是我用来解决浮点小数问题的函数也基于MDN 。它比Lavamantis的解决方案更通用(但不那么简洁):

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

    将其用于:

     
    round(10.8034, 2);      // Returns 10.8
    round(1.275, 2);        // Returns 1.28
    round(1.27499, 2);      // Returns 1.27
    round(1.2345678e+2, 2); // Returns 123.46
    

    与Lavamantis的解决方案相比,我们可以做到......

     
    round(1234.5678, -2); // Returns 1200
    round("123.45");      // Returns 123
    
        
    22
    2014-01-24 15:44:06Z
    1. 您的解决方案不包括某些情况,而不是MDN的解决方案。虽然它可能更短,但不准确......
      2015-07-05 21:42:55Z
    2. round(-1835.665,2)=&gt; -1835.66
      2016-07-29 01:38:35Z
    3. 醇>

    如果您使用的是lodash库,则可以使用lodash的圆形方法,如下所示。

     
    _.round(number, precision)
    

    例如:

     
    _.round(1.7777777, 2) = 1.78
    
        
    20
    2017-07-28 06:59:19Z
    1. @ Peter与标准Javascript相比,Lodash提供的功能组合非常好。但是,我听说Lodash与标准JS相比有一些性能问题。 codeburst.io /...
      2018-10-04 08:26:31Z
    2. 我接受你的观点,即使用lodash存在性能缺陷。我认为这些问题在许多抽象中都很常见。但是看看这个帖子上有多少答案以及直观解决方案如何在边缘情况下失败。我们已经看到了jQuery的这种模式,当浏览器采用一种解决了我们大多数用例的通用标准时,根问题就解决了。然后将性能瓶颈转移到浏览器引擎。我认为同样应该发生在lodash。 :)
      2018-10-04 10:17:31Z
    3. 醇>

    这可能会对您有所帮助:

     
    var result = (Math.round(input*100)/100);
    

    了解更多信息,您可以查看此链接

    Math.round(num)vs num。 toFixed(0)和浏览器不一致

        
    18
    2017-05-23 11:55:00Z
     
    var roundUpto = function(number, upto){
        return Number(number.toFixed(upto));
    }
    roundUpto(0.1464676, 2);
    

    toFixed(2)这里2是我们想要对这个数字进行舍入的数字。

        
    16
    2015-06-02 07:15:38Z
    1. 这个.toFixed()实现起来更简单。只需经过一次。
      2015-05-15 07:19:20Z
    2. 醇>

    它可能适合你,

     
    Math.round(num * 100)/100;
    

    知道toFixed和round之间的区别。您可以查看 Math.round (num)vs num.toFixed(0)和浏览器不一致

        
    14
    2017-05-26 19:36:50Z

    由于ES6有一种“正确”的方式(没有覆盖静态和创建变通方法),所以使用toPrecision

     
    var x = 1.49999999999;
    console.log(x.toPrecision(4));
    console.log(x.toPrecision(3));
    console.log(x.toPrecision(2));
    
    var y = Math.PI;
    console.log(y.toPrecision(6));
    console.log(y.toPrecision(5));
    console.log(y.toPrecision(4));
    
    var z = 222.987654
    console.log(z.toPrecision(6));
    console.log(z.toPrecision(5));
    console.log(z.toPrecision(4));

    然后你可以只有parseFloat而且零会“消失”。

     
    console.log(parseFloat((1.4999).toPrecision(3)));
    console.log(parseFloat((1.005).toPrecision(3)));
    console.log(parseFloat((1.0051).toPrecision(3)));
        
    14
    2019-06-08 04:59:59Z
    1. (1.005).toPrecision(3)仍然返回1.00而不是1.01
      2018-02-23 22:21:07Z
    2. toPrecision返回一个更改所需输出类型的字符串。
      2018-11-16 22:59:49Z
    3. @ Giacomo这不是.toPrecision方法的缺陷,它是浮点数的特异性(JS中的数字是) - 尝试1.005 - 0.005,它将返回0.9999999999999999
      2018-11-26 01:44:24Z
    4. (1).toPrecision(3)返回'1.00',但是在这种情况下提问者想要1
      2019-06-07 20:39:31Z
    5. 对于没有小数的较大数字,这也可能无法满足大多数人的需要 - 例如144.它将四舍五入为140.
      2019-06-28 17:19:14Z
    6. 醇>

    最简单的方法:

    +num.toFixed(2)

    它将它转换为字符串,然后再转换为整数/浮点数。

        
    13
    2015-02-25 20:09:30Z
    1. 感谢您提供这个最简单的答案。但是,+ num中的'+'是什么?它对我来说不起作用,其中十进制val以字符串形式出现。我做了:(num * 1).toFixed(2)。
      2015-03-22 08:21:20Z
    2. 2015-04-28 15:59:04Z
    3. @ momo只是将参数更改为toFixed()到3.所以它将是+num.toFixed(3)。这是按照预期的方式工作,1.005舍入为1.00,等于1
      2015-05-04 16:13:56Z
    4. @ Edmund它应该返回1.01,而不是1.00
      2015-05-05 19:20:36Z
    5. 醇>

    使用类似的东西 “parseFloat(parseFloat(value).toFixed(2))”

     
    parseFloat(parseFloat("1.7777777").toFixed(2))-->1.78 
    parseFloat(parseFloat("10").toFixed(2))-->10 
    parseFloat(parseFloat("9.1").toFixed(2))-->9.1
    
        
    13
    2018-03-26 08:26:56Z
    1. 这是此页面中唯一正确的答案。
      2018-07-09 14:08:42Z
    2. 如果不准确性是浮动表示的内在因素,则不行。你只是删除它,然后通过再次转换回浮动重新引入相同的错误!
      2018-10-28 20:00:32Z
    3. 醇>

    这是一个原型方法:

     
    Number.prototype.round = function(places){
        places = Math.pow(10, places); 
        return Math.round(this * places)/places;
    }
    
    var yournum = 10.55555;
    yournum = yournum.round(2);
    
        
    12
    2017-05-26 19:43:00Z

    通常,通过缩放来完成舍入:round(num / p) * p

    使用指数表示法正确处理+ ve数字的舍入。 但是,此方法无法正确舍入边缘情况。

     
    function round(num, precision = 2) {
    	var scaled = Math.round(num + "e" + precision);
    	return Number(scaled + "e" + -precision);
    }
    
    // testing some edge cases
    console.log( round(1.005, 2) );  // 1.01 correct
    console.log( round(2.175, 2) );  // 2.18 correct
    console.log( round(5.015, 2) );  // 5.02 correct
    
    console.log( round(-1.005, 2) );  // -1    wrong
    console.log( round(-2.175, 2) );  // -2.17 wrong
    console.log( round(-5.015, 2) );  // -5.01 wrong

    这里也是我写的一个函数正确地进行算术舍入。你可以自己测试一下。

     
    /**
     * MidpointRounding away from zero ('arithmetic' rounding)
     * Uses a half-epsilon for correction. (This offsets IEEE-754
     * half-to-even rounding that was applied at the edge cases).
     */
    
    function RoundCorrect(num, precision = 2) {
    	// half epsilon to correct edge cases.
    	var c = 0.5 * Number.EPSILON * num;
    //	var p = Math.pow(10, precision); //slow
    	var p = 1; while (precision--> 0) p *= 10;
    	if (num < 0)
    		p *= -1;
    	return Math.round((num + c) * p) / p;
    }
    
    // testing some edge cases
    console.log(RoundCorrect(1.005, 2));  // 1.01 correct
    console.log(RoundCorrect(2.175, 2));  // 2.18 correct
    console.log(RoundCorrect(5.015, 2));  // 5.02 correct
    
    console.log(RoundCorrect(-1.005, 2));  // -1.01 correct
    console.log(RoundCorrect(-2.175, 2));  // -2.18 correct
    console.log(RoundCorrect(-5.015, 2));  // -5.02 correct
        
    11
    2018-02-13 10:23:22Z

    要不处理多个0,请使用以下变体:

     
    Math.round(num * 1e2) / 1e2
    
        
    10
    2013-10-11 15:21:39Z

    如果你碰巧已经在使用d3库,他们就有一个强大的数字格式库: https://github。 COM /mbostock /D3 /维基/格式化

    特此舍入在这里:​​ https://github.com/mbostock/d3/wiki/Formatting#d3_round

    在您的情况下,答案是:

     
    > d3.round(1.777777, 2)
    1.78
    > d3.round(1.7, 2)
    1.7
    > d3.round(1, 2)
    1
    
        
    9
    2014-06-18 13:35:04Z
    1. 查看来源,这只不过是@ustasb答案的通用版本,使用num * Math.pow(n)而不是num * 100(但它绝对是一个整齐的单行; - )
      2014-06-18 14:23:13Z
    2. 但是记录在案,并且,在库中,我不需要检查浏览器兼容性BS。
      2014-06-19 18:11:20Z
    3. 使用Math.pow(n)允许d3.round(12,-1)== 10
      2014-08-05 09:25:53Z
    4. 醇>

    仅在必要时实现这种舍入的一种方法是使用 Number.prototype.toLocaleString()

     
    myNumber.toLocaleString('en', {maximumFractionDigits:2, useGrouping:false})
    

    氏s将提供您期望的输出,但作为字符串。如果这不是您期望的数据类型,您仍然可以将它们转换回数字。

        
    9
    2017-02-22 21:32:54Z
    1. 这是迄今为止最干净的解决方案,并回避了所有复杂的浮点问题,但每个MDN 支持仍然不完整 - Safari不支持将参数传递给toLocaleString
      2016-07-30 23:12:09Z
    2. 醇>
来源放置 这里