Digits in binary have a "weight" of 2
n, where n is the bit number.
So...
1 2 3 4 5 6 7 8
|
bit n -> weight
___________________
bit 0 -> 2^0 -> 1
bit 1 -> 2^1 -> 2
bit 2 -> 2^2 -> 4
bit 3 -> 2^3 -> 8
...
bit 7 -> 2^7 -> 128
|
You can calculate the value of any given binary number by summing the weight of the bits that are set.
Example:
1 2 3 4 5 6 7 8 9 10 11 12
|
00100100
^ ^
| |
| bit 0
bit 7
Here, bits 2 and 5 are set
Therefore the value is:
2^2 + 2^5
4 + 32
36
|
Signed 2's compliment numbers work the exact same way. The only difference is the weight of the highest bit is negative. So, with a 16 bit number, the highest bit is bit 15, so it would have a weight of -(2^15)
Another example (8-bit to keep it simple, but the same concept applies to 16-bit, just use bit 15 as the high bit instead of bit 7):
1 2 3 4 5 6 7 8 9 10 11 12
|
10000010
^ ^
| |
| bit 0
bit 7
Here, bits 1 and 7 are set
Therefore the value is:
2^1 + -(2^7)
2 - 128
-126
|
-------------------------------------
Alternatively, (and likely more simply).... if you have an
unsigned 16-bit number and you want to make it signed, there's some bit magic you can do:
1 2 3 4 5 6
|
int foo = some_unsigned_16_bit_number;
// make it signed:
foo = (foo ^ 0x8000) - 0x8000;
// now it's signed!
|
EDIT:
If you want an explanation of how that bit magic works...
The XOR operator (^) will toggle bit 15.
So if the number is positive, bit 15 is clear, which means the ^ operator will set it. Then we immediately subtract bit 15, so the value remains unchanged.
But if the number is negative, bit 15 is set, which means the ^ operator will clear it. At which point, when we subtract bit 15, we're effectively replacing the original positive weight of that bit, and replacing it with a negative weight.