0

My number type is a signed two’s complement integer.

In memory registers %rdi/edi/di, I have 0xFFFFFFFF. In %rsi/esi/si, I have 0x80000000.

My instruction is addl %edi, %esi.

How do I properly add these?

I think the answer is:

Since I'm adding the full 32-bit register, I have the benefit of adding the full amounts 0xFFFFFFFF and 0x80000000.

So, I have a signed integer added to a signed, and they are both 32-bit. I am effectively adding -2147483648 and 0x80000000. Since 0x80000000 is 2147483648 in hexadecimal, I add these two and I get zero.

The Zero Flag is activated The Carry Flag is activated (since I am adding the leading value of the 32 bit register)

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
The_Senate
  • 149
  • 6
  • In two's compliment 0x800....... is negative zero. When you compliment negative zero you always get negaive zero. The largest negative number is 0x80000001. – jdweng Oct 20 '18 at 13:46
  • 4
    @jdweng 0x80000000 is -2147483648, there is no negative zero. This seems familiar, haven't I told you this before? – harold Oct 20 '18 at 13:47
  • @jdweng Is it negative "zero", or -2147483648 ? – The_Senate Oct 20 '18 at 13:48
  • Call it what ever you want. If you do a two's compliment on the number you get the same results. I was taught the number was call negative zero. You can call it anything else you want. It is not a valid two's compliment number. – jdweng Oct 20 '18 at 13:55
  • 4
    @jdweng: 0x80000000 is not negative zero. In unsigned binary, it would represent 2147483648. A bit pattern that represents x in unsigned binary and has its high bit on represents x−2^n in n-bit two’s complement, so 0x80000000 represents 2147483648−2^32, which is −2147483648. – Eric Postpischil Oct 20 '18 at 14:10
  • 3
    @jdweng This is a new low, arguing against all evidence, that negative zero is a thing with two's complement integer representations. – David Heffernan Oct 22 '18 at 18:08
  • 2
    @DavidHeffernan I keep telling you guys he's a menace! – The_Senate Oct 22 '18 at 23:59
  • 3
    @The_Senate I know but there's nothing we can do beyond refuting any blatantly false statements – David Heffernan Oct 23 '18 at 06:11
  • To heck with that, he's a menace! I want pictures! – The_Senate Oct 23 '18 at 10:56
  • @jdweng two's complement (**not** compliment) [is a ring](https://en.wikipedia.org/wiki/Signed_number_representations#Two's_complement), so definitely all representable values are valid. Sign-extending 0x80000000 always result in -2147483648 in any longer bit width and not -0. Math operations on it also results in the correct value (except `-2147483648/1` and `abs(-2147483648)` which needs a longer type) – phuclv Oct 28 '18 at 02:52
  • You cannot add two 32 bit signed integers and get the number -2147483648 nor do a 2's complement of a positive 32 bit number and get the number. You are creating vapor-ware. When you have hardware that implements 32 bit arithmetic you cannot just add bits that do no exist. Software can simulate anything they want. But hardware people cannot. – jdweng Oct 28 '18 at 07:21
  • @jdweng Sure? There are infinite number of 32-bit int expressions that can produce that value **without any overflow**: `-2147483647 - 1`, `(-2147483648 + 1) - 1`, `-2147483640 - 8`... Just check the overflow flag of your CPU or [`__builtin_sadd_overflow`](https://gcc.gnu.org/onlinedocs/gcc/Integer-Overflow-Builtins.html). It's also possible to check with [pure C code](https://stackoverflow.com/q/15920639/995714). Besides, if it were negative zero then `-(-2147483648)` should produce +0, and `-0 == +0` would be true like [in floating-point types](https://stackoverflow.com/q/45795397/995714) – phuclv Oct 31 '18 at 17:27
  • ... Unfortunately the former produces the **same value**, and the comparison obviously doesn't result in equality. Even the C standard defines [-2147483648 as `-2147483647 - 1` instead of `-0`](https://stackoverflow.com/q/26003893/995714). * nor do a 2's complement of a positive 32 bit number and get the number* well `(int)-2147483648U` results in -2147483648. *When you have hardware that implements 32 bit arithmetic you cannot just add bits that do no exist* There's no non-exist bits in 2's complement **Every 2's complement value maps to exact one value in unsigned**... – phuclv Oct 31 '18 at 17:29
  • ... results in total 2ⁿ values for both the signed and unsigned version of an n-bit type. And two's complement math wraps around exactly like what unsigned math does. There are even the [`-ftrapv` and `-fwrapv` flags in gcc to either wrap or trap on overflow](https://stackoverflow.com/a/3679149/995714). It's a mathematically proven thing like that [2's complement is a ring/cyclic group](https://en.wikipedia.org/wiki/Two%27s_complement#Most_negative_number) – phuclv Oct 31 '18 at 17:29
  • I won't go further when I bet you don't even understand what [methods of complement (which works for any bases)](https://en.wikipedia.org/wiki/Method_of_complements) mean and didn't even read proper documents about 2's complement: **Unlike ones' complement systems, two's complement has `no representation for negative zero`, and thus does not suffer from its associated difficulties.** – phuclv Oct 31 '18 at 17:30
  • You software people will never learn. – jdweng Oct 31 '18 at 18:17
  • You math is all wrong, 1) -2147483647 - 1 : how can you take the largest negative number and subtract 1. You will get an underflow error. 2) (-2147483648 + 1) - 1 : -2147483648 is negative zero which not a valid number in 2's compliment. 3) -2147483640 - 8 : this is the same as 1st item. It give an underflow. – jdweng Oct 31 '18 at 20:32
  • @jdweng Do you mean to say Zero Flag and the Negative Flag when you say "Negative Zero" ? Because Negative Zero makes no sense in any context. – The_Senate Oct 31 '18 at 23:26
  • The largest positive number you can have in 32 bit signed numbers is 2^31 - 1 which is 0x7FFFFFFF. The 32 bit is the sign bit. The largest negative number is the two compliment of the positive number which is 0x80000001. To get the twos compliment you invert every bit and add 1. The number of positive numbers (not including zero) and number of negative number should be equal. When you include zero that means there are an odd number of signed numbers. There is one additional number that is not part of the signed numbers which is 0x80000000, It is called negative zero. – jdweng Nov 01 '18 at 00:52
  • @jdweng: 2's complement does have a special number that is its own complement (i.e. `sub dst, 0, x` overflows to `x` with wraparound). This is called the *most negative number*, and is not equal to zero. https://en.wikipedia.org/wiki/Two%27s_complement#Most_negative_number. Yes it's a problem for some people that the result of abs needs to be unsigned to not overflow, but that's the way it is. Note the examples on https://en.cppreference.com/w/c/types/limits where the negative limit is larger magnitude than positive limit for 2's complement types. – Peter Cordes Dec 08 '20 at 15:59
  • @jdweng: Whoever taught you was wrong about calling it "negative zero", or they were talking about *one's* complement (or sign/magnitude). In sign/magnitude, `0x80000000` is negative zero. In one's complement, `0xffffffff` is negative zero. https://en.wikipedia.org/wiki/Signed_zero. In 2's complement, there is no negative zero, and there are more negative numbers than positive. x86 uses 2's complement. Please stop spreading misinformation about 2's complement; go find somewhere to talk about sign/magnitude integers that no CPUs use. – Peter Cordes Dec 08 '20 at 16:04
  • I'm looking from a hardware point of view. When you have a micro circuit that does the addition there is a zero bit that gets set when you add and get 0x80000000. The output is meant for adding another circuit to make the arithmetic larger. So if you have and 8 bit adder and want to make 16 bits you use two circuits. So the zero bit is active for a results of 0x80000000 since you may have another part and the sum is really 0x180000000. – jdweng Dec 08 '20 at 17:27

1 Answers1

4

In 32-bit two’s complement, 0xFFFFFFFF represents −1, and 0x80000000 represents −2,147,483,648. The sum of these is −2,147,483,649. That does not fit in 32 bits, so it overflows. The computed result will be 0x7FFFFFFF, which represents 2,147,483,647.

At the bit-level: FFFFFFFF plus 80000000 produces 17FFFFFFF, which means 7FFFFFFF is stored in the 32-bit destination, and the 1 is a carry out.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • Ahhh okay, did the math incorrectly then. Thank you for correcting me. – The_Senate Oct 20 '18 at 13:50
  • Question: Since one is a "carry out" would that mean it is represented as : 1x7FFFFFFF ? – The_Senate Oct 20 '18 at 14:22
  • 1
    @The_Senate: The 32-bit register has no place for a 33rd bit. It is not placed in the destination. The carry-out bit in the flags register is set. “1x7FFFFFFF” is not a notation that is commonly used. The “0” in “0x12345678” does not stand for a zero bit; it is a notation forced by historical development of C. We might have used “hex 12345678” instead, if things had gone differently. – Eric Postpischil Oct 20 '18 at 14:24
  • "Not commonly used" implies that it is used, so if I'm reading this correctly, the '0' is a flag, not a bit? Does this mean that this computation we have discussed has a CF flag and an OF flag? – The_Senate Oct 20 '18 at 14:28
  • 3
    @The_Senate: It is not used anywhere I know of. No, the “0” is not a flag. They just wanted hexadecimal constants in the C language, and they could not start with a letter because anything starting with a letter was already an identifier, so it had to start with a number or a special character, and presumably they did not want to use a special character. At it cannot have just digits, because decimal numbers already used those. So they needed a digit and something else. I suppose somebody suggested “0x” and it stuck. It does not mean anything other than “here is a hexadecimal numeral.” – Eric Postpischil Oct 20 '18 at 14:39