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 few different systems and I get back 0x80000000 on all of them.
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 few different systems and I get back 0x80000000 on all of them.
For a 32bit datatype there is no expression of +2^31, because the biggest number is 2^31-1 ... read more about the two's complement ...
Because integers are stored in memory as a two's complement binary number, the positive version of the minimum value overflows back to negative.
That is to say (in .NET, but still applies):
int.MaxValue + 1 == int.MinValue // Due to overflow.
And
Math.Abs((long)int.MinValue) == (long)int.MaxValue + 1
This goes back to how numbers are stored.
Negative numbers are stored using two's complement. The algorithm goes like ...
Flip all the bits, then add 1.
Using eight bit numbers for examples ...
+0 = -0
00000000 -> 11111111, 11111111 + 1 = 100000000
(but due to limitation of bits, this becomes 00000000).
AND...
-128 [aka -(2^7)] equals -(-128)
10000000 -> 01111111, 01111111 + 1 = 10000000
Hope this helps.
Actually, in C, the behavior is undefined. From the C99 standard, §7.20.6.1/2:
The
abs
,labs
, andllabs
functions compute the absolute value of an integerj
. If the result cannot be represented, the behavior is undefined.
and its footnote:
The absolute value of the most negative number cannot be represented in two’s complement.
I think the way abs
works is to first check the sign bit
of the number. If its clear do nothing as the number is already +ve
else return the 2's complement
of the number. In your case the number is -ve
and we need to find its 2's complement
. But 2's complement of 0x80000000
happens to be 0x80000000
itself.
The representation of a two's complement number has the most significant bit as a negative number. 0x80000000 is 1 followed by 31 zeroes, the first 1 represents -2^31 not 2^31. Therefore there is no way to represent 2^31 as the highest positive number is 0x7FFFFFFF, which is 0 followed by 31 ones, which equals 2^31-1.
abs(0x80000000) is therefore undefined in the two's complement since it is too large, due to this the machine just gives up and gives you 0x80000000 again. Typically at least.
0x8000.. is stored as 10000.... (binary). This is known as twos complement, which means that the highest bit (the one at the left) is used to store the sign of the value and negative values are stored with negative binary - 1. The abs() function now checks the signbit, sees that it is set and computes the positive value.
Now this is a negative number again which we didn't want, the reason is a overflow, try the number 0x9000... which is 10010...
With this number the overflow is stopped by the 0 bit on the right
because it uses the neg instruction to perform this operation.
In the Art of Assembly language programming book they said like this.
If the operand is zero, its sign does not change, although this clears the carry flag. Negating any other value sets the carry flag. Negating a byte containing -128, a word containing -32,768, or a double word containing -2,147,483,648 does not change the operand, but will set the overflow flag. Neg always updates the A, S, P, and Z flags as though you were using the sub instruction
source :http://www.arl.wustl.edu/~lockwood/class/cs306/books/artofasm/Chapter_6/CH06-2.html#HEADING2-313 So it will set the overflow flag and be silently.That's the reason.