~ bitwise operator in JavaScript - javascript

I have the following code :
var a = parseInt('010001',2);
console.log(a.toString(2));
// 10001
var b = ~a;
console.log(b.toString(2));
// -10010
The MSDN Say
~ Performs the NOT operator on each bit. NOT a yields the inverted
value (a.k.a. one's complement) of a.
010001 should thus return this 101110.
This Topic kinda confirm that
So I can't understand how we can get -10010 instead ? The only potential explanation is that:
010001 is negated 101110 but he write this -10001
and then for an obscure reason he give me the two complements
and -10001 become -10010.
But all this is very obscure in my mind, would you have an idea on what happen precisely.

JavaScript's bitwise operators convert their operands to 32-bit signed integers (the usual 2's complement), perform their operation, then return the result as the most appropriate value in JavaScript's number type (double-precision floating point; JavaScript doesn't have an integer type). More in §12.5.11 (Bitwise NOT Operator ~) and §7.1.5 (ToInt32).
So your 10001 is:
00000000 00000000 00000000 00010001
which when ~ is:
11111111 11111111 11111111 11101110
...which is indeed negative in 2s complement representation.
You may be wondering: If the bit pattern is as above, then why did b.toString(2) give you -10010 instead? Because it's showing you signed binary, not the actual bit pattern. - meaning negative, and 10010 meaning 18 decimal. The bit pattern above is how that's represented in 2s complement bits. (And yes, I did have to go check myself on that!)

Under the covers, when Javascript does bitwise operations, it converts to a 32-bit signed integer representation, and uses that, then converts the result back into its internal decimal representation.
As such, your input value, 010001 becomes 00000000 00000000 00000000 00010001.
This is then inverted:
~00000000 00000000 00000000 00010001 => 11111111 11111111 11111111 11101110
Converted into hex, the inverted value is 0xFFFFFFEE, which is equivalent to the decimal value of -18.
Since this is a signed integer with a value of -18, this value is converted to the underlying decimal representation of -18 by Javascript.
When Javascript tries to print it as a base-2 number, it sees the negative sign and the value of 18, and prints it as -10010, since 10010 is the binary representation of positive 18.

JavaScript uses 32-bit signed numbers,so
a (010001) (17) is 0000 0000 0000 0000 0000 0000 0001 0001
b = ~a (?) (-18) is 1111 1111 1111 1111 1111 1111 1110 1110
The reason for printing -18 as -10010 and methods to get actual value is explained well here Link

As per the documentation on the Mozilla developer website here. Bitwise NOTing any number x yields -(x + 1). For example, ~5 yields -6. That is why you are getting the negative sign in front of the number.

Related

How does | and + do the trick to turn string into number?

When I was reading a doc about Symbol on MDN, I noticed these things can trun string into number which I've never seen before.
Quote:
When trying to convert a symbol to a number, a TypeError will be
thrown (e.g. +sym or sym | 0).
For example:
+"15"
will return
15
which is number type.
Also
"15" | 0
can do the same thing.
I am wondering how does this trick work.
Can you help?
+"15" is casting the "15" to a number type, the same way -15 works.
eg.
>> -"15" === -15
>> true
The second case, "15" | 0 is doing the same thing, casting to an integer in order to perform a Bitwise OR.
Which means taking the bits of 15 and ORing them with the bits of zero.
15 in binary is, for example 00001111 and zero is 00000000 so each bit is or'd with each other resulting in 15 again which is returned.
Unary Plus Operator
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators#Unary_plus_()
The unary plus operator precedes its operand and evaluates to its operand but attempts to convert it into a number, if it isn't already. Although unary negation (-) also can convert non-numbers, unary plus is the fastest and preferred way of converting something into a number, because it does not perform any other operations on the number. It can convert string representations of integers and floats, as well as the non-string values true, false, and null. Integers in both decimal and hexadecimal ("0x"-prefixed) formats are supported. Negative numbers are supported (though not for hex). If it cannot parse a particular value, it will evaluate to NaN.
+"6";//6
+6;//6
+-6;//-6
+undefined;//NaN
+false;//0
+true;//1
+null;//0
+{};//NaN
+[];//0
+function(){};//NaN
Bitwise OR Operator
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#.7c_%28Bitwise_OR%29
The operands are converted to 32-bit integers and expressed by a series of bits (zeroes and ones). Numbers with more than 32 bits get their most significant bits discarded.
Each bit in the first operand is paired with the corresponding bit in the second operand: first bit to first bit, second bit to second bit, and so on.
The operator is applied to each pair of bits, and the result is constructed bitwise.
The Bitwise OR Operator first converts both operands to 32-bit integers and each bit is compared. When comparing the two bits, if any of the bits is 1, 1 is returned. If both bits are 0, 0 is returned.
Example:
2|1;//produces 3
--------
00000010 //2 in binary
00000001 //1 in binary
--------
00000011 //3 in binary

