consider the following:
(i+j)/2
i and j are both 32 bit integers and the result should also be.
But in the little equation, there’s a hidden overflow, i+j could become larger then a 32 bit integer even though the result would always be a 32 bit integer.
public class Sum{
public static void main(String []args){
int i = 2147483647;
int j = 2147483647;
System.out.println((i + j)/2);
}
}
Gives me -1 as a result.
How do you guard against situations that can overflow but are not always obvious.
Is there a pattern that describes this?
(apart from declaring everything long)
I’m looking for a general answer, the java example is just to provide an example, my Delphi does the same.
8
You have three choices, none of which are ideal for all situations:
Detect Overflows. Most languages have a way to determine the largest possible value for integer data types. The addition in your example will result in an overflow whenever j > (max_value_of_type - i)
. You will have to check every use for overflows or build a library or class to does it for you.
Use Larger Types. If there are larger integers available, use those to do your intermediate calculations and convert back to the smaller type when finished. The hitch here is that you must understand whether the results of those calculations are guaranteed to fit the smaller size if that’s what you’ll be returning. Your example of (i + j) / 2
fits, but (i * j) / 2
doesn’t.
Restrict the Input Values. This is a lot like both of the above in that you’re limiting the inputs to values you know won’t cause an overflow and at the same time making the integers large enough to hold the result.
2
You can define your own arithmetic operators, for example like this.
int operator + (int a, int b) {
int res = a + b;
if(a > 0 && b > 0 && res < 0) {
throw new ArithmeticOverflowException();
} else if(a < 0 && b < 0 && res > 0) {
throw new ArithmeticUnderflowException();
}
return res;
}
8