I have read this article NUM00-J. Detect or prevent integer overflow and this question How does Java handle integer underflows and overflows and how would you check for it?.
As you can see, there are many solutions to prevent integer overflow when multiplying an integer by an integer. But I wonder is there any solution to prevent integer overflow when multiplying an integer by float?
My current (silly) solution:
public static final int mulInt(int a, float b) {
double c = a * b;
return c > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int)c;
}
But it has a lot of problems:
So, what is the real solution to this problem?
Your answer will be very helpful, I will appreciate it!
UPDATE: There is another question here How can I check if multiplying two numbers in Java will cause an overflow? that is quite similar BUT it is about multiplying an integer by an integer instead of multiplying by a float.
Below is a C approach that may shed light in Java.
Perform the multiplication using double
, not float
math before the assginment to gain the extra precision/range of double
. Overflow is not then expected.
A compare like c > Integer.MAX_VALUE
suffers from Integer.MAX_VALUE
first being converted into a double
. This may lose precision.*1 Consider what happens if the converted value is Integer.MAX_VALUE + 1.0
. Then if c
is Integer.MAX_VALUE + 1.0
, code will attempt to return (int) (Integer.MAX_VALUE + 1.0)
- not good. Better to use well formed limits. (Negative ones too.) In C, maybe Java, floating point conversion to int
truncates the fraction. Special care is needed near the edges.
#define INT_MAX_PLUS1_AS_DOUBLE ((INT_MAX/2 + 1)*2.0)
int mulInt(int a, float b) {
// double c = a * b;
double c = (double) a * b;
//return c > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int)c;
if (c < INT_MAX_PLUS1_AS_DOUBLE && c - INT_MIN > -1.0) {
return (int) c;
}
if (c > 0) return INT_MAX;
if (c < 0) return INT_MIN;
return 0; // `b` was a NaN
}
c - INT_MIN > -1
is like c > INT_MIN - 1
, but as INT_MIN
is a -power-of-2, INT_MIN - 1
might not convert precisely to double
. c - INT_MIN
is expected to be exact near the edge cases.
*1 When int
is 32-bit (or less) and double
is 64-bit (with 53-bit significand) not an issue. But important with wider integer types.