5

I have got two signed integers, and I would like to subtract them. I need to know if it overflowed.

int one;
int two;
int result = two - one;

if (OVERFLOW) {
    printf("overflow");
} else {
    printf("no overflow");
}

Something like that. Is there a good way to do this?

1

5 Answers 5

15

You need to catch the overlow (or underflow) before it happens. Once it happens you're in Undefined Behaviour land and all bets are off.

#include <limits.h>
#include <stdio.h>

int sum_invokes_UB(int a, int b) {
  int ub = 0;
  if ((b < 0) && (a < INT_MIN - b)) ub = 1;
  if ((b > 0) && (a > INT_MAX - b)) ub = 1;
  return ub;
}

int main(void) {
  printf("(INT_MAX-10) + 8: %d\n", sum_invokes_UB(INT_MAX - 10, 8));
  printf("(INT_MAX-10) + 100: %d\n", sum_invokes_UB(INT_MAX - 10, 100));
  printf("(INT_MAX-10) + INT_MIN: %d\n", sum_invokes_UB(INT_MAX - 10, INT_MIN));
  printf("100 + INT_MIN: %d\n", sum_invokes_UB(100, INT_MIN));
  printf("-100 + INT_MIN: %d\n", sum_invokes_UB(-100, INT_MIN));
  printf("INT_MIN - 100: %d\n", sum_invokes_UB(INT_MIN, -100));
  return 0;
}
Sign up to request clarification or add additional context in comments.

2 Comments

Your example is for unsigned integer. a-b > MAX and a-b < MIN will never give a > MAX -b, unless a + b > MAX.
@Jay-Pi: no, my example is for signed integer. Unsigned integer atithmetic doesn't, strictly speaking, cause UB. Suppose you're calculating Fibonacci numbers on a 8-bit computer: 0 1 1 2 3 5 8 13 21 34 55 89 now what??? If you calculate 55+89 you invoke UB (MAX being 127)... but you can test if it's safe 55 > 127 - 89
7

Firstly, overflow in signed calculations causes undefined behavior in C.

Secondly, forgetting about UB for a second and sticking to the typical overflow behavior of a 2's complement machine: overflow is revealed by the fact that result "moves" in the "wrong direction" from the first operand, i.e when the result ends up greater than the first operand with positive second operand (or smaller than the first operand with negative second operand).

In your case

int one, two;

int result = two - one;
if ((result < two) != (one > 0))
  printf("overflow");

7 Comments

If int result = two - one; overflows (or underflows) you're in Undefined Behaviour land and anything can happen.
Which is what stated explicitly in the very first sentence of my response. (Although the term "underflow" in its traditional meaning is not applicable here.)
I like this answer but as you noted - undefined behaviour. If is safe to assume that the result will 'move' in the 'wrong direction'?
My point is that your if is not reliable. After the operation on the line before, if there was overflow, the result of the comparison is meaningless.
@pmg: Think of it as a solution specifically intended for implementations that extend C language specification by defining the signed integer overflow behavior in the way implied in my answer.
|
1

There are 2 cases to consider on evaluating a-b:

  1. a-b may underflow, iff b>0 && a<0 and a-b < min == a<min+b
  2. a-b may overflow, iff b<0 && a>0 and a-b > max == -b>max-a

This leads us on simplifying the a case to

#include <limits.h>

int sub_invokes_UB(int a, int b) {
  if ((b > 0) && (a < INT_MIN + b)) return 1; // error
  if ((b < 0) && (a > INT_MAX + b)) return 1; // error
  return 0; // ok
}

Comments

0

You can do it with higher precision and compare. Say you have 32-bit integers. You can promote them to 64-bit integers, subtract, then compare that result with itself cast to 32-bit and then up again to 64 bits.

I wouldn't do it this way with int, because the language doesn't give you guarantees on sizes... Maybe int32_t and int64_t from <inttypes.h> (from C99).

If you're on Windows use can use ULongSub() etc, which returns an error code on overflow.

1 Comment

If I do this case in 32 bit: 0x7fffffff - 0x80000000 = 0xffffffff In 64 bit I get 0xffffffffffffffff and thus i see no overflow (it should be, though. that's the wrong answer).
-1

https://llvm.org/doxygen/MathExtras_8h_source.html

/// Subtract two signed integers, computing the two's complement truncated
/// result, returning true if an overflow ocurred.
template <typename T>
std::enable_if_t<std::is_signed<T>::value, T> SubOverflow(T X, T Y, T &Result) {
  #if __has_builtin(__builtin_sub_overflow)
    return __builtin_sub_overflow(X, Y, &Result);
  #else
    // Perform the unsigned addition.
    using U = std::make_unsigned_t<T>;
    const U UX = static_cast<U>(X);
    const U UY = static_cast<U>(Y);
    const U UResult = UX - UY;
 
    // Convert to signed.
    Result = static_cast<T>(UResult);
 
    // Subtracting a positive number from a negative results in a negative number.
    if (X <= 0 && Y > 0)
      return Result >= 0;
    // Subtracting a negative number from a positive results in a positive number.
    if (X >= 0 && Y < 0)
      return Result <= 0;
    return false;
  #endif
}

2 Comments

Not the person who downvoted but the question was in C and your answer is in C++.
Who said C++ in this question?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.