Binary operations in js

I've been trying to figure out how to implement some stuff about rijndael algorithm in js. One particular step (mixColumns) requires to mess around with binary numbers. I decided to follow a guide and at a particular point it does this operation:
it has to multiply d4 (hexadecimal) by 2. Now d4 in binary is 1101 0100, and it's turned into 1010 1000. I guess this is because he left-shifted the number so the leftmost number goes away and a 0 is pushed in the right side. After that it does 1010 1000 XOR 0001 1011 and then the result is: 1011 0011
I don't understand where those XOR and 0001 1011 come from.
I tried to do 10101000 ^ 00011011, yet I didn't manage to get the same result.
Could anyone explain me why that? Please try to be as clear as you can, since I'm new with binaries and these operations.
(Also, sorry for my english or imperfections (it's my first question here));
By the way, I'm also trying to understand this one:
{03} . {bf} = {10 XOR 01} . {1011 1111}
= {1011 1111 . 10} XOR {1011 1111 . 01}
= {1011 1111 . 10} XOR {1011 1111}
= 0111 1110 XOR 0001 1011 XOR 1011 1111
= 1101 1010 (ans)
It does more or less the same things, it converts the bf and the 3 in binary, then it becomes 10 XOR 01..and then..I don't know..
still far away from the solution.
I also wonder if there is a simplest way to do what it does.
Thanks

Why does bitwise "not 1" equal -2?

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)

Why doesn't a >>> 100 produce 0 in JavaScript?

So I was playing around with shifts in the console, and the results have me stumped.
Input:
a = -1
a >>> 100
Output:
268435455
I looked on the Mozilla reference page about it, but it mentions nothing about the behavior of >>> when you shift by large amounts. I assumed that shifting all the bits to the right with zero-fill would result in a zero.
Is this a bug in Firefox or something?
It seems you can only shift by a maximum of 31.
From the site you linked in your post (MDN):
Shifts a in binary representation b (< 32) bits to the right,
discarding bits shifted off, and shifting in zeros from the left.
From the actual spec (Page 77)
Let shiftCount be the result of masking out all but the least
significant 5 bits of rnum, that is, compute rnum & 0x1F.
What's actually happening is when you shift by 100 it shifts by (100 & 0x1F) or 4.
-1 >>> 100 === -1 >>> 4
If you were to split it up into multiple shifts then it will work:
-1 >>> 25 >>> 25 >>> 25 >>> 25 === 0
Any bitwise operator on a Number in JavaScript will convert its operand to a 32 bit big-endian signed number.
This means that if the number is larger than what can be stored by 32 bits, it will be truncated. Big-endian means that number are stored in natural order when reading it from left to right, i.e. more significant numbers are stored first, so if the number is stored over one byte, its first byte is the more significant.
This means that -1's binary representation will be...
11111111 11111111 11111111 11111111
(This is -1 in two's complement. This is performed by calculating the number's value in binary, and then flipping each bit and adding one.)
When you shift by 100, you will find it only shifts by 4, leaving you with...
00001111 11111111 11111111 11111111
As you can see, the high bit is no longer set, so it's not negative, and it is in fact 268435455 (the number from your question).

javascript bitwise operator question

In Javascript when I do this
var num = 1;
~ num == -2
why does ~num not equal 0
in binary 1 is stored as 1 ... thus not 1 should be 0
or it is stored like 0001 thus not 0001 would be 1110
I think I am missing something... can someone clear this up
Look up Two's complement for signed binary numbers
Lets assume that a javascript Number is 8 bits wide (which its not):
then
1 = 0000 0001b
and
~1 = 1111 1110b
Which is the binary representation of -2
0000 0010b = 2
0000 0001b = 1
0000 0000b = 0
1111 1111b = -1
1111 1110b = -2
~ toggles the bits of the operand so
00000001
becomes
11111110
which is -2
Note: In javascript, the numbers are 32-bit, but I shortened it to illustrate the point.
From the documentation:
Bitwise NOTing any number x yields -(x + 1). For example, ~5 yields -6.
The reason for this is that using a bitwise NOT reverses all the bits of a value. If you are storing the value of 1 in a signed 8-bit integer, you're storing the binary value 00000001. If you apply a bitwise NOT, you get 11111110, which for a signed 8-bit integer is the binary value for -2.

Categories

Resources