我的一位同事偶然发现了一种使用按位或来计算浮点数的方法:
var a = 13.6 | 0; //a == 13
我们正在谈论它并想知道一些事情。
- 它是如何工作的?我们的理论是使用这样的运算符将数字转换为整数,从而去除小数部分
- 它比做有什么优势
Math.floor
吗?也许它会快一点?(双关语不是故意的) - 它有什么缺点吗?也许在某些情况下它不起作用?清晰度是显而易见的,因为我们必须弄清楚,好吧,我正在写这个问题。
谢谢。
我的一位同事偶然发现了一种使用按位或来计算浮点数的方法:
var a = 13.6 | 0; //a == 13
我们正在谈论它并想知道一些事情。
Math.floor
吗?也许它会快一点?(双关语不是故意的)谢谢。
它是如何工作的?我们的理论是使用这样的运算符将数字转换为整数,从而去除小数部分
除了无符号右移之外的所有按位运算都>>>
适用于有符号的 32 位整数。因此,使用按位运算会将浮点数转换为整数。
它比做 Math.floor 有什么优势吗?也许它会快一点?(双关语不是故意的)
http://jsperf.com/or-vs-floor/2似乎稍微快一点
它有什么缺点吗?也许在某些情况下它不起作用?清晰度是显而易见的,因为我们必须弄清楚,好吧,我正在写这个问题。
Math.floor(NaN) === NaN
, 而(NaN | 0) === 0
这是截断而不是地板。霍华德的回答有点正确;但我想补充一点,Math.floor
它完全符合负数的预期。从数学上讲,这就是地板。
在上面描述的情况下,程序员更感兴趣的是截断或完全切掉小数点。虽然,他们使用的语法有点掩盖了他们将浮点数转换为 int 的事实。
在ECMAScript中6,相当于|0
是Math.trunc,善良的我应该说:
通过删除任何小数位返回数字的整数部分。它只是截断点及其后面的数字,无论参数是正数还是负数。
Math.trunc(13.37) // 13
Math.trunc(42.84) // 42
Math.trunc(0.123) // 0
Math.trunc(-0.123) // -0
Math.trunc("-1.123")// -1
Math.trunc(NaN) // NaN
Math.trunc("foo") // NaN
Math.trunc() // NaN
你的第一点是正确的。该数字被转换为整数,因此任何十进制数字都将被删除。请注意,Math.floor
向负无穷大四舍五入到下一个整数,因此在应用于负数时会产生不同的结果。
Javascript 表示Number
为双精度 64 位浮点数。
Math.floor
考虑到这一点。
按位运算适用于 32 位有符号整数。32 位有符号整数使用第一位作为负号,其他 31 位是数字。因此,允许的 32 位有符号数的最小值和最大值分别为 -2,147,483,648 和 2147483647 (0x7FFFFFFFF)。
因此,当您在做 时| 0
,您实际上是在做的是& 0xFFFFFFFF
。这意味着,任何表示为 0x80000000 (2147483648) 或更大的数字都将返回为负数。
例如:
// Safe
(2147483647.5918 & 0xFFFFFFFF) === 2147483647
(2147483647 & 0xFFFFFFFF) === 2147483647
(200.59082098 & 0xFFFFFFFF) === 200
(0X7FFFFFFF & 0xFFFFFFFF) === 0X7FFFFFFF
// Unsafe
(2147483648 & 0xFFFFFFFF) === -2147483648
(-2147483649 & 0xFFFFFFFF) === 2147483647
(0x80000000 & 0xFFFFFFFF) === -2147483648
(3000000000.5 & 0xFFFFFFFF) === -1294967296
还。按位运算不“地板”。它们截断,这与说,它们最接近0
。一旦你到处去负数,Math.floor
几轮下来,而按位开始舍去了。
正如我之前所说,Math.floor
更安全,因为它使用 64 位浮点数运行。按位更快,是的,但仅限于 32 位有符号范围。
总结一下:
0 to 2147483647
.-2147483647 to 0
.-2147483648
和大于 的数字,按位完全不同2147483647
。如果您真的想调整性能并同时使用两者:
function floor(n) {
if (n >= 0 && n < 0x80000000) {
return n & 0xFFFFFFFF;
}
if (n > -0x80000000 && n < 0) {
return (n - 1) & 0xFFFFFFFF;
}
return Math.floor(n);
}
只是添加Math.trunc
像按位操作一样的工作。所以你可以这样做:
function trunc(n) {
if (n > -0x80000000 && n < 0x80000000) {
return n & 0xFFFFFFFF;
}
return Math.trunc(n);
}