Javascript 整数除法,或者是 Math.floor(x) 等价于 x | 0 代表 x >= 0?
Posted
技术标签:
【中文标题】Javascript 整数除法,或者是 Math.floor(x) 等价于 x | 0 代表 x >= 0?【英文标题】:Javascript Integer Division, or is Math.floor(x) equivalent to x | 0 for x >= 0? 【发布时间】:2012-02-22 08:56:43 【问题描述】:看下面的例子,看起来Math.floor(x)
等价于x | 0
,对于x >= 0
。这是真的吗?如果是,为什么? (或者x | 0
是如何计算的?)
x = -2.9; console.log(Math.floor(x) + ", " + (x | 0)); // -3, -2
x = -2.3; console.log(Math.floor(x) + ", " + (x | 0)); // -3, -2
x = -2; console.log(Math.floor(x) + ", " + (x | 0)); // -2, -2
x = -0.5; console.log(Math.floor(x) + ", " + (x | 0)); // -1, 0
x = 0; console.log(Math.floor(x) + ", " + (x | 0)); // 0, 0
x = 0.5; console.log(Math.floor(x) + ", " + (x | 0)); // 0, 0
x = 2; console.log(Math.floor(x) + ", " + (x | 0)); // 2, 2
x = 2.3; console.log(Math.floor(x) + ", " + (x | 0)); // 2, 2
x = 2.9; console.log(Math.floor(x) + ", " + (x | 0)); // 2, 2
x = 3.1; console.log(Math.floor(x) + ", " + (x | 0)); // 3, 3
这对于在 javascript 中执行整数除法很有用:(5 / 3) | 0
而不是 Math.floor(5 / 3)
。
【问题讨论】:
x >= 0
和 x < Math.pow(2, 31)
,因为 32 位和有符号。
其实x|0
也和~~x
是一样的,~
是按位NOT操作符,就是这样的:~x = -(x+1)
(加1换号)。而且由于 ~ 也是按位运算符,它还将数字转换为整数。通过再次执行 ~x,您将返回带有原始 +/- 符号的原始数字,但作为整数。换句话说:~~x == (x|0)
【参考方案1】:
按位运算符将数字转换为 32 位序列。因此,您建议的替代方案仅适用于正符号 32 位浮点数,即从 0
到 +2,147,483,647
(2^31-1
) 的数字。
Math.floor(2147483646.4); // 2147483647
2147483646.4 | 0; // 2147483647
// but…
Math.floor(2147483648.4); // 2147483648
2147483648.4 | 0; // -2147483648
另一个区别:如果x
不是数字,x | 0
的结果可能与Math.floor(x)
的结果不同。
Math.floor(NaN); // NaN
NaN | 0; // 0
除此之外,结果应该与Math.floor()
类似,只要使用正数即可。
这里有更多示例 + 性能测试:http://jsperf.com/rounding-numbers-down
【讨论】:
看性能测试,parseInt(x)
是最快的。
@MishaMoroshko 不,这是最慢的。显示的数字是每秒的操作次数,所以数字越大,速度越快。【参考方案2】:
根据ECMAScript spec,§11.10 二进制位运算符:
Semantics
The production A : A @ B, where @ is one of the bitwise operators in the productions
above, is evaluated as follows:
1. Let lref be the result of evaluating A.
2. Let lval be GetValue(lref).
3. Let rref be the result of evaluating B.
4. Let rval be GetValue(rref).
5. Let lnum be ToInt32(lval).
6. Let rnum be ToInt32(rval).
7. Return the result of applying the bitwise operator @ to lnum and rnum. The result
is a signed 32 bit integer.
x | y
的计算方式如下:
x
和 y
被解析为 Int32
,然后对它们应用 |
运算符。
【讨论】:
【参考方案3】:JS 中的按位运算是 32 位的,即浮点数首先“转换”为“int”。
"2.6" | 0 = 2
表明正在调用parseInt
。
【讨论】:
Math.floor
没有在内部调用,ToInt32
是。请参阅规范中的BitwiseORExpression
:es5.github.com/x11.html#x11.10
你是对的。我才意识到。这没有任何意义。因为 Math.floor(竖线是按位或运算符。由于 0 的位全为零,x|0
理论上是无操作的。但是为了评估它,操作数必须是整数,所以x
必须首先从浮点数转换为整数。通过消除小数部分进行转换,所以是的,对于某些 x >= 0,我们有 x|0
== Math.floor(x)
。
请注意,结果取决于内部整数类型的大小和符号。例如你得到:
2147483648|0 == -2147483648 // 0x80000000
Math.pow(2,32)|0 == 0 // the lowest 32 bits are all 0
【讨论】:
【参考方案5】:(x | 0) 去掉“.”之后的位,所以我们可以得到下一个真正的关系:
x | 0 = (x < 0 ? -1 : 1) * Math.floor(Math.abs(x)) ;
x >> 0 与 x | 效果相同0,所以:
x >> 0 = x | 0 = (x < 0 ? -1 : 1) * Math.floor(Math.abs(x)) ;
【讨论】:
以上是关于Javascript 整数除法,或者是 Math.floor(x) 等价于 x | 0 代表 x >= 0?的主要内容,如果未能解决你的问题,请参考以下文章