Javascript 使用按位或 0 对数字求底

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7487977/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 02:28:45  来源:igfitidea点击:

Using bitwise OR 0 to floor a number

javascriptfloating-pointbit-manipulation

提问by Alex Turpin

A colleague of mine stumbled upon a method to floor float numbers using a bitwise or:

我的一位同事偶然发现了一种使用按位或来计算浮点数的方法:

var a = 13.6 | 0; //a == 13

We were talking about it and wondering a few things.

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

  • How does it work? Our theory was that using such an operator casts the number to an integer, thus removing the fractional part
  • Does it have any advantages over doing Math.floor? Maybe it's a bit faster? (pun not intended)
  • Does it have any disadvantages? Maybe it doesn't work in some cases? Clarity is an obvious one, since we had to figure it out, and well, I'm writting this question.
  • 它是如何工作的?我们的理论是,使用这样的运算符将数字强制转换为整数,从而去除小数部分
  • 它比做有什么优势Math.floor吗?也许它会快一点?(双关语不是故意的)
  • 它有什么缺点吗?也许它在某些情况下不起作用?清晰度是显而易见的,因为我们必须弄清楚,好吧,我正在写这个问题。

Thanks.

谢谢。

采纳答案by Joe

How does it work? Our theory was that using such an operator casts the number to an integer, thus removing the fractional part

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

All bitwise operations except unsigned right shift, >>>, work on signed 32-bit integers. So using bitwise operations will convert a float to an integer.

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

Does it have any advantages over doing Math.floor? Maybe it's a bit faster? (pun not intended)

它比做 Math.floor 有什么优势吗?也许它会快一点?(双关语不是故意的)

http://jsperf.com/or-vs-floor/2seems slightly faster

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

Does it have any disadvantages? Maybe it doesn't work in some cases? Clarity is an obvious one, since we had to figure it out, and well, I'm writting this question.

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

  • Will not pass jsLint.
  • 32-bit signed integers only
  • Odd Comparative behavior: Math.floor(NaN) === NaN, while (NaN | 0) === 0
  • 不会通过 jsLint。
  • 仅限 32 位有符号整数
  • 奇怪的比较行为:Math.floor(NaN) === NaN, 而(NaN | 0) === 0

回答by Chad La Guardia

This is truncationas opposed to flooring. Howard's answer is sort of correct; But I would add that Math.floordoes exactly what it is supposed to with respect to negative numbers. Mathematically, that is what a floor is.

这是截断而不是地板。霍华德的回答有点正确;但我想补充一点,Math.floor它完全符合负数的预期。从数学上讲,这就是地板。

In the case you described above, the programmer was more interested in truncationor chopping the decimal completely off. Although, the syntax they used sort of obscures the fact that they are converting the float to an int.

在上面描述的情况下,程序员更感兴趣的是截断或完全切掉小数点。虽然,他们使用的语法有点掩盖了他们将浮点数转换为 int 的事实。

回答by zangw

In ECMAScript 6, the equivalent of |0is Math.trunc, kind of I should say:

在ECMAScript中6,相当于|0Math.trunc,善良的我应该说:

Returns the integral part of a number by removing any fractional digits. It just truncate the dot and the digits behind it, no matter whether the argument is a positive number or a negative number.

通过删除任何小数位返回数字的整数部分。它只是截断点及其后面的数字,无论参数是正数还是负数。

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

回答by Howard

Your first point is correct. The number is cast to an integer and thus any decimal digits are removed. Please note, that Math.floorrounds to the next integer towards minus infinity and thus gives a different result when applied to negative numbers.

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

回答by pimvdb

  • The specs say that it is converted to an integer:

    Let lnum be ToInt32(lval).

  • Performance: this has been tested at jsperfbefore.

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

    令 lnum 为 ToInt32(lval)。

  • 性能:这之前已经在jsperf 上测试过了。

note: dead link to spec removed

注意:删除了规范的死链接

回答by ShortFuse

Javascript represents Numberas Double Precision 64-bit Floating numbers.

Javascript 表示Number双精度 64 位浮点数

Math.floorworks with this in mind.

Math.floor考虑到这一点。

Bitwise operations work in 32bit signedintegers. 32bit signed integers use first bit as negative signifier and the other 31 bits are the number. Because of this, the min and max number allowed 32bit signed numbers are -2,147,483,648 and 2147483647 (0x7FFFFFFFF), respectively.

按位运算适用于 32 位有符号整数。32 位有符号整数使用第一位作为负号,其他 31 位是数字。因此,允许的 32 位有符号数的最小值和最大值分别为 -2,147,483,648 和 2147483647 (0x7FFFFFFFF)。

So when you're doing | 0, you're essentially doing is & 0xFFFFFFFF. This means, any number that is represented as 0x80000000 (2147483648) or greater will return as a negative number.

因此,当您在做 时| 0,您实际上是在做的是& 0xFFFFFFFF。这意味着,任何表示为 0x80000000 (2147483648) 或更大的数字都将返回为负数。

For example:

例如:

 // 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

Also. Bitwise operations don't "floor". They truncate, which is the same as saying, they round closest to 0. Once you go around to negative numbers, Math.floorrounds downwhile bitwise start rounding up.

还。按位运算不“地板”。它们截断,这就是说,它们最接近0。一旦你到处去负数,Math.floor几轮下来,而按位开始舍去

As I said before, Math.flooris safer because it operates with 64bit floating numbers. Bitwise is faster, yes, but limited to 32bit signed scope.

正如我之前所说,Math.floor更安全,因为它使用 64 位浮点数运行。按位更快,是的,但仅限于 32 位有符号范围。

To summarize:

总结一下:

  • Bitwise works the same if you work from 0 to 2147483647.
  • Bitwise is 1 number off if you work from -2147483647 to 0.
  • Bitwise is completely different for numbers less than -2147483648and greater than 2147483647.
  • 如果您从0 to 2147483647.
  • 如果您从-2147483647 to 0.
  • 对于小于-2147483648和大于 的数字,按位完全不同2147483647

If you reallywant to tweak performance and use both:

如果您真的想调整性能并同时使用两者:

function floor(n) {
    if (n >= 0 && n < 0x80000000) {
      return n & 0xFFFFFFFF;
    }
    if (n > -0x80000000 && n < 0) {
      return (n - 1) & 0xFFFFFFFF;
    }
    return Math.floor(n);
}


Just to add Math.truncworks like bitwise operations. So you can do this:

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

function trunc(n) {
    if (n > -0x80000000 && n < 0x80000000) {
      return n & 0xFFFFFFFF;
    }
    return Math.trunc(n);
}