使用按位OR 0来设置数字

Ale*_*pin 178 javascript floating-point bit-manipulation

我的一位同事偶然发现了一种方法来使用按位或者:

var a = 13.6 | 0; //a == 13
Run Code Online (Sandbox Code Playgroud)

我们在谈论它并想知道一些事情.

  • 它是如何工作的?我们的理论是使用这样的运算符将数字转换为整数,从而删除小数部分
  • 它有什么优势Math.floor吗?也许它快一点?(双关语不打算)
  • 它有任何缺点吗?也许它在某些情况下不起作用?清晰度是显而易见的,因为我们必须弄清楚,而且,我正在写这个问题.

谢谢.

Joe*_*Joe 144

它是如何工作的?我们的理论是使用这样的运算符将数字转换为整数,从而删除小数部分

除了无符号右移之外的所有按位运算都>>>适用于带符号的32位整数.因此,使用按位运算会将float转换为整数.

做Math.floor有什么优势吗?也许它快一点?(双关语不打算)

http://jsperf.com/or-vs-floor/2似乎稍快一些

它有任何缺点吗?也许它在某些情况下不起作用?清晰度是显而易见的,因为我们必须弄清楚,而且,我正在写这个问题.

  • 不会传递jsLint.
  • 仅限32位有符号整数
  • 奇怪的比较行为:Math.floor(NaN) === NaN同时(NaN | 0) === 0

  • @harold确实,因为它实际上并不圆,只是截断. (8认同)
  • 另一个可能的缺点是`Math.floor(NaN)=== NaN`,而`(NaN | 0)=== 0`.在某些应用中,这种差异可能很重要. (4认同)
  • 由于循环不变代码运动,您的jsperf在chrome上产生空循环的性能信息.稍微好一点的性能测试将是:http://jsperf.com/floor-performance/2 (4认同)
  • 这是`asm.js`的标准部分(我第一次了解它).如果没有其他原因,它会更快,因为它不会在`Math`对象上调用一个函数,这个函数可以在任何时候被替换为`Math.floor = function(...)`. (2认同)
  • `(value | 0)=== value`可以用来检查一个值实际上是一个整数而只是一个整数(如榆树源代码@dwayne-crooks链接).并且`foo = foo | 0`可用于将任何值强制转换为整数(其中32位数字被截断,所有非数字变为0). (2认同)

Cha*_*dia 31

这是截断而不是地板.霍华德的回答是正确的; 但我想补充的Math.floor是,它与负数完全相同.在数学上,这就是一个楼层.

在上面描述的情况下,程序员对截断或完全关闭十进制更感兴趣.虽然,他们使用的语法有点掩盖了他们将float转换为int的事实.

  • 这是正确的答案,接受的不是。加上`Math.floor(8589934591.1)`会产生预期结果,`8589934591.1 | 0` **不会**。 (5认同)

zan*_*ngw 18

在ECMAScript中6,相当于|0Math.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
Run Code Online (Sandbox Code Playgroud)

  • 除了`Math.trunc()`使用数字高于或等于2 ^ 31和`|的事实 0`没有 (3认同)

How*_*ard 10

你的第一点是正确的.该数字被转换为整数,因此删除任何十进制数字.请注意,它会Math.floor向负无穷大舍入到下一个整数,因此在应用于负数时会产生不同的结果.


Sho*_*use 9

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
Run Code Online (Sandbox Code Playgroud)

还。按位运算不“地板”。它们截断,这就是说,它们最接近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);
}
Run Code Online (Sandbox Code Playgroud)

只是添加Math.trunc像按位操作一样的工作。所以你可以这样做:

function trunc(n) {
    if (n > -0x80000000 && n < 0x80000000) {
      return n & 0xFFFFFFFF;
    }
    return Math.trunc(n);
}
Run Code Online (Sandbox Code Playgroud)


pim*_*vdb 5

  • 规范说,它被转换为一个整数:

    让lnum成为ToInt32(lval).

  • 性能:此前已在jsperf进行过测试.