我的一位同事偶然发现了一种使用按位或者
来浮动数字的方法var a = 13.6 | 0; //a == 13
我们正在谈论它并想知道一些事情。
Math.floor
相比,它有什么优势吗?也许它快一点? (双关语无意)感谢。
答案 0 :(得分:130)
它是如何工作的?我们的理论是使用这样的操作员来投射 数字为整数,从而删除小数部分
除了无符号右移>>>
之外的所有按位运算都适用于带符号的32位整数。因此,使用按位运算会将float转换为整数。
与Math.floor相比,它有什么优势吗?也许有点儿 快点? (双关语无意)
http://jsperf.com/or-vs-floor/2似乎稍快一点
它有任何缺点吗?也许它在某些情况下不起作用? 清晰度是显而易见的,因为我们必须弄明白,而且, 我正在写这个问题。
Math.floor(NaN) === NaN
,而(NaN | 0) === 0
答案 1 :(得分:28)
这是截断而不是地板。霍华德的回答是正确的;但我要补充的是,Math.floor
完全按照负数做了它应该做的事情。在数学上,这就是一个楼层。
在上面描述的情况下,程序员对截断或完全关闭十进制更感兴趣。虽然,他们使用的语法有点掩盖了他们将float转换为int的事实。
答案 2 :(得分:17)
在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
答案 3 :(得分:10)
你的第一点是正确的。该数字被转换为整数,因此删除任何十进制数字。请注意,Math.floor
向负无穷大舍入下一个整数,因此在应用于负数时会产生不同的结果。
答案 4 :(得分:5)
规格说它被转换为整数:
让lnum成为ToInt32(lval)。
效果:此前已在jsperf进行了测试。
注意:删除规范的死链接
答案 5 :(得分:2)
JavaScript将Number
表示为Double Precision 64-bit Floating numbers。
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
开始工作,则按位折扣1。-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);
}
答案 6 :(得分:0)
var myNegInt = -1 * Math.pow(2, 32);
var myFloat = 0.010203040506070809;
var my64BitFloat = myNegInt - myFloat;
var trunc1 = my64BitFloat | 0;
var trunc2 = ~~my64BitFloat;
var trunc3 = my64BitFloat ^ 0;
var trunc4 = my64BitFloat - my64BitFloat % 1;
var trunc5 = parseInt(my64BitFloat);
var trunc6 = Math.floor(my64BitFloat);
console.info(my64BitFloat);
console.info(trunc1);
console.info(trunc2);
console.info(trunc3);
console.info(trunc4);
console.info(trunc5);
console.info(trunc6);
IMO:问题“它是如何工作的?”、“它比做 Math.floor 有什么优势吗?”、“它有什么缺点吗?”与“将其用于此目的是否合乎逻辑?”
相比显得苍白无力我认为,在您尝试巧妙地使用您的代码之前,您可能需要运行这些。我的建议;继续前进,这里没什么可看的。使用按位来保存一些操作并且对你来说很重要,通常意味着你的代码架构需要工作。至于为什么它可以工作有时,一个停止的时钟每天准确两次,这并没有使它有用。这些运算符有其用途,但不是在这种情况下。