How to calculate the absolute difference of two unsigned integers?

273 views Asked by At

How can one prevent overflow when calculating the absolute of the difference of two unsigned integers?

The result must be an unsigned integer as well (actually independent of the processer, as it will mathematically be just a number between 0 and MAXINT).

unsigned int a;
unsigned int b;

abs(a-b);

But this only works if b<=a, otherwise a-b<0 and will then overflow, and taking abs later will not help.

What is the easiest, overflow-safe way of doing that calculation?

(Actually I want to test if |a-b|<c where c is some constant. So, one could check a-bb and b-aa.)

2

There are 2 answers

3
pas-calc On

Thanks to the answers in the comments, one sees a simple solution can be accomplished like that using case differentiation.

unsigned int uint_diff(unsigned int a, unsigned int b){
  if (a > b){
    return (a - b);
  }
  else {
    return (b - a);
  }
}
0
Adrian Mole On

You can use a simple cast if a long long signed int is larger than an unsigned int on your platform. It probably will be but the Standard does allow int, long and long long to be the same size. (Note: I specifically used long long because on some common platforms – like MSVC/Windows – long int is the same size as int, as also for the unsigned versions.)

Here's a version that uses constexpr if (compile-time) checks and, if neither of the casts will work, falls back on the simpler, test-first solution:

#include <iostream>
#include <cmath>

unsigned int unsint_diff(unsigned int a, unsigned int b)
{
    if constexpr (sizeof(long int) > sizeof(unsigned int)) {
        return static_cast<unsigned int>
            (std::abs(static_cast<long signed int>(a) - static_cast<long signed int>(b)));
    }
    else if constexpr (sizeof(long long int) > sizeof(unsigned int)) {
        return static_cast<unsigned int>
            (std::abs(static_cast<long long signed int>(a) - static_cast<long long signed int>(b)));
    }
    else {
        return (a > b) ? a - b : b - a;
    }
}

int main()
{
    unsigned int i = 123456789u;
    unsigned int j = 987654321u;
    std::cout << unsint_diff(i, j) << "\n";
    std::cout << unsint_diff(j, i) << "\n";
    return 0;
}

Note that you need the casts on both operands of the subtraction because, if the size comparisons are not 'successful', then the call to std::abs will be using an unsigned int argument – which is ambiguous and, thus, the code is ill-formed (and that isn't allowed, even in the body of an if constexpr statement that won't actually be used).