Math.round(num)与num.toFixed(0)和浏览器不一致

考虑下面的代码:

for (var i=0;i<3;i++){
   var num = i + 0.50;
   var output = num + " " + Math.round(num) + " " + num.toFixed(0);
   alert(output);
}

在Opera 9.63中,我得到:

0.5 1 0

1.5 2 2

2.5 3 2

在FF 3.03中,我得到:

0.5 1 1

1.5 2 2

2.5 3 3

在IE 7中,我得到:

0.5 1 0

1.5 2 2

2.5 3 3

注意粗体结果。 为什么存在这种不一致? 这是否意味着toFixed(0)应该被避免? 将数字四舍五入到最接近的整数的正确方法是什么?


编辑:要回答您的编辑,请使用Math.round 。 如果你喜欢这种语法,你也可以原型化Number对象,让它做你的出价。

Number.prototype.round = function() {
  return Math.round(this);
}
var num = 3.5;
alert(num.round())

我之前从未使用Number.toFixed() (主要是因为大多数JS库提供了toInt()方法),但根据您的结果来判断,我会说使用Math方法( roundfloorceil )会更一致。然后toFixed如果跨浏览器一致性是你正在寻找。


我认为FF用toFixed做了正确的事情,因为下面的第10步说“如果有两个这样的n,选择较大的n”。

正如Grant Wagner所说:使用Math.ceil(x)或Math.floor(x)代替x.toFixed()。

以下全部内容来自ECMAScript语言规范:

15.7.4.5 Number.prototype.toFixed (fractionDigits)

返回一个字符串,其中包含以小数点后的fractionDigits数字表示的以定点表示法表示的数字。 如果fractionDigits未定义,则假定为0 。 具体来说,执行以下步骤:

  • fToInteger(fractionDigits) 。 (如果fractionDigits未定义,则此步骤会生成值0 )。
  • 如果f < 0f > 20 ,则引发RangeError异常。
  • x是这个数字值。
  • 如果xNaN ,则返回字符串"NaN"
  • s为空字符串。
  • 如果x ≥ 0 ,请转至步骤9。
  • 让我们成为"-"
  • x = –x
  • 如果x ≥ 10^21 ,让m = ToString(x)并转到步骤20。
  • n是一个整数,其精确的数学值n ÷ 10^f – x尽可能接近于零。 如果有两个这样的n ,选择较大的n
  • 如果n = 0 ,则让m为字符串"0" 。 否则,设m为由n的十进制表示形式的数字组成的字符串(按顺序,没有前导零)。
  • 如果f = 0 ,则转到步骤20。
  • km的字符数。
  • 如果k > f ,请转至步骤18。
  • z是由字符'0'f+1–k次出现组成的字符串。
  • m是串zm的串联。
  • k = f + 1
  • am的前k–f字符,设bm的剩余f字符。
  • m是三个字符串a"." ,和b
  • 返回字符串sm的连接。
  • toFixed方法的length属性为1

    如果使用多个参数调用toFixed方法,则行为未定义(请参见第15节)。

    一个实现允许扩展toFixed的行为,以便小于0或大于20fractionDigits值。 在这种情况下toFixed不一定会为这些值抛出RangeError

    :对于某些值, toFixed的输出可能比toString更精确,因为toString只打印足够的有效数字以区分相邻数值的数字。 例如, (1000000000000000128).toString()返回"1000000000000000100" ,而(1000000000000000128).toFixed(0)返回"1000000000000000128"


    解决您的两个原始问题/问题:

    Math.round(num)vs num.toFixed(0)

    这里的问题在于它们应该总是给出相同结果的错误观念。 事实上,它们受不同规则的约束。 例如,看负数。 由于Math.round使用“半舍起”作为规则,因此即使Math.round(1.5)计算结果为2Math.round(-1.5)计算结果也为-1

    另一方面, Number.prototype.toFixed使用基本上等同于“离零的一半的距离”的规则,根据规范的步骤6,基本上说,将负数视为正数,然后加回最后的负号。 因此, (-1.5).toFixed(0) === "-2"(1.5).toFixed(0) === "2"是所有符合规范的浏览器中的真实语句。 请注意,这些值是字符串,而不是数字。 进一步注意,由于运算符的优先级, -1.5.toFixed(0)-(1.5).toFixed(0)都是=== -2 (数字)。

    浏览器不一致

    大多数现代浏览器 - 或者至少在本文编写时应该支持的浏览器除外 -都应该正确实现规范。 (根据Renee的评论,你在Opera中指出的toFixed问题已经修复,大概是因为他们开始使用与Chrome相同的JS引擎。)仍然值得重申的是,即使规范在所有浏览器中一致地实现,行为在规范中定义的,特别是对于toFixed四舍五入,仍然可以对谁想到“凡人” JS开发商有点不直观的真实数字的精确性,看到的Javascript toFixed不圆整而这个“作品意欲”错误,是在V8 JS引擎提交举些例子。

    结论

    总之,这些是两种不同的功能,具有两种不同的返回类型和两套不同的舍入规则。

    正如其他人所建议的,我还想说“使用适合您的特定用例的功能”(特别注意toFixed的特性,特别是IE的错误实现)。 正如其他人所提到的,我个人更倾向于推荐Math.round/ceil/floor明确组合。 编辑:...然而,在回头阅读你的说明之后,你的用例(四舍五入为整数)肯定会要求命名为Math.round函数。

    链接地址: http://www.djcxy.com/p/21373.html

    上一篇: Math.round(num) vs num.toFixed(0) and browser inconsistencies

    下一篇: Is a double really unsuitable for money?