如何将数字保留两位小数(如果必要)

4114

我希望最多保留两位小数,但只有必要时才这样做。

输入:

10
1.7777777
9.1

输出:

10
1.78
9.1

我该如何在JavaScript中实现这个?


1
const formattedNumber = Math.round(myNumber * 100) / 100; 将数字乘以100,然后四舍五入保留两位小数。 - Hamza Dahmoun
const formattedNumber = new Intl.NumberFormat('en', { minimumFractionDigits: 2, maximumFractionDigits: 2 }).format(myNumber); const formattedNumberInNumber = parseFloat(formattedNumber);``` // #=> 1.28。[更多信息](https://dev59.com/anI-5IYBdhLWcg3wsKl4#1726662) - tinystone
92个回答

66

一个精确的四舍五入方法。来源: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

66

这里找到的答案都不正确stinkycheeseman提问 要求向上取整,但你们所有人都将数字四舍五入了。

要向上取整,请使用以下方法:

Math.ceil(num * 100)/100;

1.3549999999999998会返回错误的结果。应该是1.35,但结果是1.36。 - A Kunin
2
大多数值将返回不正确的结果。试试看。 - user207421
1
如果你想在第二位小数总是向上取整(我相信这是 OP 想要的),我会说 1.36 实际上是正确答案。 - Simon Green

39

4
为什么这个回答和被接受的回答几乎是一样的,但是它却比这个回答早1分钟发布,而且被接受的回答比这个回答得到更多的投票? - DUO Labs
2
Math.round(1.965 * 100) / 100 的结果是1.96,这是错误的。 - Kamlesh
它们在创建时大致相同。被接受的答案的第一个实质性编辑是在2020年进行的,而这个答案在发布后9分钟内被编辑以包含额外信息。因此,如果这个答案在创建时是错误的,那么被接受的答案在接下来的8年中也是错误的。 - Chris Strickland

38
如果您正在使用Lodash库,您可以像以下这样使用Lodash的round方法。
_.round(number, precision)

例如:

_.round(1.7777777, 2) = 1.78

@Peter Lodash 提供的功能集与标准 JavaScript 相比确实非常出色。但是,我听说 Lodash 在性能方面与标准 JS 相比存在一些问题。 https://codeburst.io/why-you-shouldnt-use-lodash-anymore-and-use-pure-javascript-instead-c397df51a66 - Madura Pradeep
2
我接受你的观点,使用lodash会有性能缺陷。我认为这些问题在许多抽象中都很常见。但是看看这个线程上有多少答案以及直觉解决方案如何失败于边缘情况。我们已经在jQuery中看到了这种模式,当浏览器采用解决大多数用例的共同标准时,根本问题得到了解决。性能瓶颈随后移至浏览器引擎。我认为lodash也应该发生同样的事情。 :) - Peter

37

使用这个函数Number(x).toFixed(2);


9
如果您不想返回一个字符串,请将所有内容再次包装在Number中:Number(Number(x).toFixed(2)); - user993683
5
Number 的调用是不必要的,x.toFixed(2) 就可以了。 - bgusach
3
需要调用Number函数,因为语句x.toFixed(2)返回的是字符串而不是数字。要再次转换为数字,我们需要将其包装在Number函数中。 - Mohan Ram
2
使用这种方法时,(1).toFixed(2) 返回的是 1.00,但是在这种情况下提问者需要的是 1 - Eugene Mala
2
这个不行,1.005.toFixed(2)得到的结果是"1" ,但它应该是"1.01" - Adam Jagosz
1
这是user3711536的答案的副本,同样没有任何解释。至少另一个答案有一些示例输入和输出。 - Peter Mortensen

37

对我来说,Math.round() 没有给出正确��答案。我发现使用 toFixed(2) 更好。 以下是两者的示例:

console.log(Math.round(43000 / 80000) * 100); // wrong answer

console.log(((43000 / 80000) * 100).toFixed(2)); // correct answer


值得注意的是,toFixed 不执行舍入操作,Math.round 只是将数字四舍五入为最接近的整数。为了保留小数点,我们因此需要将原始数字乘以表示所需小数点的零数量的十的幂次数,然后将结果除以相同的数字。在你的情况下: Math.round(43000 / 80000 * 100 * 100) / 100。最后 toFixed(2) 可以应用于确保结果始终有两个小数位(在需要时带有尾随零)-非常适合垂直呈现一系列数字时的右对齐 :) - Turbo

36
+(10).toFixed(2); // = 10
+(10.12345).toFixed(2); // = 10.12

(10).toFixed(2); // = 10.00
(10.12345).toFixed(2); // = 10.12

需要解释一下。例如,这个想法/主旨是什么?为什么只有toFixed()?它来自于特定的库吗?JavaScript的哪个版本/何时引入的?根据帮助中心的说法:“...始终要解释为什么你提出的解决方案是合适的以及它是如何工作的”。请通过编辑(更改)您的答案进行回复,而不是在评论中回复(不要使用“编辑:”、“更新:”或类似的字眼 - 答案应该看起来像是今天写的)。 - Peter Mortensen
好的,OP已经离开了。也许其他人可以加入讨论? - Peter Mortensen

35

试用这个轻巧的解决方案:

function round(x, digits){
  return parseFloat(x.toFixed(digits))
}

 round(1.222,  2);
 // 1.22
 round(1.222, 10);
 // 1.222

有人知道这个和 return Number(x.toFixed(digits)) 之间有什么区别吗? - user993683
1
@JoeRocc... 就我所看到的,这应该没有任何影响,因为 .toFixed() 只允许使用数字。 - petermeissner
4
这个答案和本页面上多次提到的问题一样。尝试使用round(1.005,2)并查看结果为1而不是1.01 - MilConDoin
似乎更像是舍入算法的问题?- 实际上比人们想象的还要多:https://en.wikipedia.org/wiki/Rounding ... round(0.995, 2) => 0.99; round(1.006, 2) => 1.01 ; round(1.005, 2) => 1 - petermeissner
这个方法可以运行,但是它增加了系统的不必要的复杂性,因为它将一个浮点数转换成字符串,然后再将字符串解析回浮点数。 - racribeiro

33

有几种方法可以做到这一点。对于像我这样的人,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方法。


第二个选项会返回一个带有两位小数的字符串。如果必要,问题只要求小数点即可。在这种情况下,第一个选项更好。 - Marcos Lima
@MarcosLima Number.toFixed() 会返回一个带加号的字符串,但是JS解释器会将该字符串转换为数字。这是一种语法糖。 - stanleyxu2005
在Firefox上,alert((+1234).toFixed(2))会显示"1234.00"。 - Marcos Lima
在Firefox上,alert(+1234.toFixed(2))会抛出SyntaxError: identifier starts immediately after numeric literal的错误。我选择第一种选项。 - Marcos Lima
在某些边缘情况下,这不起作用:尝试使用362.42499999999995jsfiddle)。期望结果(如PHP中的echo round(362.42499999999995, 2)):362.43。实际结果:362.42 - Dr. Gianluigi Zane Zanettini
@Dr.GianluigiZaneZanettini 忘记任何编程语言。如果您手动进行四舍五入,您认为哪个结果是正确的,362.42还是362.43?我在PHP中进行了一些测试,我认为这是PHP浮点数精度问题。如果您运行echo(362.42499999999995);,您将获得362.425,并且PHP使用此数字进行2位小数的四舍五入,它返回362.43。我认为这是一个PHP问题,而不是数学问题。 - stanleyxu2005

32

2017年
只需使用原生代码.toFixed()

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

如果您需要严格控制并仅在必要时添加数字,可以使用 replace 函数。

number = 1; // "1"
number.toFixed(5).replace(/\.?0*$/g,'');

4
toFixed 方法返回一个字符串。如果你想得到一个数字结果,需要将 toFixed 的结果发送到 parseFloat 函数中。 - Zambonilli
1
@Zambonilli 如果必要的话,可以直接乘以1。但因为固定数字大多数情况是用于显示而非计算,所以字符串是正确的格式。 - pery mimon
3
不仅在你之前的多个回答中建议使用toFixed,而且它不符合问题中"必要时才执行"的条件;(1).toFixed(2)的结果为"1.00",而问题提出者希望得到"1" - Mark Amery
好的,我明白了。我也为那种情况添加了一些解决方案。 - pery mimon
如果您正在使用lodash,那么这将更加容易:_.round(number, decimalPlace)。删除了我的上一个评论,因为它有问题。但是Lodash _.round确实有效。带有2位小数的1.005转换为1.01。 - Devin Fields
但是1.005应该四舍五入为1.01。这是四舍五入的规则。 - pery mimon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接