Javascript represents Number
as Double Precision 64-bit Floating numbers.
Math.floor
works with this in mind.
Bitwise operations work in 32bit signed integers. 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.
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.
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.floor
rounds down while bitwise start rounding up.
As I said before, Math.floor
is safer because it operates with 64bit floating numbers. Bitwise is faster, yes, but limited to 32bit signed scope.
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
-2147483648
and greater than 2147483647
.
If you really want 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.trunc
works like bitwise operations. So you can do this:
function trunc(n) {
if (n > -0x80000000 && n < 0x80000000) {
return n & 0xFFFFFFFF;
}
return Math.trunc(n);
}
3000000000.1 | 0
evaluates to -1294967296. So this method can't be applied for money calculations (especially in cases where you multiply by 100 to avoid decimal numbers). – Šime Vidas0.1 + 0.2 == 0.3
in a JavaScript console. If your language supports it, you should use a decimal type. If not, store cents instead. – Alex Turpin