In a TC++ compiler, the binary representation of 5 is (00000000000000101). I know that negative numbers are stored as 2's complement, thus -5 in binary is (111111111111011). The most significant bit (sign bit) is 1 which tells that it is a negative number.
So how does the compiler know that it is -5? If we interpret the binary value given above (111111111111011) as an unsigned number, it will turn out completely different?
Also, why is the 1's compliment of 5 -6 (1111111111111010)?
The compiler doesn't know. If you cast -5
to unsigned int
you'll get 32763
.
The compiler knows because this is the convention the CPU uses natively. Your computer has a CPU that stores negative numbers in two's complement notation, so the compiler follows suit. If your CPU supported one's complement notation, the compiler would use that (as is the case with IEEE floats, incidentally).
The Wikipedia article on the topic explains how two's complement notation works.
The processor implements signed and unsigned instructions, which will operate on the binary number representation differently. The compiler knows which of these instructions to emit based on the type of the operands involved (i.e. int
vs. unsigned int
).
The compiler doesn't need to know if a number is negative or not, it simply emits the correct machine or intermediate language instructions for the types involved. The processor or runtime's implementation of these instructions usually doesn't much care if the number is negative or not either, as the formulation of two's complement arithmetic is such that it is the same for positive or negative numbers (in fact, this is the chief advantage of two's complement arithmetic). What would need to know if a number is negative would be something like printf()
, and as Andrew Jaffe pointed out, the MSBit being set is indicative of a negative number in two's complement.
The first bit is set only for negative numbers (it's called the sign bit)
Detailed information is available here
The kewl part of two's complement is that the machine language Add, and Subtract instructions can ignore all that, and just do binary arithmetic and it just works...
i.e., -3 + 4
in Binary 2's complement, is
1111 1111 1111 1101 (-3)
+ 0000 0000 0000 0100 ( 4)
-------------------
0000 0000 0000 0001 ( 1)
let us give an example: we have two numbers in two bytes in binary: A = 10010111 B = 00100110 (note that the machine does not know the concept of signed or unsigned in this level)
now when you say "add" these two, what does the machine? it simply adds:
R = 10111101 (and carry bit : 1)
now, we -as compiler- need to interpret the operation. we have two options: the numbers can be signed or unsigned.
1- unsigned case: in c, the numbers are of type "unsigned char" and the values are 151 and 38 and the result is 189. this is trivial.
2 - signed case: we, the compiler, interpret the numbers according to their msb and the first number is -105 and the second is still 38. so -105 + 38 = -67. But -67 is 10111101. But this is what we already have in the result (R)! The result is same, the only difference is how the compiler interprets it.
The conclusion is that, no matter how we consider the numbers, the machine does the same operation on the numbers. But the compiler will interpret the results in its turn.
Note that, it is not the machine who knows the concept of 2's complement. it just adds two numbers without caring the content. The compiler, then, looks at the sign bit and decides.
When it comes to subtraction, this time again, the operation is unique: take 2's complement of the second number and add the two.
If the number is declared as a signed data type (and not type cast to an unsigned type), then the compiler will know that, when the sign bit is 1, it's a negative number. As for why 2's complement is used instead of 1's complement, you don't want to be able to have a value of -0, which 1's complement would allow you to do, so they invented 2's complement to fix that.
It's exactly that most significant bit -- if you know a number is signed, then if the MSB=1 the compiler (and the runtime!) knows to interpret it as negative. This is why c-like languages have both integers (positive and negative) and unsigned integers -- in that case you interpret them all as positive. Hence a signed byte goes from -128 to 127, but an unsigned byte from 0 to 255.
来源:https://stackoverflow.com/questions/655257/twos-complement-binary-form