Issue
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:
- It can get the expected result when multiplying performs multiplication with both parameters having to be small numbers.
- When either parameter is large digits the result is bound to be incorrect (I know in part because of the floating-point data type).
- Suppose if the result of the calculation is even greater than the maximum value of double, it will be unstoppable and return a negative number.
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.
Solution
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 significant) not an issue. But important with wider integer types.
Answered By - chux - Reinstate Monica Answer Checked By - Timothy Miller (PHPFixing Admin)
0 Comments:
Post a Comment
Note: Only a member of this blog may post a comment.