-3
int main(){
unsigned int num1 = 0x65764321; 
unsigned int num2 = 0x23657432;
unsigned int sum = num1 + num2;
cout << hex << sum;
return 0;
}

If i have two unsigned integers say num1 and num2. And then I tell the computer to unsigned

int sum = num1 + num2; 

What method does the computer use to add them, would it be two's complement. Would the sum variable be printed in two's complement.

iamsankalp89
  • 4,607
  • 2
  • 15
  • 36
  • 5
    Two's complement makes no sense in the context of unsigned numbers. – Jester Aug 25 '17 at 13:11
  • The computer will not do anything to add them, because the shown code is undefined behavior. – Sam Varshavchik Aug 25 '17 at 13:12
  • @jester then what would the printed sum be in, 2s complement or unsigned – Sahil Kumar Aug 25 '17 at 13:13
  • You declared everything unsigned. Obviously the calculation and the result will be unsigned too. – Jester Aug 25 '17 at 13:16
  • 2
    @SamVarshavchik `unsigned` overflow is well defined. – nwp Aug 25 '17 at 13:18
  • @jester now the overflow flag here is 1(its an example given by our instructor) meaning there is overflow but there is no carry, so how can there be overflow here – Sahil Kumar Aug 25 '17 at 13:19
  • 2
    I assume your instructor is talking about the cpu flag for x86, and that is set because x86 only has one addition that does both signed and unsigned at the same time. It's up to you (or the compiler) to use the appropriate flag. PS: it has no effect on the result though. – Jester Aug 25 '17 at 13:20
  • 2
    @nwp, the text of the question changed after some comments..@SamVarshavchik was right at that time.. – Stefano Buora Aug 25 '17 at 13:21
  • @Sahil Kuma: There is no undefined behavior here, unsigned integer arithmetic is well-defined in `C++` and will yield the expected result modulo `UINT_MAX+1`. The `num1` and `num2` variables may be truncated in the assignment on platforms with integers narrower than 32-bits however, potentially resulting on overflow during the addition as well depending on the particular integer width used. – doynax Aug 25 '17 at 13:23
  • Whether or not this question should be closed, this does not appear to be a duplicate of unsigned overflow to me. – eerorika Aug 25 '17 at 13:37
  • Please describe properly – iamsankalp89 Aug 25 '17 at 14:40
  • `0x65764321 + 0x23657432 = 0x88DBB753` ... a method used to add depends on CPU, but AFAIK every CPU (classic digital one on silicon die) so far produced does add all the bits together starting from lowest ones, carrying over to upper bit when the result is bigger than 1 for particular bit. If you will then [`reinterpret_cast`](http://en.cppreference.com/w/cpp/language/reinterpret_cast) `sum` from `unsigned` to `signed`, it will be equal to `-1998866605` (as long as we are talking about 32 bit signed/unsigned types, in case of 64b types the 0x88DBB753 will be still 2296100691 even as signed). – Ped7g Aug 25 '17 at 17:03
  • Also I'm not sure how much that reinterpretation is stable by C++ standard, I'm not C++ guru, but most of the common platforms (x86, ARM, MIPS) will do this. But I guess it may be implementation specific, not defined/required by C++ standard? – Ped7g Aug 25 '17 at 17:06
  • 1
    @ped7g: actual CPUs do something that produces the same result as a simple ripple-carry adder, but with lower latency. One common thing is [carry-lookahead](https://en.wikipedia.org/wiki/Carry-lookahead_adder), which works in smaller chunks and then fixes up the carry. It's incorrect to say that actual silicon just starts from the lowest bits. – Peter Cordes Aug 25 '17 at 17:12
  • @Ped7g: Your `reinterpret_cast` example is assuming a C++ implementation that uses two's complement signed integers. One's complement and sign/magnitude are the other possibilities allowed by the C++ standard (and I think it also allows padding and stuff in signed integers, so it might not be guaranteed that `signed int` is the same number of bytes as `unsigned int`, and maybe the highest bit doesn't end up in the sign bit. This question isn't tagged [tag:x86], so talking about C++ stuff shouldn't assume 2's complement. – Peter Cordes Aug 25 '17 at 17:15
  • ok ... so then the result is same, so "in principle" ;) ... I should never ever comment on HW again (fair, as I know nothing about it) ... about two's complement: well, sure, that's why I added specific CPUs where it will reinterpret it like that. You at least made clear it's not standardized/required behaviour. – Ped7g Aug 25 '17 at 17:15

2 Answers2

3

2's complement addition is identical to unsigned addition as far the actual bits are concerned. In the actual hardware, the design will be something complicated like a https://en.wikipedia.org/wiki/Carry-lookahead_adder, so it can be low latency (not having to wait for the carry to ripple across 32 or 64 bits, because that's too many gate-delays for add to be single-cycle latency.)

One's complement and sign/magnitude are the other signed-integer representations that C++ allows implementations to use, and their wrap-around behaviour is different from unsigned.

For example, one's complement addition has to wrap the carry-out back into the low bit. See this article about optimizing TCP checksum calculation for how you implement one's complement addition on hardware that only provide 2's complement / unsigned addition. (Specifically x86).

C++ leaves signed overflow as undefined behaviour, but real one's complement and sign/magnitude hardware does have specific documented behaviour. reinterpret_casting an unsigned bit pattern to a signed integer gives a result that depends on what kind of hardware you're running on. (All modern hardware is 2's complement, though.)


Since the bitwise operation is the same for unsigned or 2's complement, it's all about how you interpret the results. On CPU architectures like x86 that set flags based on the results of an instruction, the overflow flag is only relevant for the signed interpretation, and the carry flag is only relevant for the unsigned interpretation. The hardware produces both from a single instruction, instead of having separate signed/unsigned add instructions that do the same thing.

See http://teaching.idallen.com/dat2343/10f/notes/040_overflow.txt for a great write-up about unsigned carry vs. signed overflow, and x86 flags.


On other architectures, like MIPS, there is no FLAGS register. You have to use a compare or test instruction to figure out what happened (carry or zero or whatever). The add instruction doesn't set flags. See this MIPS Q&A about add-with-carry for a 64-bit add on 32-bit MIPS.

But for detecting signed overflow, add raises an exception on overflow (where x86 would set OF), so you use addu for signed or unsigned addition if you want it to not fault on signed overflow.


now the overflow flag here is 1(its an example given by our instructor) meaning there is overflow but there is no carry, so how can there be overflow here

You have a C++ program, not an x86 assembly language program! C++ doesn't have a carry or overflow flag.

If you compiled this program for x86 with a non-optimizing compiler, and it used the ADD instruction with your two inputs, you would get OF=1 and CF=0 from that ADD instruction.

But the compiler might use lea edi, [rax+rdx] to do the sum without overwriting either input, and LEA doesn't set flags.

Or if the compiler did the addition at compile time, your code would compile the same as source like this:

cout << hex << 0x88dbb753U;

and no addition of your numbers would take place at run-time. (There will of course be lots of addition in the iostream library functions, and maybe even an add instruction in main() as part of making a stack frame, if your compiler chooses to emit code that sets up a stack frame.)

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
1

i have two unsigned integers

What method does the computer use to add them

Whatever method is available on the target CPU architecture. Most have an instruction named ADD.

Would the sum variable be printed in two's complement.

Two's complement is a way to represent an integer type in binary. It is not a way to print numbers.

Community
  • 1
  • 1
eerorika
  • 232,697
  • 12
  • 197
  • 326
  • It's not undefined behavior. The result of `num1 + num2` is unpredictable. but the program behaves normal. – user1810087 Aug 25 '17 at 13:15
  • 1
    @user1810087 standard says otherwise. (unless the type is narrow character type) – eerorika Aug 25 '17 at 13:16
  • 1
    2's complement is used to represent _negative_ numbers. It uses the left-most bit to indicate sign. Hence this bit cannot be used anymore to represent positive numbers. There is no "2's complement" for positive numbers. – Paul Ogilvie Aug 25 '17 at 13:18
  • @user2079303 If so, can you show me where? Because i don't think calculating to unsigned numbers is undefined behavior. – user1810087 Aug 25 '17 at 13:18
  • @user1810087 `[dcl.init] §12` (number may vary depending on version of standard) *"If an indeterminate value is produced by an evaluation, the behavior is undefined except in the following cases:"* All of the exceptions involve the narrow character type. – eerorika Aug 25 '17 at 13:21
  • @user2079303: Can you help parse that out a bit for us? The paragraph quoted seemingly refers to uninitialized variables and it is not apparent how unsigned integer overflow results constitutes indeterminate values. – doynax Aug 25 '17 at 13:31
  • @doynax our discussion is about [an earlier version of the question](https://stackoverflow.com/revisions/45882221/1) (and correspondlingly, earlier version of my answer) – eerorika Aug 25 '17 at 13:32
  • Instead of saying *Two's complement is binary representation of signed numbers* how about *Two's complement is a way to represent a integer type in binary*? – NathanOliver Aug 25 '17 at 13:55
  • @NathanOliver I used your suggestion, thanks. I find it difficult to find a wording that does not mislead a beginner, without going into too much detail. – eerorika Aug 25 '17 at 13:58
  • @user2079303 No problem. Thanks for updating. – NathanOliver Aug 25 '17 at 13:59