如何在不使用 toFixed() 的情况下在 JavaScript 中舍入数字

How to round a number in JavaScript without using toFixed()

提问人:Alexander Mills 提问时间:12/16/2022 最后编辑:Alexander Mills 更新时间:12/16/2022 访问量:249

问:

我正在尝试将数字四舍五入到某个小数位,预期的 API 是这样的:

const rounded = Math.round(1.6180339, 5);

const rounded = new Number(1.6180339).round(5);

但这些 API 似乎并不存在。我有这个,它似乎可以正常工作:

const [
  e,
  π,
  φ
] = [
  2.71828182845904,
  3.14159265358979,
  1.61803398874989,
];


console.log(
  Number(e.toFixed(5)) === 2.71828  // true
);

console.log(
  Number(e.toFixed(3)) === 2.718    // true
);

console.log(
  Number(e.toFixed(3)) === 2.7182   // false
);

console.log(
  Number(e.toFixed(3)) === 2.71     // false
);

这可行,但我们必须使用 toFixed() 它首先将数字转换为字符串。有没有办法在不转换为字符串的情况下直接舍入数字?

JavaScript 节点 .js 舍入 精度 为固定

评论

0赞 Diego D 12/16/2022
你可能有兴趣 developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/... 但请记住,数字是一个浮点数,并不总是适合数学
1赞 Diego D 12/16/2022
JS中的数字是一个令人头疼的问题。浮点部分是最大的。还有BigInt的原因之一 developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...
1赞 slebetman 12/16/2022
您首先需要了解浮点数的工作原理。它类似于十进制数,其中小数点后面的每个数字都比前一个数字小 1/10(即 0.123 表示 1/10 + 2/100 + 3/1000),小数点后面的每个都比前一位小 1/2。以类似的方式,你不能用十进制精确地表示 1/3,你不能用浮点格式完全表示一些十进制数。著名的是0.1不能用浮点数精确表示(必须近似为1/16 + 1/32 + 1/256 + 1/512 + 1/4096 + 1/8192 + 1/65536等)
1赞 slebetman 12/16/2022
这不是 javascript 特有的问题。这是常用 CPU 的问题。浮点数不是编程语言的特性,而是硬件的特性。有些语言实现了十进制数,而不是使用浮点格式,但这意味着你有意避免使用硬件进行数学运算。一些专业语言实际上使用基本上是字符串操作的东西来做数学运算(除了他们通常每位 4 位而不是每个数字一个字节,所以一个字节存储两个数字)......
1赞 slebetman 12/16/2022
..这种语言非常适合会计,因为它们处理数字的方式类似于人类处理数字的方式,但通常很慢。像javascript,Java,C++,Python,Ruby,Go等常见的语言使用浮点数来提高速度,并假设程序员可以在处理金钱时学习如何使用正确的算法。对于任何与金钱无关的事情,浮点数的工作方式已经足够好了。

答:

2赞 Bertrand 12/16/2022 #1

正如评论中提到的,浮点运算对于 javascript 来说可能很痛苦。无论如何,您仍然可以构建一个像这样的工具,它依靠 10 的幂来执行舍入并避免字符串转换步骤:

const Rounder = {
  floor(n, m) {
      return Math.floor(n * Math.pow(10, m)) / Math.pow(10, m);
  },
  ceil(n, m) {
      return Math.ceil(n * Math.pow(10, m)) / Math.pow(10, m);
  },
  round(n, m) {
      return Math.round(n * Math.pow(10, m)) / Math.pow(10, m);
  }
}

console.log(Rounder.ceil(7.1812828, 3));
console.log(Rounder.floor(7.1812828, 5));
console.log(Rounder.round(7.1812828, 2));
console.log(Rounder.round(0.11111111111, 8));
console.log(Rounder.ceil(0.11111111111, 8));

评论

0赞 Alexander Mills 12/16/2022
谢谢,无论好坏,我认为使用更快、更精确?测试一下可能会很好Number(x.toFixed(y))
1赞 Bertrand 12/16/2022
Math.pow 的速度似乎快得惊人。我试过 jsbench.me,Math.pow 的结果是 842,907,326 ops/s,toFixed 的结果是 3,888,108 ops/s(慢 99.54%)。此外,您可以在 toFixed 不允许的地方选择舍入行为。