Javascript Integer Division, or is Math.floor(x) equivalent to x | 0 for x >= 0?

Looking at the following examples, it looks like Math.floor(x) is equivalent to x | 0, for x >= 0. Is that really true? If yes, why? (or how x | 0 is calculated?)

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

This can be useful to perform integer division in Javascript: (5 / 3) | 0 rather than Math.floor(5 / 3).

Answers:

Answer

Bitwise operators convert numbers to a 32-bit sequence. So the alternatives you’re suggesting will only work with positive signed 32-bit floats, i.e. numbers from 0 to +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

Another difference: if x is not a number, the result of x | 0 might be different than that of Math.floor(x).

Math.floor(NaN); // NaN
NaN | 0; // 0

Other than that, the result should be similar to that of Math.floor(), as long as a positive number is used.

Here are some more examples + performance tests: http://jsperf.com/rounding-numbers-down

Answer

As per ECMAScript spec, §11.10 Binary Bitwise Operators:

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.

This is how x | y is calculated: x and y are parsed to Int32 and then apply the | operator to them.

Answer

Bitwise operations in JS are 32bit, that is the float is first "cast" into an "int".

"2.6" | 0 = 2 suggests that parseInt is being called.

Answer

The vertical bar is the bitwise-or operator. Since the bits of 0 are all zero, x|0 is in theory a no-op. But in order to evaluate it the operands must be integers, so x must be converted from floating point into an integer first. The conversion is made by eliminating the fractional part, so yes, for some x >= 0 we have x|0 == Math.floor(x).

Note that the result depends on the size and signness of the internal integer type. For example you get:

2147483648|0     == -2147483648     // 0x80000000
Math.pow(2,32)|0 == 0               // the lowest 32 bits are all 0
Answer

(x | 0) removes the bits after the ".", so we can get the next true relation:

x | 0 = (x < 0 ? -1 : 1) * Math.floor(Math.abs(x)) ;

x >> 0 has the same effect as x | 0, so :

x >> 0 = x | 0 = (x < 0 ? -1 : 1) * Math.floor(Math.abs(x)) ;

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.