如何在 JavaScript 中格式化浮点数?

495
在JavaScript中,将浮点数转换为字符串时,如何仅获取小数点后两位?例如,获取0.34而不是0.3445434。

21
您希望将所有数字除了前两位都去掉,还是想要四舍五入到两位小数? - xtofl
15个回答

957
有用于四舍五入数字的函数,例如:
var x = 5.0364342423;
print(x.toFixed(2));

将打印出5.04。

编辑: Fiddle


11
我建议不要在浏览器中使用print()函数。 - cobbal
87
注意,toFixed()返回一个字符串: var x = 5.036432346; var y = x.toFixed(2) + 100; y将等于"5.03100" - Vlad
5
请注意,(1e100).toFixed(2) === "1e+100"。 - qbolec
9
同时要注意保持一致的四舍五入方式:(0.335).toFixed(2) == 0.34 == (0.345).toFixed(2)... - Skippy le Grand Gourou
7
如果你正在寻找一个具有一致舍入的 toFixed 等效函数,可以使用 toLocaleString: (0.345).toLocaleString('en-EN',{minimumFractionDigits:2, maximumFractionDigits:2})。 - fred727
显示剩余3条评论

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

具体细节,以防代码不够自解释。

编辑:...或者像Tim Büthe所建议的那样,直接使用toFixed。忘记这个了,感谢提醒(并点赞):)


1
我在使用“Highchart”库时遇到了问题,因为它不接受字符串值,所以toFixed对我无效。Math.round解决了我的问题,谢谢。 - Swapnil Chincholkar
6
toFixed()会模仿C语言中的printf()函数。然而,toFixed()Math.round()会以不同的方式处理四舍五入。在这种情况下,如果你事先将原始数字乘以10^n,然后使用n个数字调用toFixed(),那么toFixed()将具有与Math.floor()相同的效果。答案的“正确性”非常依赖于OP在这里想要什么,两者在其自己的方式上都是“正确”的。 - DDPWNAGE
2
这里提出的方法不是一个好方法,因为它可能会导致意外的值,比如4.99999999998等,这是由于二进制基数的工作方式造成的。请改用toFixed。 - Karveiani

196

使用toFixed()时要小心:

首先,四舍五入是使用数字的二进制表示来完成的,这可能会导致意外行为。例如:

(0.595).toFixed(2) === '0.59'

使用'0.6'替代。

其次,toFixed()在IE中存在一个bug。在IE(至少到版本7,没有检查IE8),以下内容是正确的:

(0.9).toFixed(0) === '0'

你可以考虑采纳kkyy的建议或使用自定义的toFixed()函数,例如:

function toFixed(value, precision) {
    var power = Math.pow(10, precision || 0);
    return String(Math.round(value * power) / power);
}

13
我建议在返回值中添加本地的.toFixed()方法,这将增加所需的精度,例如:return (Math.round(value * power) / power).toFixed(precision);,并将值作为字符串返回。否则,对于较小的小数,精度20会被忽略。 - William Joss Crowcroft
3
关于 toFixed 的一个注意事项:请注意,增加精度可能会产生意外的结果:(1.2).toFixed(16) === "1.2000000000000000",而 (1.2).toFixed(17) === "1.19999999999999996"(在 Firefox/Chrome 中;在 IE8 中,由于 IE8 内部可以提供较低的精度,后者不成立)。 - jakub.g
这似乎在Chrome、Safari或Node中无法工作。toFixed(1.5, 2)的结果是"1.5"。 - Matt
2
请注意,即使(0.598).toFixed(2)也不会产生0.6,它会产生0.60 :) - qbolec
1
此外,要注意不一致的四舍五入:(0.335).toFixed(2) == 0.34 == (0.345).toFixed(2) - Skippy le Grand Gourou
显示剩余2条评论

50

还需要注意的一个问题是,toFixed()方法可能会在数字结尾处产生不必要的零。

var x=(23-7.37)
x
15.629999999999999
x.toFixed(6)
"15.630000"

这个想法是使用 RegExp 来清理输出:

function humanize(x){
  return x.toFixed(6).replace(/\.?0*$/,'');
}

RegExp 匹配尾部的零(以及可选的小数点),以确保整数看起来合适。

