Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to subtract two unsigned ints with wrap around or overflow

Tags:

There are two unsigned ints (x and y) that need to be subtracted. x is always larger than y. However, both x and y can wrap around; for example, if they were both bytes, after 0xff comes 0x00. The problem case is if x wraps around, while y does not. Now x appears to be smaller than y. Luckily, x will not wrap around twice (only once is guaranteed). Assuming bytes, x has wrapped and is now 0x2, whereas y has not and is 0xFE. The right answer of x - y is supposed to be 0x4.

Maybe,

( x > y) ? (x-y) : (x+0xff-y); 

But I think there is another way, something involving 2s compliment?, and in this embedded system, x and y are the largest unsigned int types, so adding 0xff... is not possible

What is the best way to write the statement (target language is C)?

like image 745
mgag Avatar asked Jan 13 '10 23:01

mgag


People also ask

Can unsigned subtraction overflow?

A computation involving unsigned operands can never overflow, because a result that cannot be represented by the resulting unsigned integer type is reduced modulo the number that is one greater than the largest value that can be represented by the resulting type.

What happens when you subtract two unsigned integers?

Subtracting two unsigned values of the same size will result in an unsigned value. If the first operand is less than the second the result will be arithmetically in correct.

What happens if you subtract 1 from unsigned int?

An unsigned is an integer that can never be negative. If you take an unsigned 0 and subtract 1 from it, the result wraps around, leaving a very large number (2^32-1 with the typical 32-bit integer size).

What is the behavior of an unsigned integer subtraction?

Well, an unsigned integer subtraction has defined behavior, also it is a tricky thing. When you subtract two unsigned integers, result is promoted to higher type int if result (lvalue) type is not specified explicitly. In the latter case, for example, int8_t result = a - b; (where a and b have int8_t type) you can obtain very weird behavior.

Which INTs need to be subtracted?

There are two unsigned ints (x and y) that need to be subtracted. x is always larger than y. However, both x and y can wrap around; for example, if they were both bytes, after 0xff comes 0x00.

How to subtract two integers with the same width?

Assuming two unsigned integers: If you know that one is supposed to be "larger" than the other, just subtract. If you don't know that one is larger than the other, subtract and cast the result to a signed int of the same width.

Can x-y wrap around or overflow when subtracting?

You said that you are subtracting unsigned values. If x is always larger than y, as you said, then x - y cannot possibly wrap around or overflow. So you just do x - y (if that's what you need) and that's it. Show activity on this post.


2 Answers

Assuming two unsigned integers:

  • If you know that one is supposed to be "larger" than the other, just subtract. It will work provided you haven't wrapped around more than once (obviously, if you have, you won't be able to tell).
  • If you don't know that one is larger than the other, subtract and cast the result to a signed int of the same width. It will work provided the difference between the two is in the range of the signed int (if not, you won't be able to tell).

To clarify: the scenario described by the original poster seems to be confusing people, but is typical of monotonically increasing fixed-width counters, such as hardware tick counters, or sequence numbers in protocols. The counter goes (e.g. for 8 bits) 0xfc, 0xfd, 0xfe, 0xff, 0x00, 0x01, 0x02, 0x03 etc., and you know that of the two values x and y that you have, x comes later. If x==0x02 and y==0xfe, the calculation x-y (as an 8-bit result) will give the correct answer of 4, assuming that subtraction of two n-bit values wraps modulo 2n - which C99 guarantees for subtraction of unsigned values. (Note: the C standard does not guarantee this behaviour for subtraction of signed values.)

like image 79
Matthew Slattery Avatar answered Oct 14 '22 09:10

Matthew Slattery


Here's a little more detail of why it 'just works' when you subtract the 'smaller' from the 'larger'.

A couple of things going into this…
1. In hardware, subtraction uses addition: The appropriate operand is simply negated before being added.
2. In two’s complement (which pretty much everything uses), an integer is negated by inverting all the bits then adding 1.

Hardware does this more efficiently than it sounds from the above description, but that’s the basic algorithm for subtraction (even when values are unsigned).

So, lets figure 2 – 250 using 8bit unsigned integers. In binary we have

  0 0 0 0 0 0 1 0   - 1 1 1 1 1 0 1 0 

We negate the operand being subtracted and then add. Recall that to negate we invert all the bits then add 1. After inverting the bits of the second operand we have

0 0 0 0 0 1 0 1   

Then after adding 1 we have

0 0 0 0 0 1 1 0   

Now we perform addition...

  0 0 0 0 0 0 1 0    + 0 0 0 0 0 1 1 0  = 0 0 0 0 1 0 0 0 = 8, which is the result we wanted from 2 - 250 
like image 26
Purdude Avatar answered Oct 14 '22 07:10

Purdude