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
方法( round
, floor
, ceil
)会更一致。然后toFixed
如果跨浏览器一致性是你在找什么。
我认为FF与toFixed是正确的,因为下面的第10步说:“如果有两个这样的n,select较大的n”。
正如Grant Wagner所说:使用Math.ceil(x)或Math.floor(x)而不是x.toFixed() 。
以下全部来自ECMAScript语言规范 :
15.7.4.5
Number.prototype.toFixed (fractionDigits)
返回一个string,其中包含以小数点后的小数点位数表示的定点符号表示的数字。 如果
fractionDigits
未定义,则假定为0
。 具体来说,执行以下步骤:
- 设
f
为ToInteger(fractionDigits)
。 (如果fractionDigits
未定义,则此步骤将生成值0
)。- 如果
f < 0
或f > 20
,则引发RangeError
exception。- 设
x
是这个数字值。- 如果
x
是NaN
,则返回string"NaN"
。- 我们是空string。
- 如果
x ≥ 0
,则转到步骤9。- 让我们成为
"-"
。- 令
x = –x
。- 如果
x ≥ 10^21
,设m = ToString(x)
并转到步骤20。- 假设
n
是n ÷ 10^f – x
的精确math值尽可能接近零的整数。 如果有两个这样的n
,挑选较大的n
。- 如果
n = 0
,则让m
为string"0"
。 否则,设m
为由n
的十进制表示的数字组成的string(按顺序,没有前导零)。- 如果
f = 0
,则转到步骤20。- 令
k
为m
的字符数。- 如果
k > f
,则转到步骤18。- 令
z
是由字符'0'
的f+1–k
出现组成的string。- 令
m
是串z
和m
的串联。- 令
k = f + 1
。- 设
a
是m
的前k–f
字符,设b
是m
的剩余f
字符。- 设
m
是三个stringa
,"."
,和b
。- 返回string
s
和m
的连接。
toFixed
方法的length
属性是1
。如果使用多个参数调用
toFixed
方法,则行为是未定义的(请参阅第15节)。允许实现扩展对小于
0
或大于20
的fractionDigits
值toFixed
的行为。 在这种情况下toFixed
不一定会为这些值抛出RangeError
。注意
toFixed
的输出可能比toString
更精确,因为toString
只打印足够的有效数字来区分相邻数字值。 例如,(1000000000000000128).toString()
返回"1000000000000000100"
,而(1000000000000000128).toFixed(0)
返回"1000000000000000128"
。
toFixed()返回一个string值。 从Javascript:权威指南
将数字转换为包含小数点后指定位数的string。
Math.round()返回一个整数。
显然,toFixed()似乎更多地用于金钱,例如,
'$'+ 12.34253.toFixed(2)='$ 12.34'
toFixed()看起来好像很可惜!
为了解决您的两个原始问题/问题:
Math.round(num)vs num.toFixed(0)
这里的问题在于它们应该总是给出相同结果的错误观念。 事实上,它们受不同规则的约束。 看看负数,例如。 由于Math.round
使用“半舍起”作为规则,即使Math.round(1.5)
计算结果为2
,您也会看到Math.round(-1.5)
计算结果为-1
。
另一方面, Number.prototype.toFixed
使用基本上相当于“离零的一半”的规则,根据规范的第6步 ,本质上说,将负数视为正数,然后加回最后的负面信号。 因此, (-1.5).toFixed(0) === "-2"
和(1.5).toFixed(0) === "2"
是所有符合规范的浏览器中的真实语句。 (请注意,这些值是string,而不是数字。由于运算符的优先级, -1.5.toFixed(0)
注意-1.5.toFixed(0)
和-(1.5).toFixed(0)
是=== -2
( Number
)。
浏览器不一致
大多数现代浏览器 – 或者至less是本书编写时应该支持的 浏览器(IE除外) – 都应该正确实现规格。 (根据Renee的评论 ,你在Opera中指出的toFixed
问题已经被修正,大概是因为他们开始使用与Chrome相同的JS引擎。)仍然值得重申的是,即使规范在所有浏览器中一致地实现,行为定义在规范中,特别是对于固定四舍五入,对于那些期望真正的math准确性的“凡人”JS开发人员来说,仍然有点不直观 – 请参阅JavaScript toFixed Not Rounding和这个“按预期工作”的错误 ,引擎的例子。
结论
总之,这是两种不同的函数,有两种不同的返回types和两套不同的舍入规则。
正如其他人所build议的那样,我也想说“使用适合您的特定用例的function”(特别注意toFixed
的特性,特别是IE的错误实现)。 我个人更倾向于推荐一些明确的 编辑: …但是,回去后,阅读你的说明,你的用例(四舍五入到一个整数)绝对要求适当命名的Math.round/ceil/floor
组合,正如其他人所说的那样。Math.round
函数。
而不是toFixed(0)
使用Math.ceil()
或Math.floor()
,取决于需要什么。
这绝对是这样,如果你得到不一致的答案。
我只能猜测,你使用固定(0)的意图是把一个十进制数转成一个整数,在这一点上,我build议Math.floor()。 在这个问题上,最好的方法是讨论一下。