Why is it that ~2 is equal to -3? How does ~ operator work?
Why is it that ~2 is equal to -3? How does ~ operator work?
Remember that negative numbers are stored as the two's complement of the positive counterpart. As an example, here's the representation of -2 in two's complement: (8 bits)
1111 1110
The way you get this is by taking the binary representation of a number, taking its complement (inverting all the bits) and adding one. Two starts as 0000 0010, and by inverting the bits we get 1111 1101. Adding one gets us the result above. The first bit is the sign bit, implying a negative.
So let's take a look at how we get ~2 = -3:
Here's two again:
0000 0010
Simply flip all the bits and we get:
1111 1101
Well, what's -3 look like in two's complement? Start with positive 3: 0000 0011, flip all the bits to 1111 1100, and add one to become negative value (-3), 1111 1101.
So if you simply invert the bits in 2, you get the two's complement representation of -3.
~ flips the bits in the value.
Why ~2 is -3 has to do with how numbers are represented bitwise. Numbers are represented as two's complement.
So, 2 is the binary value
00000010
And ~2 flips the bits so the value is now:
11111101
Which, is the binary representation of -3.
As others mentioned ~ just flipped bits (changes one to zero and zero to one) and since two's complement is used you get the result you saw.
One thing to add is why two's complement is used, this is so that the operations on negative numbers will be the same as on positive numbers. Think of -3 as the number to which 3 should be added in order to get zero and you'll see that this number is 1101, remember that binary addition is just like elementary school (decimal) addition only you carry one when you get to two rather than 10.
1101 +
0011 // 3
=
10000
=
0000 // lose carry bit because integers have a constant number of bits.
Therefore 1101 is -3, flip the bits you get 0010 which is two.
This operation is a complement, not a negation.
Consider that ~0 = -1, and work from there.
The algorithm for negation is, "complement, increment".
Did you know? There is also "one's complement" where the inverse numbers are symmetrical, and it has both a 0 and a -0.
Simply speaking, ~ is to find the symmetric value (to -0.5).
~a and a should be symmetric to the mirror in the middle of 0 and -1.
-5,-4,-3,-2,-1 | 0, 1, 2, 3, 4
~0 == -1
~1 == -2
~2 == -3
~3 == -4
The reason for this is due to how computers represent negative values.
Say, if positive value uses 1 to count, negative value uses 0.
1111 1111 == -1
1111 1110 == -2; // add one more '0' to '1111 1111'
1111 1101 == -3; // add one more '0' to '1111 1110'
Finally, ~i == -(i+1).
Basically action is a complement not a negation .
Here x= ~x produce results -(x+1) always .
x = ~2
-(2+1)
-3
tl;dr ~ flips the bits. As a result the sign changes. ~2 is a negative number (0b..101). To output a negative number ruby prints -, then two's complement of ~2: -(~~2 + 1) == -(2 + 1) == 3. Positive numbers are output as is.
There's an internal value, and its string representation. For positive integers, they basically coincide:
irb(main):001:0> '%i' % 2
=> "2"
irb(main):002:0> 2
=> 2
The latter being equivalent to:
irb(main):003:0> 2.to_s
"2"
~ flips the bits of the internal value. 2 is 0b010. ~2 is 0b..101. Two dots (..) represent an infinite number of 1's. Since the most significant bit (MSB) of the result is 1, the result is a negative number ((~2).negative? == true). To output a negative number ruby prints -, then two's complement of the internal value. Two's complement is calculated by flipping the bits, then adding 1. Two's complement of 0b..101 is 3. As such:
irb(main):005:0> '%b' % 2
=> "10"
irb(main):006:0> '%b' % ~2
=> "..101"
irb(main):007:0> ~2
=> -3
To sum it up, it flips the bits, which changes the sign. To output a negative number it prints -, then ~~2 + 1 (~~2 == 2).
The reason why ruby outputs negative numbers like so, is because it treats the stored value as a two's complement of the absolute value. In other words, what's stored is 0b..101. It's a negative number, and as such it's a two's complement of some value x. To find x, it does two's complement of 0b..101. Which is two's complement of two's complement of x. Which is x (e.g ~(~2 + 1) + 1 == 2).
In case you apply ~ to a negative number, it just flips the bits (which nevertheless changes the sign):
irb(main):008:0> '%b' % -3
=> "..101"
irb(main):009:0> '%b' % ~-3
=> "10"
irb(main):010:0> ~-3
=> 2
What is more confusing is that ~0xffffff00 != 0xff (or any other value with MSB equal to 1). Let's simplify it a bit: ~0xf0 != 0x0f. That's because it treats 0xf0 as a positive number. Which actually makes sense. So, ~0xf0 == 0x..f0f. The result is a negative number. Two's complement of 0x..f0f is 0xf1. So:
irb(main):011:0> '%x' % ~0xf0
=> "..f0f"
irb(main):012:0> (~0xf0).to_s(16)
=> "-f1"
In case you're not going to apply bitwise operators to the result, you can consider ~ as a -x - 1 operator:
irb(main):018:0> -2 - 1
=> -3
irb(main):019:0> --3 - 1
=> 2
But that is arguably of not much use.
An example Let's say you're given a 8-bit (for simplicity) netmask, and you want to calculate the number of 0's. You can calculate them by flipping the bits and calling bit_length (0x0f.bit_length == 4). But ~0xf0 == 0x..f0f, so we've got to cut off the unneeded bits:
irb(main):014:0> '%x' % (~0xf0 & 0xff)
=> "f"
irb(main):015:0> (~0xf0 & 0xff).bit_length
=> 4
Or you can use the XOR operator (^):
irb(main):016:0> i = 0xf0
irb(main):017:0> '%x' % i ^ ((1 << i.bit_length) - 1)
=> "f"
here, 2 in binary(8 bit) is 00000010 and its 1's complement is 11111101, subtract 1 from that 1's complement we get 11111101-1 = 11111100, here the sign is - as 8th character (from R to L) is 1 find 1's complement of that no. i.e. 00000011 = 3 and the sign is negative that's why we get -3 here.
It's easy:
Before starting please remember that
1 Positive numbers are represented directly into the memory.
2. Whereas, negative numbers are stored in the form of 2's compliment.
3. If MSB(Most Significant bit) is 1 then the number is negative otherwise number is
positive.
You are finding ~2:
Step:1 Represent 2 in a binary format
We will get, 0000 0010
Step:2 Now we have to find ~2(means 1's compliment of 2)
1's compliment
0000 0010 =================> 1111 1101
So, ~2 === 1111 1101, Here MSB(Most significant Bit) is 1(means negative value). So,
In memory it will be represented as 2's compliment(To find 2's compliment first we
have to find 1's compliment and then add 1 to it.)
Step3: Finding 2's compliment of ~2 i.e 1111 1101
1's compliment Adding 1 to it
1111 1101 =====================> 0000 0010 =================> 0000 0010
+ 1
---------
0000 0011
So, 2's compliment of 1111 1101, is 0000 0011
Step4: Converting back to decimal format.
binary format
0000 0011 ==============> 3
In step2: we have seen that the number is negative number so the final answer would
be -3
So, ~2 === -3
Here is a way it can be explained :
let's take the case of why ~2 = -3,(explained using the 8-bit system for simplicity)
1)we've 2 ---> 00000010
2)we can get ~2 ---> 11111101 #by simply switching the bits.
[but the common mistake is that some try to convert the binary value of ~2 obtained directly to decimal(base 10) numbers, in this case, it's 253. This is not how we find complements.]
3)now we find a binary number which on adding to the binary value of 2~ gives 0 (00000000) as the result. In this case, it is 00000011 (which is 3), since if we add 00000011 to 11111101 that we have, we get 100000000, but since we are using the 8-bit system and the 1 is in the 9th position, it is ignored completely, so we end up with 00000000.
4)From point (3) we can say ~2+3 = 0, and hence we can say, ~2 = -3
Note: The value of -3 is simply 11111101 and can be explained in the same way.