我想最多四舍五入两位小数,但只有在必要时。

输入:

10
1.7777777
9.1

输出:

10
1.78
9.1

如何在JavaScript中执行此操作?


当前回答

您应该使用:

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

似乎没有人知道数字EPSILON。

此外,值得注意的是,这并不像某些人所说的那样是JavaScript的怪异之处。

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

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

编辑:

正如评论中所问的,让我们澄清一件事:添加Number.EPSILON仅当要舍入的值是算术运算的结果时才相关,因为它可以吞下一些浮点误差增量。

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

编辑(2019):

像@maganap和一些人指出的那样,最好在相乘之前加上Number.EPSILON:

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

编辑(2019年12月):

最近,我使用了一个类似于此的函数来比较epsilon感知的数字:

const ESPILON_RATE = 1 + Number.EPSILON ;
const ESPILON_ZERO = Number.MIN_VALUE ;

function epsilonEquals( a , b ) {
  if ( Number.isNaN( a ) || Number.isNaN( b ) ) {
    return false ;
  }
  if ( a === 0 || b === 0 ) {
    return a <= b + EPSILON_ZERO && b <= a + EPSILON_ZERO ;
  }
  return a <= b * EPSILON_RATE && b <= a * EPSILON_RATE ;
}

我的用例是我多年来开发的断言+数据验证库。

事实上,在代码中,我使用的是ESPILON_RATE=1+4*数字.EPSILON和EPSILON_ZERO=4*数字.MIN_VALUE(四倍于EPSILON),因为我想要一个足够宽松的等式检查器来累积浮点错误。

到目前为止,它看起来很适合我。我希望这会有所帮助。

其他回答

parseFloat(“1.555”).toFixed(2);//返回1.55而不是1.56。

1.55是绝对正确的结果,因为在计算机中不存在1.555的精确表示。如果读数为1.555,则四舍五入至最接近的值=1.55499999999999994(64位浮点)。将这个数字四舍五入到Fixed(2)得到1.55。

如果输入为1.55499999999999,则此处提供的所有其他功能都会给出故障结果。

解决方案:在扫描前加上数字“5”,将数字舍入(更准确地说,从0开始舍入)。仅当数字真的是浮点(有小数点)时才执行此操作。

parseFloat("1.555"+"5").toFixed(2); // Returns 1.56

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

与拉瓦曼蒂斯的解决方案相比,我们可以做到。。。

round(1234.5678, -2); // Returns 1200
round("123.45");      // Returns 123

只有在必要时才能实现这种舍入的一种方法是使用Number.protype.toLocaleString():

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

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

对我来说,Math.rround()没有给出正确的答案。我发现Fixed(2)效果更好。以下是两者的示例:

console.log(数学舍入(43000/80000)*100);//错误的答案console.log(((43000/80000)*100).toFixed(2));//正确回答

如果使用的是Lodash库,可以使用Lodash的舍入方法,如下所示。

_.round(number, precision)

例如:

_.round(1.7777777, 2) = 1.78