请考虑以下代码:
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)
?将数字舍入到最接近的整数的正确方法是什么?
答案 0 :(得分:32)
修改:要回答您的修改,请使用Math.round
。如果您更喜欢这种语法,也可以对Number
对象进行原型设计,让它进行出价。
Number.prototype.round = function() {
return Math.round(this);
}
var num = 3.5;
alert(num.round())
我之前从未使用Number.toFixed()
(主要是因为大多数JS库提供了toInt()
方法),但根据您的结果判断,我会说使用{{1}会更加一致方法(Math
,round
,floor
)然后ceil
如果您正在寻找跨浏览器一致性。
答案 1 :(得分:11)
我认为FF正在使用toFixed做正确的事情,因为下面的第10步说“如果有两个这样的n,请选择更大的n。”
正如Grant Wagner所说:使用 Math.ceil(x)或 Math.floor(x)而不是 x.toFixed()
以下所有内容均来自ECMAScript Language Specification:
15.7.4.5
Number.prototype.toFixed (fractionDigits)
返回包含定点数表示的数字的字符串 小数点后面带有
fractionDigits
数字的表示法。如果fractionDigits
未定义,假设为0
。具体来说,执行 以下步骤:
- 让
f
为ToInteger(fractionDigits)
。 (如果fractionDigits
未定义, 此步骤生成值0
)。- 如果
f < 0
或f > 20
,则抛出RangeError
例外。- 让
x
为此数字值。- 如果
x
为NaN
,请返回字符串"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
成为。{1}} 由十进制表示的数字组成的字符串n
的顺序(按顺序,没有前导零)。- 如果
f = 0
,请转到步骤20.- 让
k
为m
中的字符数。- 如果
k > f
,请转到步骤18.- 让
z
成为由f+1–k
次出现的字符串组成的字符串 字符'0'
。- 让
m
成为字符串z
和m
的串联。- 允许
k = f + 1
。- 让
a
成为k–f
的第一个m
字符,让b
成为f
的剩余m
个字符。- 让
m
成为三个字符串a
,"."
和b
的串联。- 返回字符串
醇>s
和m
的串联。
length
方法的toFixed
属性为1
。如果使用多个参数调用
toFixed
方法,那么 行为未定义(见第15节)。允许实现扩展
toFixed
的行为fractionDigits
小于0
或大于20
的值。在这种情况下toFixed
不一定会为这些值抛出RangeError
。注意
toFixed
的输出可能比toString
更精确 一些值,因为toString
仅打印足够的有效数字 区分数字与相邻数字值。例如,(1000000000000000128).toString()
会返回"1000000000000000100"
(1000000000000000128).toFixed(0)
会返回"1000000000000000128"
。
答案 2 :(得分:10)
解决您的两个原始问题:
这里的问题在于误解这些应该总是给出相同的结果。事实上,它们受不同规则的约束。例如,查看负数。由于Math.round
使用"round half up"作为规则,因此即使Math.round(-1.5)
评估为-1
,您也会看到Math.round(1.5)
评估为2
。
Number.prototype.toFixed
根据"round half away from zero"使用基本等同于step 6 of the spec的规则,基本上将负数视为正数,然后添加在最后支持负号。因此,(-1.5).toFixed(0) === "-2"
和(1.5).toFixed(0) === "2"
在所有符合规范的浏览器中都是真实的语句。请注意,这些值是字符串,而不是数字。请注意,由于运算符优先级,-1.5.toFixed(0)
和-(1.5).toFixed(0)
都是=== -2
(数字)。
大多数现代浏览器 - 或者至少是您在撰写本文时可能会支持的浏览器 except for IE - 都应该正确实现规范。 (根据Renee's comment,您在Opera中指出的toFixed
问题已得到修复,大概是因为他们开始使用与Chrome相同的JS引擎。)即使它仍然值得重申,即使规范在所有浏览器中都是一致的,规范中定义的行为,尤其是toFixed
四舍五入的行为,对于“凡人”而言仍然有点不直观。期望真正的数学准确性的JS开发人员 - 请参阅V8 JS引擎上提交的Javascript toFixed Not Rounding和this "works as intended" bug作为示例。
简而言之,这是两个不同的函数,有两种不同的返回类型和两组不同的舍入规则。
正如其他人所建议的那样,我还想说&#34;使用适合您特定用例的任何功能&#34; (特别注意注意toFixed
的特殊性,尤其是IE的错误实施)。 我个人倾向于更多地推荐 编辑: ......但是,在回去阅读之后你的澄清,你的用例(四舍五入到整数)绝对需要恰当命名的Math.round/ceil/floor
的明确组合,正如其他人所提到的那样。Math.round
函数。
答案 3 :(得分:6)
toFixed()返回一个字符串值。来自Javascript:The Definitive Guide
将数字转换为包含指定数量的字符串 小数点后的数字。
Math.round()返回一个整数。
显然,toFixed()似乎更有用,例如,
'$'+ 12.34253.toFixed(2)='$ 12.34'
似乎很可惜 toFixed()似乎没有正确舍入!
答案 4 :(得分:2)
而不是toFixed(0)
使用Math.ceil()
或Math.floor()
,取决于所需内容。
答案 5 :(得分:0)
如果你的答案不一致,肯定会这样。
我只能猜测你使用toFixed(0)的意图是将十进制数转换为整数,此时我推荐使用Math.floor()。在this question中有关于最佳方法的更多讨论。