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,则引发RangeErrorexception。- 设
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()。 在这个问题上,最好的方法是讨论一下。