Using bitwise OR 0 to floor a number
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.
Does it have any advantages over doing Math.floor? Maybe it's a bit
faster? (pun not intended)
http://jsperf.com/or-vs-floor/2 seems slightly faster
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
How does x|0 floor the number in JavaScript?
Because, according to the ECMAScript specifications, bitwise operators operators call ToInt32
on each expression to be evaluated.
See 11.10 Binary Bitwise Operators:
The production
A : A @B
, where@
is one of the bitwise operators in
the productions above, is evaluated as follows:
Evaluate
A
.Call
GetValue(Result(1))
.Evaluate
B
.Call
GetValue(Result(3))
.Call
ToInt32(Result(2)).
Call
ToInt32(Result(4)).
Apply the bitwise operator
@
toResult(5)
andResult(6)
. The result is a signed 32 bit integer.Return
Result(7)
.
Flooring numbers in JavaScript: ~~n, n|0 or Math.floor(n)?
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.
Bitwise OR operation with 0b transform a given number in negative
Bitwise operators implicitly convert their operands to 32-bit integers (signed or unsigned, depending on operator). In process, numbers with more than 32 bits get their most significant bits discarded:
Before: 11100110111110100000000000000110000000000001
After: 10100000000000000110000000000001
The only exception of this rule is (relatively) new kid on the primitive block, BigInt type: all the bitwise ops (&
, |
, ^
) and almost all the shifts are overloaded for that type.
This opens a way out of your problem: just use BigInt
instead of plain number
, either explicitly, like this:
const bigIntee = BigInt(1071698660929); // note no `new` here!
... or, if you actually have to use literal, by appending n
to it:
const bigIntee = 1071698660929n; // also works
Note that if one operand is BigInt
, another should be BigInt
as well. So this...
bigIntee | 0
... will make JS angry with your pathetic attempts of getting back to happy type-anarchy times of 90s. To be more specific, you'll get a TypeError thrown right at you:
Cannot mix BigInt and other types, use explicit conversions
This is easily fixable, though: just apply either of aforementioned conversion tricks to the second operand as well.
bigIntee | 0n
// or bigIntee | BigInt(0)
Both works. Disregard 0
being, well, not really a Biggus Integerus kind; type safety reigns here.
Still, there's a problem: >>>
(unsigned right shift operator) cannot be used on BigInts. If you attempt to go with it, you'll get a pretty specific error:
bigIntee >>> 0n
// Uncaught TypeError: BigInts have no unsigned right shift, use >> instead
... which makes total sense (and us wishing all the errors thrown by JS were that specific).
Is it possible to test if a number is either even or '1', using only bitwise operators?
Although I would not recommend to do this at all, but I was able to achieve it in C, but with only making a
to be anunsigned char
. It could work with others too, but that would lengthen the condition.
#include <stdio.h>
int main() {
for (unsigned char a = 0; a < 255; a++) {
if ((~a & 1) | (1 >> (a & 0x0E | a >> 4)))
printf ("%d is even or 1\n", a);
else
printf("%d is odd\n", a);
}
return 0;
}
(~a & 1)
will yield 1
if a
is even. (a & 0x0E | a >> 4)
will yield 0
when a
is either 1
or 0
. Therefore in those cases (1 >> (a & 0x0E | a >> 4)))
will be (1 >> 0)
which is 1
, otherwise the shift value is between 1
and 15
so making the expression 0
.
My initial approach was (1 >> (a >> 1))
, but soon realized this cause shift overflow, since the shift amount exceed the max possible. And not just raising that warning, but actually falsely recognize every n * 64 + 1
values as even. So the more complicated approach is there to limit the shift amount to be less than 64
by OR -ing a
upper 4 bit with its lower 4 bit, but setting the LSB to 0
. This resulting number is <= 15
and only 0
when a
is 1
or 0
just as needed.
C program to clear nth bit of a number using bitwise and operator
Bitwise operations are performed on all bits.
The result of 0 << time
is timeth bit set to zero, and all other bits are zero. So all bits are zero. Bitwise and with zero will always result in zero.
Contrary, the result of 1 << time
is timeth bit set to one, and all other bits are zero. After bitwise negation, the result is timeth bit set to zero, and all other bits are one. Bitwise and will zero out only timeth bit.
How removing decimal parts with bitwise operators work?
With |
, its two operators are converted to integers through the NumberBitwiseOp operation, which calls ToInt32
on both operators, whose process is:
The abstract operation ToInt32 takes argument argument. It converts argument to one of 232 integer values in the range -231 through 231 - 1, inclusive. It performs the following steps when called:
- Let number be ? ToNumber(argument).
- If number is NaN, +0, -0, +∞, or -∞, return +0.
- Let int be the Number value that is the same sign as number and whose magnitude is floor(abs(number)).
- Let int32bit be int modulo 2 ** 32.
- If int32bit ≥ 2 ** 31, return int32bit - 2 ** 32; otherwise return int32bit.
~
, or bitwise NOT, does the same sort of thing, by calling ToInt32
on its operator.
Using x | 0
will remove the decimal part of x
(via ToInt32
) and flip no bits, so it's as if just the decimal part was removed.
Using ~x
will remove the decimal part of x
and flip all of its bits. Using ~~x
will do the same, but flip the bits twice, so the result is as if all that was done to the original expression was drop the decimal part.
Computing the floor of log₂(x) using only bitwise operators in C
This gets the floor of logbase2 of a number.
int ilog2(int x) {
int i, j, k, l, m;
x = x | (x >> 1);
x = x | (x >> 2);
x = x | (x >> 4);
x = x | (x >> 8);
x = x | (x >> 16);
// i = 0x55555555
i = 0x55 | (0x55 << 8);
i = i | (i << 16);
// j = 0x33333333
j = 0x33 | (0x33 << 8);
j = j | (j << 16);
// k = 0x0f0f0f0f
k = 0x0f | (0x0f << 8);
k = k | (k << 16);
// l = 0x00ff00ff
l = 0xff | (0xff << 16);
// m = 0x0000ffff
m = 0xff | (0xff << 8);
x = (x & i) + ((x >> 1) & i);
x = (x & j) + ((x >> 2) & j);
x = (x & k) + ((x >> 4) & k);
x = (x & l) + ((x >> 8) & l);
x = (x & m) + ((x >> 16) & m);
x = x + ~0;
return x;
}
Why Date.now() | 0 not same as Date.now()
Bitwise operators operate on bits as represented by 32 zeros and/or ones. If the number being operated on is outside this range, the result will likely be unintuitive.
For bitwise OR, this limit is reached once the number is 2 ** 31 - 1
:
const test = num => console.log((num | 0) === num);
test(2 ** 31 - 1)
test(2 ** 31)
test(2 ** 31 + 1)
Comparing floats/doubles bitwise after floor/ceil
fabs(floor(a) - floor(b)) < 0.0001
only if floor(a) == floor(b)
, as long as you're in the range of integers that doubles can accurately represent: Does casting to an int after std::floor guarantee the right result?
Related Topics
JavaScript - Generating Combinations from N Arrays With M Elements
CSS Hover VS. JavaScript Mouseover
How to Add Anything in <Head> Through Jquery/Javascript
How to Use the Spacing Utility Classes in Bootstrap
Scrollintoview() Causing the Whole Page to Move
Jquery Drag/Resize with CSS Transform Scale
Check Browser CSS Property Support with JavaScript
Leaflet Map Not Displayed Properly Inside Tabbed Panel
How to Access the Value of Invalid/Custom CSS Properties from JavaScript
Read CSS Property of an Element Using JavaScript
How to Set a Cookie for Another Domain
Rotate the Elements in an Array in JavaScript
Cross-Browser JavaScript Xml Parsing
Jquery in Greasemonkey 1.0 Conflicts with Websites Using Jquery