在 JavaScript 中使用两位小数格式化数字

IT技术 javascript rounding decimal-point
2021-01-09 00:44:02

我有这行代码将我的数字四舍五入到两位小数。但我得到这样的数字:10.8、2.4 等。这些不是我对两位小数的想法,所以我如何改进以下内容?

Math.round(price*Math.pow(10,2))/Math.pow(10,2);

我想要 10.80、2.40 等数字。使用 jQuery 对我来说很好。

6个回答

要使用定点表示法格式化数字,您可以简单地使用toFixed方法:

(10.8).toFixed(2); // "10.80"

var num = 2.4;
alert(num.toFixed(2)); // "2.40"

请注意,toFixed()返回一个字符串。

重要提示:请注意,toFixed 在 90% 的情况下不会四舍五入,它将返回四舍五入的值,但在许多情况下,它不起作用。

例如:

2.005.toFixed(2) === "2.00"

更新:

如今,您可以使用Intl.NumberFormat构造函数。它是ECMAScript 国际化 API 规范(ECMA402) 的一部分。它具有非常好的浏览器支持,甚至包括 IE11,并且在 Node.js 中完全支持

const formatter = new Intl.NumberFormat('en-US', {
   minimumFractionDigits: 2,      
   maximumFractionDigits: 2,
});

console.log(formatter.format(2.005)); // "2.01"
console.log(formatter.format(1.345)); // "1.35"

您也可以使用该toLocaleString方法,该方法在内部将使用IntlAPI:

const format = (num, decimals) => num.toLocaleString('en-US', {
   minimumFractionDigits: 2,      
   maximumFractionDigits: 2,
});


console.log(format(2.005)); // "2.01"
console.log(format(1.345)); // "1.35"

此 API 还为您提供了多种格式化选项,例如千位分隔符、货币符号等。

在大多数情况下这是一个坏主意,它在某些情况下将数字转换为字符串或浮点数。
2021-03-10 00:44:02
必须在这里同意@AshBlue...这仅对于格式化值的表示是安全的。可能会因进一步计算而破坏代码。否则Math.round(value*100)/100对 2DP 效果更好。
2021-03-11 00:44:02
@rekans:这是错误的。Math.Round(0.09)会回来0所以这将永远给0.0...
2021-03-13 00:44:02
固定不圆,你可以先做:(Math.round(0.09)).toFixed(1);
2021-03-24 00:44:02
不能在所有浏览器上一致工作,即(0.09).toFixed(1);在 IE8 中给出 0.0
2021-04-01 00:44:02

这是一个古老的话题,但仍然是排名靠前的 Google 结果,并且提供的解决方案共享相同的浮点小数问题。这是我使用的(非常通用的)函数,感谢 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));
}

正如我们所见,我们没有遇到这些问题:

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

这种通用性还提供了一些很酷的东西:

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

现在,要回答 OP 的问题,必须输入:

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

或者,对于更简洁、更通用的函数:

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

您可以通过以下方式调用它:

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

各种示例和测试(感谢@tj-crowder!):

我如何使用它来获得小数点后第一位的值,例如 3.0421 应该返回 3.0?
2021-03-20 00:44:02
怎么没有一个简单的方法来做到这一点?ES6 来拯救?
2021-03-30 00:44:02
感谢您发布 MDN polyfill。在链接的 MDN 页面上,polyfill 不再存在。我想知道为什么它被删除了...
2021-04-01 00:44:02
@RIni,您应该能够使用round(3.0421, 1)以获取3数字或round(3.0421, 1).toFixed(1)获取'3.0'为字符串。
2021-04-03 00:44:02

我通常将它添加到我的个人库中,经过一些建议并使用@TIMINeutron 解决方案,然后使其适应十进制长度,这个最适合:

function precise_round(num, decimals) {
   var t = Math.pow(10, decimals);   
   return (Math.round((num * t) + (decimals>0?1:0)*(Math.sign(num) * (10 / Math.pow(100, decimals)))) / t).toFixed(decimals);
}