humanize(23-7.37)
"15.63"
humanize(1200)
"1200"
humanize(1200.03)
"1200.03"
humanize(3/4)
"0.75"
humanize(4/3)
"1.333333"

Number.prototype.minFixed = function(decimals) { return this.toFixed(decimals).replace(/.?0*$/, ""); }数字原型。minFixed = 函数(小数) {     返回此.toFixed(小数)。替换(/ \。?0 * $ /,“”); } - Luc Bloom
这应该被接受,尾随零很烦人,我正好在寻找这个解决方案,干得好。 - exoslav
3
尾随的零可能很烦人,但这正是方法名“toFixed”承诺要做的事情 ;) - ksadowski

12
var x = 0.3445434
x = Math.round (x*100) / 100 // this will make nice rounding

Math.round(1.015 * 100) / 100 的结果是 1.01,但我们期望它应该是 1.02? - gaurav5430
console.log(Math.round((1.015 + 0.00001) * 100) / 100) // 1.02 这将解决上述情况。 - Monish N

9

这里的关键是正确地四舍五入,然后再将其转换为字符串。

function roundOf(n, p) {
    const n1 = n * Math.pow(10, p + 1);
    const n2 = Math.floor(n1 / 10);
    if (n1 >= (n2 * 10 + 5)) {
        return (n2 + 1) / Math.pow(10, p);
    }
    return n2 / Math.pow(10, p);
}

// All edge cases listed in this thread
roundOf(95.345, 2); // 95.35
roundOf(95.344, 2); // 95.34
roundOf(5.0364342423, 2); // 5.04
roundOf(0.595, 2); // 0.60
roundOf(0.335, 2); // 0.34
roundOf(0.345, 2); // 0.35
roundOf(551.175, 2); // 551.18
roundOf(0.3445434, 2); // 0.34

现在您可以使用toFixed(p)安全地格式化此值。针对您的具体情况,可以这样操作:
roundOf(0.3445434, 2).toFixed(2); // 0.34

.toFixed(2) 将数字转换为字符串,并四舍五入保留两位小数。 - Dan Alboteanu

6

使用乘数的所有解决方案都存在问题。很遗憾,kkyy和Christoph的解决方案都是错误的。

请针对数字551.175进行测试,并保留2位小数——它会四舍五入为551.17,但应该是551.18!但是,如果您测试的是451.175等数字,则没有问题——451.18。因此,这个错误很难一眼就发现。

问题出在乘法上:尝试 551.175 * 100 = 55117.49999999999 (哎呀!)

所以我的想法是,在使用Math.round()之前使用toFixed()来处理它。

function roundFix(number, precision)
{
    var multi = Math.pow(10, precision);
    return Math.round( (number * multi).toFixed(precision + 1) ) / multi;
}

2
这就是js中算术运算的问题:(551.175 * 10 * 10) !== (551.175 * 100)。你必须使用小数增量来移动逗号以获取非实际小数结果。 - Kir Kanos
+1 感谢您注意到这一点,但 toFixed 也受到影响 - (0.335).toFixed(2) == 0.34 == (0.345).toFixed(2)... 无论使用哪种方法,在舍入之前最好添加一个 epsilon。 - Skippy le Grand Gourou

4

如果您想要不带括号的字符串,可以使用以下正则表达式(可能不是最有效的方法...但非常简单)

(2.34567778).toString().match(/\d+\.\d{2}/)[0]
// '2.34'

3
另一种可能是使用 toLocaleString() 函数:

toLocaleString() 方法返回一个具有语言敏感性的该数字的字符串表示。

const n = 2048.345;
const str = n.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2});
console.log(str);


2
function trimNumber(num, len) {
  const modulu_one = 1;
  const start_numbers_float=2;
  var int_part = Math.trunc(num);
  var float_part = String(num % modulu_one);
      float_part = float_part.slice(start_numbers_float, start_numbers_float+len);
  return int_part+'.'+float_part;
}

非常好的回答,除了您缺少分号(不,在es6中分号并未过时,我们仍然需要在某些情况下使用它们)。我还需要编辑最后一行为:return float_part ? int_part+'.'+float_part : int_part;,否则如果输入整数,则返回带有结束符号的数字(例如输入:“2100”,输出:“2100.”)。 - Kuba Šimonovský

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