4

I've recently discovered some other ways to remove the fractional part of numeric values in JavaScript other than Math.floor(n), specifically the double bitwise NOT operator ~~n and performing a bitwise or with 0 n|0.

I'd like to know what are the difference between these approaches and what the different scenarios are where one method is recommended over another.

Mick Byrne
  • 13,717
  • 14
  • 68
  • 84
  • http://stackoverflow.com/questions/2526682/why-is-javascripts-math-floor-the-slowest-way-to-calculate-floor-in-javascript , http://stackoverflow.com/questions/9049677/how-does-x0-floor-the-number-in-javascript –  Jun 05 '12 at 01:52
  • eventually, there will be no difference as browsers evolve, see the consistent performance of chrome http://jsperf.com/math-floor-vs-math-round-vs-parseint/41 , it's better write maintainable code – ajax333221 Jun 05 '12 at 03:57
  • 1
    @ajax333221 I just love how the IE entry looks like it is missing data ;-) –  Jun 05 '12 at 04:04

3 Answers3

7

The operands of all bitwise operators are converted to signed 32-bit integers:

Math.floor(2147483648) // 2147483648
2147483648 | 0         // 2147483648
~~2147483648           // 2147483648

Math.floor(2147483649) // 2147483649
2147483649 | 0         // -2147483647
~~2147483649           // -2147483647

So use Math.floor();

jasssonpet
  • 2,009
  • 16
  • 17
6

Be clear to the next person looking at your code and use Math.floor().

The performance gain of 1%-40% isn't really worth it, so don't make your code confusing and hard to maintain.

josh3736
  • 124,335
  • 26
  • 203
  • 248
2

(I entirely agree with josh's answer: favor clear maintainable code.)

Here is an explanation on the other bit-wise approaches:

The bit-wise operators work because they only operator on 32-bit (signed) integers but numbers in JavaScript are all IEEE-754 values. Thus, there is an internal conversion (truncation, not floor!) that happens to operands for bit-wise operators.

The applied bit-wise operation (e.g. n<<0, ~~n or n|0) then acts as an identity function which "does nothing" to the converted values: that is, all of these approaches rely on the same conversion applied to bit-wise operands.

Try n as a negative number or a value outside of [-231, 231-1]:

(-1.23|0)            // -1
Math.floor(-1.23)    // -2

var x = Math.pow(2, 40) + .5
x|0                  // 0
Math.floor(x)        // 1099511627776

Happy coding.