How to subtract two unsigned ints with wrap around or overflow

后端 未结 8 2009
星月不相逢
星月不相逢 2020-12-08 21:07

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, af

相关标签:
8条回答
  • 2020-12-08 21:31

    Maybe I don't understand, but what's wrong with:

    unsigned r = x - y;

    0 讨论(0)
  • 2020-12-08 21:36

    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.)

    0 讨论(0)
  • 2020-12-08 21:42

    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
    
    0 讨论(0)
  • 2020-12-08 21:47

    The question, as stated, is confusing. 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.

    0 讨论(0)
  • 2020-12-08 21:48

    This is an efficient way to determine the amount of free space in a circular buffer or do sliding window flow control. Use unsigned ints for head and tail - increment them and let them wrap! Buffer length has to be a power of 2.

    free = ((head - tail) & size_mask), where size_mask is 2^n-1 the buffer or window size.

    0 讨论(0)
  • 2020-12-08 21:51

    The problem should be stated as follows:

    Let's assume the position (angle) of two pointers a and b of a clock is given by an uint8_t. The whole circumerence is devided into the 256 values of an uint8_t. How can the smaller distance between the two pointer be calculated efficiently?

    A solution is:

    uint8_t smaller_distance = abs( (int8_t)( a - b ) );

    I suspect there is nothing more effient as otherwise there would be something more efficient than abs().

    0 讨论(0)
提交回复
热议问题