31

Possible Duplicate:
How can I check if multiplying two numbers in Java will cause an overflow?

Suppose I have a Java class method, which uses * and + operations.

int foo(int a, int b) {
  ... // some calculations with + and * 
}

How to make sure that no overflow occurs in foo?

I guess I can either use BigDecimal or replace all + and * with "wrappers" like:

int sum(int a, int b) {
   int c = a + b;
   if (a > 0 && b > 0 && c < 0) 
     throw new MyOverfowException(a, b)
   return c;
}

int prod(int a, int b) {
   int c = a * b;
   if (a > 0 && b > 0 && c < 0) 
     throw new MyOverfowException(a, b)
   return c;
}

Are there better ways to make sure that no int overflow occurs in a Java method ?

Community
  • 1
  • 1
Michael
  • 41,026
  • 70
  • 193
  • 341
  • 3
    Why do you check if it is below zero? An int can go well below 0. – 11684 Sep 01 '12 at 09:40
  • To be precise, this is the range of an int: –2,147,483,648 to 2,147,483,647 – 11684 Sep 01 '12 at 09:41
  • You want to clamp the values? – huseyin tugrul buyukisik Sep 01 '12 at 09:41
  • @11684 I think he is confident `a` and `b` are positive integers, therefore if the result is negative an overflow occurred. – Duncan Jones Sep 01 '12 at 09:42
  • Whut?! Shouldn't an Exception be thrown? @DuncanJones – 11684 Sep 01 '12 at 09:45
  • @11684 You'd think that, but Java doesn't throw exceptions on integer overflow. See http://stackoverflow.com/a/3001879/474189 – Duncan Jones Sep 01 '12 at 09:47
  • @11684 you are right. I assume a and b positive. I will update the question. – Michael Sep 01 '12 at 09:48
  • This: http://stackoverflow.com/questions/3001836/how-does-java-handle-integer-underflows-and-overflows-and-how-would-you-check-fo/3001879#3001879 plus my previous comment answer your question, I believe. – 11684 Sep 01 '12 at 09:50
  • 2
    Note that your product function won't work even if `a` and `b` are both positive, as the result can overflow and still be positive, eg `1000000000 * 15 = 2115098112`. – verdesmarald Sep 01 '12 at 09:50
  • 1
    Unless you're actually using division, BigInteger would be better than BigDecimal. – MrLore Sep 01 '12 at 09:58
  • 1
    Sucks not having unsigned types, eh? But what do you want it to do if an overflow occurs? int by definition is bounded, and will eventually overflow with big enough a and b, no matter how hard you want it not to. Should it throw an exception if overflow occurs? Perhaps fall back to an overloaded version which uses BigInteger instead? – Thomas Sep 01 '12 at 12:06

4 Answers4

23

One way to check for an overflow is to have the operands promoted to a larger type (of double the original operand bit length) then perform the operation, and then see if the resulting value is too large for the original type, e.g.

int sum(int a, int b) {
    long r = (long)a + b;
    if (r >>> 32 != 0) {    // no sign extension
        throw new MyOverflowException(a, b);
    }
    return (int)r;
}

If your original type is a long, you'd have to use BigInteger as that larger type.

Alnitak
  • 334,560
  • 70
  • 407
  • 495
  • I know this answer is old, but this solution isn't guaranteed to work since the larger type itself can overflow and end up in a range that appears normal for the smaller type. – yitzih Aug 18 '16 at 15:56
  • @yitzih you're wrong - the addition of two (positive) integers cannot exceed a value any more than 1 bit longer than the longest operand. There's no way given the constraints of the question to end up with a "larger type itself overflow" – Alnitak Aug 19 '16 at 22:55
  • @yitzihI I forgot that multiplication is also involved, but there too, the product of two 31 bit positive integers cannot exceed 62 bits. – Alnitak Aug 19 '16 at 23:01
  • that's a fair point. My mistake, thank you for clarifying. – yitzih Aug 21 '16 at 05:51
20

It is a difficult problem from an engineering perspective.

The Secure Coding site recommends:

  • use of preconditions; i.e. range-check the inputs so that overflow is impossible,
  • doing each individual arithmetic operation using the next larger primitive integer type and explicitly checking for overflow, or
  • using BigInteger.

This Dr Dobbs article suggests creating a library of primitive arithmetic methods that do each primitive operation with an explicit overflow check. (You could view this as an implementation of bullet point #2 above.) But the authors go further by suggesting that you use bytecode rewriting to replace arithmetic bytecodes with calls to the equivalent methods which incorporate overflow checks.

Unfortunately, there is no way to enable overflow checking natively in Java. (But the same applies in lots of other languages; e.g. C, C++ ... )

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • the second of those is what my answer does – Alnitak Sep 01 '12 at 09:47
  • 2
    "It is a difficult problem from an engineering perspective." -- It's not that difficult: just generate machine code to check the overflow register flag after every operation. That's what the C# "checked" block does. The issue is that Java doesn't offer that as an option, not because it is beyond the wit of man. – Rich Jan 21 '14 at 10:22
  • 1
    @Rich - it is difficult if you are not in a position to modify the Java compiler. Most people aren't! – Stephen C Jan 21 '14 at 11:15
  • 1
    lol, good point :-) It's frustrating that this wasn't included in the Java compiler. There isn't a nice easy answer (which is also correct) on this question or it's duplicate :-( – Rich Jan 21 '14 at 11:18
  • http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/math/IntMath.html#checkedAdd(int, int) – Rich Jan 21 '14 at 11:19
7

Sum: Check whether b is larger than the difference of the maximum value you can store in int minus the value of a. If a and/or b can be negative, you must (i) be careful not to get an overflow already for the difference check and (ii) perform a similar check for the minimum.

Product: Thats more difficult. I would split the integers into two half-length integers (i.e. if int is 32 bit, split it into two 16 bit numbers using bit-masking and shifting). Then do the multiplication, and then look whether the result fits into 32 bit.

Everything under the condition that you do not want to simply take long for the temporary result.

JohnB
  • 13,315
  • 4
  • 38
  • 65
3

Suppose both a and b are positive or negative, and if the sign of a + b is not equal with the sign of a and b, then overflow happens. You can use this rule to judge whether overflow happens and throw an exception. When you catch this expcetion, you can deal it according to the method metioned in previous answers. Another method is to doing operation using largest range type which will not overflow. You can use long for the operation between Integers.

Basic
  • 26,321
  • 24
  • 115
  • 201
Macok
  • 31
  • 1