I just started reading Hacker\'s Delight and it defines abs(-231) as -231. Why is that?
I tried printf(\"%x\", abs(0x80000000))
on a f
Obviously, mathematically, |−231| is 231. If we have 32 bits to represent integers, we can represent at most 232 numbers. If we want a representation that is symmetric about 0, we have a few decisions to make.
For the following, as in your question, I am assuming 32-bit wide numbers. At least one bit pattern must be used for 0. So that leaves us with 232−1 or less bit patterns for the rest of the numbers. This number is odd, so we can either have a representation that's not exactly symmetric about zero, or have one number be represented with two different representations.
0x80000000
is "negative zero" (i.e., zero), and 0x00000000
is "positive zero" or regular zero. In this scheme, the most positive number is 0x7fffffff
(2147483647) and the most negative number is 0xffffffff
(−2147483647). This scheme has the advantage that it is easy for us to "decode", and that it is symmetric. This scheme has a disadvantage in that calculating a + b
when a
and b
are of different signs is a special case, and has to be dealt with specially.0x7fffffff
(2147483647), and the maximum negative number is 0x80000000
(−2147483647). There are again two representations of 0: positive zero is 0x00000000
and negative zero is 0xffffffff
. This scheme also has issues with calculations involving negative numbers.1
to it. In this scheme, there is only one 0, namely 0x00000000
. The most positive number is 0x7fffffff
(2147483647) and the most negative number is 0x80000000
(−2147483648). There is an asymmetry in this representation. The advantage of this scheme is that one doesn't have to deal with special cases for negative number. The representation takes care of giving you the right answer as long as the result doesn't overflow. For this reason, most of the current hardware represents integers in this representation.In two's complement representation, there is no way to represent 231. In fact, if you look at your compiler's limits.h
or equivalent file, you might see a definition for INT_MIN
in such a way:
#define INT_MIN (-2147483647 - 1)
This done rather than
#define INT_MIN -2147483648
because 2147483648 is too large to fit in an int
in a 32-bit two's complement representation. By the time the unary minus operator "gets" the number to operate on, it is too late: overflow has already occurred and you can't fix it.
So, to answer your original question, the absolute value of the most negative number in a two's complement representation cannot be represented in that encoding. Also, from the above, to get from a negative value to a positive value in two's complement representation, you take its ones' complement and then add 1. So, for 0x80000000
:
1000 0000 0000 0000 0000 0000 0000 0000 original number
0111 1111 1111 1111 1111 1111 1111 1111 ones' complement
1000 0000 0000 0000 0000 0000 0000 0000 + 1
you get the original number back.