将适用于报告的异常。

我在 IE 中为错误签名方法添加了一个解决方法:gist.github.com/ArminVieweg/28647e735aa6efaba401
2021-03-12 00:44:02
如果你的第二个函数被选中,你在哪里声明“sign”和“dec”,它不应该将它们设为未定义?
2021-03-21 00:44:02
precision_round(1.275,2) 是 1.27?
2021-04-05 00:44:02
@Armin 你的修复也让它在 Safari 中工作。原始功能在 Safari 中不起作用。
2021-04-07 00:44:02
@Imre 将返回值更改为 (Math.round(num*Math.pow(10,decimals))/Math.pow(10,decimals)).toFixed(2); 你将不再有那个问题。
2021-04-08 00:44:02

我不知道为什么我不能在以前的答案中添加评论(也许我完全瞎了,我不知道),但我想出了一个使用@Miguel 的答案的解决方案:

function precise_round(num,decimals) {
   return Math.round(num*Math.pow(10, decimals)) / Math.pow(10, decimals);
}

以及它的两条评论(来自@bighostkim 和@Imre):

  • precise_round(1.275,2)不返回 1.28 的问题
  • precise_round(6,2)不返回 6.00 的问题(如他所愿)。

我的最终解决方案如下:

function precise_round(num,decimals) {
    var sign = num >= 0 ? 1 : -1;
    return (Math.round((num*Math.pow(10,decimals)) + (sign*0.001)) / Math.pow(10,decimals)).toFixed(decimals);
}

正如你所看到的,我不得不添加一点“更正”(它不是这样,但因为 Math.round 是有损的——你可以在 jsfiddle.net 上检查它——这是我知道如何“修复”的唯一方法“ 它)。它将 0.001 添加到已经填充的数字上,因此它在十进制值的右侧添加了一个13 0所以使用起来应该是安全的。

之后,我添加.toFixed(decimal)以始终以正确的格式输出数字(具有正确的小数位数)。

差不多就是这样。好好利用它;)

编辑:为负数的“更正”添加了功能。

实际上,语言规范对于将 64 位用于数字值非常具体,因此拥有/使用超级计算机不会改变任何事情:)
2021-03-13 00:44:02
@Imre,你说得对。这就是为什么我要解释这个 0.001 在那里做什么,以防有人想让它“更精确”甚至删除它(如果你碰巧有一台每个浮点数为 2 MB 的超级计算机,我认为这里没有人会这样做;)
2021-03-23 00:44:02
“更正”大多是安全的,但例如precise_round(1.27499,2)现在也返回 1.28 ......这不是Math.round有损;计算机内部存储浮点值的方式是。基本上,在数据到达您的函数之前,您注定会因某些值而失败:)
2021-03-30 00:44:02
对于 0.001,您可以根据小数的长度添加许多零来替换。所以..
2021-04-07 00:44:02

一种 100% 确定您得到一个带有 2 个小数的数字的方法:

(Math.round(num*100)/100).toFixed(2)

如果这会导致舍入错误,您可以使用以下内容,正如 James 在他的评论中所解释的那样:

(Math.round((num * 1000)/10)/100).toFixed(2)
这是最好的、最简单的方法。然而,由于浮点数学,1.275 * 100 = 127.49999999999999,这可能会导致四舍五入的小错误。为了解决这个问题,我们可以乘以 1000 再除以 10,即 (1.275 * 1000)/10 = 127.5。如下: var answer = (Math.round((num * 1000)/10)/100).toFixed(2);
2021-03-30 00:44:02
(Math.round((1.015 * 1000)/10)/100).toFixed(2) 仍然给出 1.01,不应该是 1.02 吗?
2021-04-07 00:44:02
(Math.round((99999999999999.9999 * 1000)/10)/100).toFixed(4) 回报 "100000000000000.0000"
2021-04-07 00:44:02