In JavaScript code where the 8 bits of a byte represent 8 Boolean "decisions" (aka: flags), there is a need to isolate each given bit for conversion to a Boolean variable. Consider my solution using String parsing:
var bitParser = function (_nTestByte, _nBitOrdinal) {
var bits = ("00000000" + _nTestByte.toString(2)).slice(-8); // convert to binary and zero-pad
return bits[_nBitOrdinal] === "1";
};
console.log(bitParser(0b10100101, 2)); // ECMAScript 6+ prefix, returns true
It works, and shows the desired result. However I have a hypothesis stating that a bit shifting technique would be a faster option than String manipulation. I tend to believe that but desire to prove it.
The problem is, I have yet to produce such a function that works correctly, let alone something I can test. I have created the following logic plan that I believe is accurate:
/*
LOGIC PLAN
----------
0) Remember: all bitwise operators return 32 bits even though we are using 8
1) Left shift until the desired bit is the left-most (highest) position;
2) Right shift (zero filling) 31 bits to eliminate all right bits
*/
The implementation of the login plan follows. Because of the 32 bit nature of bitwise operators, its my belief that the entire left 3 bytes (24 bits) must be shifted off first before we even reach the byte being worked on. Then, assuming a scenario where the 3rd bit from the left (String ordinal 2) is the desired bit, I am shifting off 2 more bits (ordinals 0 & 1), for a total of 26 bits of left shifting.
This should produce a binary number with the desired bit all the way left followed by 31 undesired zero bytes. Right shifting those 31 bits away produces a binary with 31 (now) leading zero bits which evaluates to whatever the value of the desired bit is. But of course, I would not be writing this question if THAT were true, now would I? :-)
// hardcoded, assuming the second "1" (ordinal 2) is the bit to be examined
console.log((0b10100101 << 26) >> 31); // instead of 1, returns -1
I feel like I am really close, but missing something or pushing JavaScript too hard (lol).
In JavaScript code where the 8 bits of a byte represent 8 Boolean "decisions" (aka: flags), there is a need to isolate each given bit for conversion to a Boolean variable...
If that's the actual goal, bitshifting is neither necessary nor useful: Just use a bitwise &
with the desired bit, which will give you either 0
or a number with that bit set. 0
is falsy, the number with a bit set is truthy. You can either use that as-is, or force it to boolean via !!flag
or Boolean(flag)
:
Here's your bitParser
function using bitmasking:
var bitParser = function (_nTestByte, _nBitOrdinal) { return !!(_nTestByte & Math.pow(2, _nBitOrdinal)); }; console.log(bitParser(0b10100101, 2)); // true console.log(bitParser(0b10100101, 1)); // false
Rather than doing the Math.pow
every time, of course, we'd probably be better off with a lookup table:
var bits = [ 0b00000001, 0b00000010, 0b00000100, 0b00001000, 0b00010000, 0b00100000, 0b01000000, 0b10000000 ]; var bitParser = function (_nTestByte, _nBitOrdinal) { return !!(_nTestByte & bits[_nBitOrdinal]); }; console.log(bitParser(0b10100101, 2)); // true console.log(bitParser(0b10100101, 1)); // false
From your question I took
console.log((0b10100101 << 26) >> 31); //instead of 1, returns -1
console.log((0b10100101 << 26) >> 31); //instead of 1, returns -1
.
And to answer your question why it returned -1 instead of 1
You need to do unsigned right shift >>>
instead of signed one >>
console.log((0b10100101 << 26 ) >>>31);
Yes it can, and what you're doing is almost correct.
Integers are represented as a 32bit binary number, with the leftmost bit representing the sign (it's 1
if the number is negative and 0
if the number is positive). Lets look at some of the numbers' representations:
//last 31 digits keeps increasing as the number decreases
// ...
-2 => 0b11111111111111111111111111111110
-1 => 0b11111111111111111111111111111111
0 => 0b00000000000000000000000000000000
1 => 0b00000000000000000000000000000001
2 => 0b00000000000000000000000000000010
// ...
// last 31 digits keep increasing as the number increases
Now, what you're having (0b10100101 << 26)
should give you 10010100000000000000000000000000
, which you'd expect to be a big negative number (because the left-most bit is 1
). Then right afterwards, you have >> 31
which you're expecting to strip off all 31 bits and leave you with the left-most bit.
That should work, but it's not what's happening. And why is that? It's because the people who came up with ECMAScript thought it would make more sense if 4 >> 1
returns 2
and -4 >> 1
returns -2
.
4 >> 1 // returns 2 which is 0b00000000000000000000000000000010
0b0000000000000000000000000000000100 >> 1 // returns 2, same
-4 >> 1 // returns -2, which is 0b11111111111111111111111111111110
But -4 is 0b11111111111111111111111111111100
, and for your purposes right shifting it by 1 should yield 0b01111111111111111111111111111110
(big positive number, since left-post bit is 0), and that's not -2
!
To overcome that, you can use the other right shift operator which doesn't care about about the sign: >>>
. -4 >>> 1
is 2147483646
which is what we want.
So console.log((0b10100101 << 26) >>> 31);
gives you 1
, which is what you want. You can also keep using >>
and regarding any negative outcome to be a result of 1
being the chosen bit.
The most simple way to achieve your actual need is to use simple conditions rather than trying to isolate bits.
var bitParser = function (_nTestByte, _nBitOrdinal) { return (_nTestByte & _nBitOrdinal); }; console.log(bitParser(6, 2) ? true : false); // true console.log(bitParser(6, 1) ? true : false); // false
I adapted the console.log()
expression in a way that may seem complicated.
It's only to really show the logical result at this step, while I didn't choose to use !!
inside of the function, so returning a truly/falsy value rather than true
| false
.
Actually this way keeps all the most simple possible, because the expected use else where in the code is if (bitParser(...))
, which automatically casts the result to boolean.
BTW, this works whatever is the _nTestByte
size (may be more than 1 byte).
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.