I am trying to create a 32-bit bitmask in JS. However, I don't understand what's happening here:
$ node
> const num = Math.pow(2, 31) - 1
undefined
> num
2147483647
# So far, so good
> num.toString(2)
'1111111111111111111111111111111'
> num.toString(2).length
31
# According to MDN, the left-shift operator does:
# "Excess bits shifted off to the left are discarded.
# Zero bits are shifted in from the right."
# But that's not what we see here. Instead, it seems to be wrapping.
> num << 1
-2
> (num << 1).toString(2)
'-10'
According to my understanding of the MDN docs, I'd expect to have a bitmask of 31 1s followed by 1 0. Instead, I get -10. What's going on here?
Javascript doesn't have Integer, but bitwise operators only make sense on Integer.
So before bitwise operators, javascript will apply ToInt32(val) to your num.
For "Signed 32 bits Integer", the top bit represents 'signed'.
Finally your num overflow the 'signed bit'.
My English is poor, you can check ECMAScript's Language Specification.
It is not wrapping. It is exactly working as the documentation you've linked. In your linked documentation, it says:
The operands of all bitwise operators are converted to signed 32-bit integers in two's complement format.
Your num is 2147483647, and this number in two's complement format is:
01111111 11111111 11111111 11111111
After left shifting num by 1, it becomes:
11111111 11111111 11111111 11111110
The above 32-bit two's complement value is -2 in decimal number. Hence, you get:
> num
2147483647
> num << 1
-2
If you call toString(2) with a negative decimal number -2, it follows some special rule of toString(). What it does is:
Take the magitude of the decimal. (-2 => 2)
Convert the decimal to base-2 string representation. (2 => '10')
Put the minus sign in front. ('10' => '-10')
Therefore, you get:
> (num << 1).toString(2)
> -10
You also get:
> (-2).toString(2)
> -10
Today I check your question again then know I misunderstand your main point yesterday.
This is your main point:
" I'd expect to have a bitmask of 31 1s followed by 1 0. Instead, I get -10."
Because Two's complement.
A negative number doesn't express value directly.
let num=Math.pow(2,31)-1
//num in memory=> 0111111111111111111111111111111
// ^
// |
// signed bit
//This number is positive, so
//nothing to do=> 0111111111111111111111111111111
num = num<<1
//num in memory=> 1111111111111111111111111111110
// ^
// |
// signed bit
//This number is negative, so flip then add 1
//flip => 1000000000000000000000000000001
//add 1 => 1000000000000000000000000000010 => '-10'
Related
I am trying to understand this line of code. What is the minus and tilde doing to r[e]?:
r = {}
for (e of s)
r[e] = -~r[e] // What is this specific line assigning?
for (e in r)
if (r[e] == 1)
return e
return '_'
The problem this code solves is this(specific line is commented):
Given a string s, find and return the first instance of a
non-repeating character in it. If there is no such character, return
'_'.
I understand the other lines except the commented one.
Tilde is a unary operator that takes the expression to its right performs this small algorithm on it
-(N+1) // N is the expression right to the tilde
So in your code it is incrementing r[e] with 1 (because of double negation).
See the examples below:
console.log(~-2); // 1
console.log(~-1); // 0
console.log(~0); // -1
console.log(~1); // -2
console.log(~2); // -3
Tilde is the bitwise operator for NOT operation.
It takes in a number as operand, converts it into a 32 bit integer (refer IEEE_754-1985 and flips all the bits. 0 becomes 1, 1 becomes 0.
For example, if the number 5 is represented by
00000000 00000000 00000000 00000101
The number ~5 is the above, with the bits flipped
11111111 11111111 11111111 11111010
The decimal value of ~5 is (-6). This is also known as 2's complement. Since the most significant bits, which represent the sign of the number in JavaScript are flipped, the sign will always change. 2's complement causes the value of X to change to -(X+1)
Certain applications like engines, use bitwise data structures and bitwise operations play a role in those.
Bitwise OR (|)
Bitwise AND (&)
Bitwise NOT (~)
Bitwise XOR (^)
Bitwise LEFT SHIFT (<<)
Bitwise RIGHT SHIFT (>>)
What does 'x << ~y' represent in JavaScript?
I understand that the bitwise SHIFT operation does this:
x << y AS x * 2y
And a tilde ~ operator does:
~x AS -(x+1)
So, I assume the following:
5 << ~3 AS 5 * 2-4 or 5 * Math.pow(2, -4)
It should result in 0.3125.
But, when I run 5 << ~3 it results in 1342177280.
What is a step-by-step explanation? How and why does this combination of operations result in 1342177280 instead of 0.3125?
(This question is similar to Stack Overflow question What are bitwise operators? about the bitwise SHIFT operator.)
x << -n is equal to x << (32 - n)
~3 == -4 so
5 << ~3 === 5 << (32 - 4) === 5 << 28 which is 1,342,177,280
to be accurate X << -n is not the same as X << (32 - n) ... in fact it's both simpler and more complicated ... the valid range of a bit shift operator is 0 to 31 ... the RHS in a bit shift operator is first converted to an unsigned 32 bit integer, then masked with 31 (hex 1f) (binary 11111)
3 = 00000000000000000000000000000011
~3 = 11111111111111111111111111111100
0x1f (the mask) 00000000000000000000000000011111
--------------------------------
~3 & 0x1f 00000000000000000000000000011100 = 28
when the magnitude is less than 32, it's exactly the same as what I posted above though
Bit operations work with 32 bit integers. Negative bit shifts are meaningless so are wrapped into positive 32 bit integers
How the << operator works
The rhs is converted to an unsigned 32bit integer - like explained here ToUInt32
ToUint32 basically takes a number and returns the number modulo 2^32
The ~ operator flips the bits of the item, while << is a bitwise left shift. Here is what is happening in binary step-by-step. Note that the most left bit being 1 signified a negative number, this format is twos compliment:
3 // (00000000000000000000000000000011 => +3 in decimal)
// ~ flips the bits
~3 // (11111111111111111111111111111100 => -4 in decimal)
// The number 5 (..00101) shifted by left by -4 (-4 unsigned -> 28)
5 // (00000000000000000000000000000101 => +5 in decimal)
5 << -4 // (01010000000000000000000000000000 => +1342177280 in decimal)
In the last line the bits are shifted and "rotated" to the other side, leading to a large positive number. In fact shifting by a negative number is similar to a bitwise rotation (overflowed bits are rotated to the other side), where shifting by positive numbers do not have such behaviour. The draw back is that the non-rotated bits are disregarded. Essentially meaning that 5 << -4 is the same as doing 5 << (32 - 4), that rather the rotation is actually a large shift.
The reasoning for this is because bit shifts are only a 5 bit unsigned integer. So the binary number in twos compliment-4 (11100) unsigned would be 28.
Your analysis is correct, except that you should not interpret ~3 (11100) (the bit-complement of 3 (00011)) as -4 , but as an unsigned (that is non-negative) 5-bit integer, namely 28 = 16 + 8 + 4 (11100).
This is explained in the ECMAScript standard (NB in most modern machines, positive and negative integers are represented in memory using two's complement representation):
12.8.3 The Left Shift Operator ( << )
NOTE Performs a bitwise left shift operation on the left operand by the amount specified by the right operand.
12.8.3.1 Runtime Semantics: Evaluation
ShiftExpression : ShiftExpression << AdditiveExpression
Let lref be the result of evaluating ShiftExpression.
Let lval be GetValue(lref).
ReturnIfAbrupt(lval).
Let rref be the result of evaluating AdditiveExpression.
Let rval be GetValue(rref).
ReturnIfAbrupt(rval).
Let lnum be ToInt32(lval).
ReturnIfAbrupt(lnum).
Let rnum be ToUint32(rval).
ReturnIfAbrupt(rnum).
Let shiftCount be the result of masking out all but the least significant 5 bits of rnum, that is, compute rnum & 0x1F.
Return the result of left shifting lnum by shiftCount bits. The
result is a signed 32-bit integer.
~x will reverse the bit representation of your x value (32 bits signed value with two's complement).
x << y is the left shift operator (here left). Your mathematical interpretation is correct :)
You can read more about bitwise operations over here: bitwise operators in Javascript
5 << ~3 gives the same result as 5 << -4, you are right.
Important thing: shifting x << y really results into x * 2y, but it is not a direct usage, it is just a useful side-effect.
Moreover, if you have a negative y, it doesn't work in the same way.
Suppose we have 1 and this number in base 2 is:
00000000000000000000000000000001
Now I want to flip all bits to get following result:
11111111111111111111111111111110
As far as I know, the solution is to use the ~ (bitwise NOT operator) to flip all bits, but the result of ~1 is -2:
console.log(~1); //-2
console.log((~1).toString(2)); //-10 (binary representation)
Why do I get this strange result?
There are 2 integers between 1 and -2: 0 and -1
1 in binary is 00000000000000000000000000000001
0 in binary is 00000000000000000000000000000000
-1 in binary is 11111111111111111111111111111111
-2 in binary is 11111111111111111111111111111110
("binary" being 2's complement, in the case of a bitwise not ~ )
As you can see, it's not very surprising ~1 equals -2, since ~0 equals -1.
As #Derek explained, These bitwise operators treat their operands as a sequence of 32 bits. parseInt, on the other hand, does not. That is why you get some different results.
Here's a more complete demo:
for (var i = 5; i >= -5; i--) {
console.log('Decimal: ' + pad(i, 3, ' ') + ' | Binary: ' + bin(i));
if (i === 0)
console.log('Decimal: -0 | Binary: ' + bin(-0)); // There is no `-0`
}
function pad(num, length, char) {
var out = num.toString();
while (out.length < length)
out = char + out;
return out
}
function bin(bin) {
return pad((bin >>> 0).toString(2), 32, '0');
}
.as-console-wrapper { max-height: 100% !important; top: 0; }
100 -4
101 -3
110 -2
111 -1
000 0
001 1
010 2
011 3
A simple way to remeber how two's complement notation works is imagine it's just a normal binary, except its last bit corresponds to the same value negated. In my contrived three-bit two's complement first bit is 1, second is 2, third is -4 (note the minus).
So as you can see, a bitwise not in two's complement is -(n + 1). Surprisingly enough, applying it to a number twice gives the same number:
-(-(n + 1) + 1) = (n + 1) - 1 = n
It is obvious when talking bitwise, but not so much in its arithmetical effect.
Several more observations that make remebering how it works a bit easier:
Notice how negative values ascend. Quite the same rules, with just 0 and 1 swapped. Bitwise NOTted, if you will.
100 -4 011 - I bitwise NOTted this half
101 -3 010
110 -2 001
111 -1 000
----------- - Note the symmetry of the last column
000 0 000
001 1 001
010 2 010
011 3 011 - This one's left as-is
By cycling that list of binaries by half of the total amount of numbers in there, you get a typical sequence of ascending binary numbers starting at zero.
- 100 -4 \
- 101 -3 |
- 110 -2 |-\ - these are in effect in signed types
- 111 -1 / |
*************|
000 0 |
001 1 |
010 2 |
011 3 |
*************|
+ 100 4 \ |
+ 101 5 |-/ - these are in effect in unsigned types
+ 110 6 |
+ 111 7 /
In computer science it's all about interpretation. For a computer everything is a sequence of bits that can be interpreted in many ways. For example 0100001 can be either the number 33 or ! (that's how ASCII maps this bit sequence).
Everything is a bit sequence for a computer, no matter if you see it as a digit, number, letter, text, Word document, pixel on your screen, displayed image or a JPG file on your hard drive. If you know how to interpret that bit sequence, it may be turned into something meaningful for a human, but in the RAM and CPU there are only bits.
So when you want to store a number in a computer, you have to encode it. For non-negative numbers it's pretty simple, you just have to use binary representation. But how about negative numbers?
You can use an encoding called two's complement. In this encoding you have to decide how many bits each number will have (for example 8 bits). The most significant bit is reserved as a sign bit. If it's 0, then the number should be interpreted as non-negative, otherwise it's negative. Other 7 bits contain actual number.
00000000 means zero, just like for unsigned numbers. 00000001 is one, 00000010 is two and so on. The largest positive number that you can store on 8 bits in two's complement is 127 (01111111).
The next binary number (10000000) is -128. It may seem strange, but in a second I'll explain why it makes sense. 10000001 is -127, 10000010 is -126 and so on. 11111111 is -1.
Why do we use such strange encoding? Because of its interesting properties. Specifically, while performing addition and subtraction the CPU doesn't have to know that it's a signed number stored as two's complement. It can interpret both numbers as unsigned, add them together and the result will be correct.
Let's try this: -5 + 5. -5 is 11111011, 5 is 00000101.
11111011
+ 00000101
----------
000000000
The result is 9 bits long. Most significant bit overflows and we're left with 00000000 which is 0. It seems to work.
Another example: 23 + -7. 23 is 00010111, -7 is 11111001.
00010111
+ 11111001
----------
100010000
Again, the MSB is lost and we get 00010000 == 16. It works!
That's how two's complement works. Computers use it internally to store signed integers.
You may have noticed that in two's complements when you negate bits of a number N, it turns into -N-1. Examples:
0 negated == ~00000000 == 11111111 == -1
1 negated == ~00000001 == 11111110 == -2
127 negated == ~01111111 == 10000000 == -128
128 negated == ~10000000 == 01111111 == 127
This is exactly what you have observed: JS is pretending it's using two's complement. So why parseInt('11111111111111111111111111111110', 2) is 4294967294? Well, because it's only pretending.
Internally JS always uses floating point number representation. It works in a completely different way than two's complement and its bitwise negation is mostly useless, so JS pretends a number is two's complement, then negates its bits and converts it back to floating point representation. This does not happen with parseInt, so you get 4294967294, even though binary value is seemingly the same.
A 2's complement 32 bit signed integer (Javascript insists that is the format used for a 32 bit signed integer) will store -2 as 11111111111111111111111111111110
So all as expected.
It's two's complement arithmetic. Which is the equivalent of "tape counter" arithmetic. Tape recorders tended to have counters attached (adding machines would likely be an even better analogy but they were obsolete already when 2s complement became hip).
When you wind backwards 2 steps from 000, you arrive at 998. So 998 is the tape counter's 10s complement arithmetic representation for -2: wind forward 2 steps, arrive at 000 again.
2s complement is just like that. Wind forward 1 from 1111111111111111 and you arrive at 0000000000000000, so 1111111111111111 is the representation of -1. Wind instead back another 1 from there, and you get 1111111111111110 which then is the representation of -2.
Numbers in JavaScript are floating point numbers, stored and represented by IEEE 754 standard.
However, for bitwise operations, the operands are internally treated as signed 32-bit integers represented by two's complement format:
The operands of all bitwise operators are converted to signed 32-bit
integers in two's complement format. Two's complement format means
that a number's negative counterpart (e.g. 5 vs. -5) is all the
number's bits inverted (bitwise NOT of the number, a.k.a. ones'
complement of the number) plus one.
A negative number's positive counterpart is calculated the same way. Thus we have:
1 = 00000000000000000000000000000001b
~1 = 11111111111111111111111111111110b
11111111111111111111111111111110b = -2
Note that Number.toString() is not supposed to return the two's complement representation for base-2.
The expression (-2).toString(2) yields -10 which is the minus sign (-) followed by base-2 representation of 2 (10).
This is the expected behavior. According to mdn:bitwise-not.
The part you probably don't understand is that
[11111111111111111111111111111110]₂ = [10]₂¹, if expressed as a signed integer. The leading 1s can be as many as you want and it's still the same number, similar to leading 0s in unsigned integers/decimal.
¹ [10]₂ specifies that 10 should be interpreted as base 2 (binary)
I am implementing decoding of BER-compressed integers and recently I've found a weird JavaScript behavior related to bitwise operations with big integers.
E.g.:
var a = 17516032; // has 25 bits
alert(a << 7) // outputs -2052915200
alert(a * 128) // outputs 2242052096
alert(2242052096 >> 16) // outputs -31325
alert(2242052096 / 65536) // outputs 34211
While the first workaround (multiplication instead of left shift) is acceptable, the second isn't.
Why it happens? How to bear with it?
17516032 in binary is 00000001000010110100011000000000. Shifting to the left by 7 gives you 10000101101000110000000000000000. This is equal to -2052915200 in two's complement (which is how almost all computers represent negative numbers).
>> is a signed right shift. That means that the leftmost bit (which determines the sign of a number) will be shifted into the left side.
e.g.
1100 >> 2 == 1111
0111 >> 2 == 0001
If you want to do an unsigned shift (which ignores the sign bit), use >>> which will zero-fill the left end of the bitstring.
Bitwise operators work on 32 bit integers, while multiplication and division works on floating point numbers.
When you shift a number, it's converted from a floating point number to a 32 bit integer before the operations, and converted back to a floating point number after the operation. The number 2242052096 has the 32nd bit set, so it is a negative number when converted to and from a 32 bit integer.
The >> right shift operator doesn't change the sign of the value, i.e. the bits that are shifted in from the left have the same value as the sign bit. Use the >>> right shift operator to shift in zero bits instead.
Reference: MDN: Bitwise operators
(2242052096 / 65536) == (2242052096 >>> 16)
Note the different shift.
Javascript normally represents numbers as (double-precision) floating point.
Almost all bitwise operations convert to a signed 32-bit integer, do whatever they're going to do, then treat the result as a signed 32-bit integer when converting back.
The exception is >>> which treats the result as an unsigned 32-bit integer when converting back.
So:
right shifts can be made to work simply by using >>> instead of >> ;
a * 128 gives the expected answer because it's never converted to a signed 32-bit integer in the first place - it's just a floating-point multiplication;
a << 7 gives an unexpected answer because it's converted to a signed 32-bit integer, and then you shift a 1 into the sign bit, resulting in a negative signed 32-bit value.
There isn't a <<<, but if you want to write your left shift as a shift, you can use
(a << 7) >>> 0
to get the expected answer (the >>> 0 effectively casts the signed 32-bit value to an unsigned 32-bit value).
This question already has answers here:
Closed 11 years ago.
Possible Duplicates:
What do these operators do?
>> in javascript
Can somebody please explain the bitwise operator >> 1?
example:
65 >> 1 = 32
and also when >> 0
what does it achieve in this example:
var size = (Math.random() * 100 >> 0) + 20;
var size = (Math.random() * 100 >> 0) + 20;
>> 0 in the above example is used to eliminate the fractional portion, as follows:
Math.random() returns a number between 0 and 0.99999999...
This number multiplied by 100 gives you another number between 0 and 99.999999...
This number is right shifted 0 times. The number is implicitly cast to an integer for the shift operation; right shifting 0 times does not have any effect on the value of the resulting integer. You thus end up with an integer between 0 and 99. Note that you could have used the Math.floor() function instead of >> 0.
Add 20 to the integer, the result is an integer between 20 and 119.
Bitwise operator >> means shift right.
It moves the binary value to the right (and removes the right-most bit).
65 >> 1 in binary is:
1000001 >> 1 = 100000 = 32
It effectively divides the number into 2 and drops the remainder.
The operator '>>' shifts the contents of a variable right by 1 bit. This results, effectively, in integer division of that value by 2 as you show in your example:
65 >> 1 = 32
Let's say that a variable is always 32 bits long. The example then says:
65 decimal >> 1 = 32 or, in hex, 0x000041 >> 1 = 0x00000020
More generally: the operator '>>' divides its operand, as a 32-bit integer, by the power of 2 whose value is the shift length. Thus:
129 decimal >> 1 = 64 or 0x000081 >> 1 = 0x000040
129 decimal >> 2 = 32 or 0x000081 >> 2 = 0x000020
129 decimal >> 5 = 2 or 0x000081 >> 5 = 0x000002
and
129 decimal >> 8 = 0 or: 0x000081 >> 8 = 0x000000
The operator '<<' multiplies its operand, as you'd expect.
I don't know how Math.random( ) operates, but I'm willing to bet that the shift of its floating-point returned value right by 0 turns that number into an integer, because shifting left and right has arithmetic meaning only when the operand is an integer.
The bitwise shift operator shifts each bit of the input x bits to the right (>>) or to the left (<<).
65 is 1000001, thus 65 >> 1 = 0100000, which is 32.
EDIT
Here are some useful links:
http://en.wikipedia.org/wiki/Bitwise_operation
http://javascript.about.com/library/blbitop.htm
http://www.java2s.com/Tutorial/JavaScript/0040__Operators/ShiftLeft.htm
>> X takes the binary number and moves all the digits right by X places.
In your example, you use 65, which is 01000001 in binary. If you shift that right by one, the first space (on the left) gets filled in with a 0, and the last digit 'falls off the end'. Giving 00100000, which is the binary representation for 32.
>> 0, therefore shifts the number 0 spaces to the right, and does nothing.
'<< X', does the same, but shifts the number to the left.
These can be compared to multiplying by 2^X (Left-shift) or divinding by 2^X (right-shift), but it should be noted that a binary shift is much faster than a division operation.
You can understand why the output is 32 from rsplak's post. >> is the Right Bit Shift operator and using it as >> 1 will cause every bit to be shifted one place to the right. This means, if the rightmost bit was 1, it would get expelled and the left most bit will contain 0.
The bitwise operator shifts an expression by a number of digits. So in your example you have
65 which ist binary 0100 0001 shiftet 1 position to the right so you got 0010 0000 which is 32 decimal.
Another example:
48 >> 3 = 6
48 decimal is 0011 0000 binary shifted 3 to the right is 0000 0110 which is 6 decimal.
For your second example I can not help you - I can not image why I would shift an expression by 0 positions but maybe you can find out debugging it?