How can I check if multiplying two numbers in Java will cause an overflow?
Java 8 has Math.multiplyExact
, Math.addExact
etc. for ints and long. These throw an unchecked ArithmeticException
on overflow.
How to detect and prevent integer overflow when multiplying an integer by float in Java?
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.
Overflow occurs with multiplication
I would use the m2
line instead of the m3
line.
Java evaluates the multiplication operator *
from left to right, so 24 * 60
is evaluated first.
It just so happens that 24 * 60 * 60 * 1000
(one 1000
) doesn't overflow, so that by the time you multiply by 1000L
(the second 1000
), the product is promoted to long
before multiplying, so that overflow doesn't take place.
But as you mentioned in your comments, more factors can cause overflow in the int
data type before multiplying the last long
number, yielding an incorrect answer. It's better to use a long
literal for the first (left-most) number as in m2
to avoid overflow from the start. Alternatively, you can cast the first literal as a long
, e.g. (long) 24 * 60 * ...
.
Storing result of multiplication of two integers in long
Java has automatic widening from int
to long
, but that happens at assignment, but the multiplication of an int
with another int
produces an int
, so you would get integer overflow first multiplying 32329
with 4746475
, then the widening of the overflowed int
result to long
.
However, if you first cast at least one of the int
to long
, then the multiplication is done using long
and the result is long
, so no integer overflow.
Catch and compute overflow during multiplication of two large integers
1. Detecting the overflow:
x = a * b;
if (a != 0 && x / a != b) {
// overflow handling
}
Edit: Fixed division by 0
(thanks Mark!)
2. Computing the carry is quite involved. One approach is to split both operands into half-words, then apply long multiplication to the half-words:
uint64_t hi(uint64_t x) {
return x >> 32;
}
uint64_t lo(uint64_t x) {
return ((1ULL << 32) - 1) & x;
}
void multiply(uint64_t a, uint64_t b) {
// actually uint32_t would do, but the casting is annoying
uint64_t s0, s1, s2, s3;
uint64_t x = lo(a) * lo(b);
s0 = lo(x);
x = hi(a) * lo(b) + hi(x);
s1 = lo(x);
s2 = hi(x);
x = s1 + lo(a) * hi(b);
s1 = lo(x);
x = s2 + hi(a) * hi(b) + hi(x);
s2 = lo(x);
s3 = hi(x);
uint64_t result = s1 << 32 | s0;
uint64_t carry = s3 << 32 | s2;
}
To see that none of the partial sums themselves can overflow, we consider the worst case:
x = s2 + hi(a) * hi(b) + hi(x)
Let B = 1 << 32
. We then have
x <= (B - 1) + (B - 1)(B - 1) + (B - 1)
<= B*B - 1
< B*B
I believe this will work - at least it handles Sjlver's test case. Aside from that, it is untested (and might not even compile, as I don't have a C++ compiler at hand anymore).
How do you check if an arithmetic operation will overflow?
How is this done in C?
When wider math is available, code could use that.
int a,b;
...
int_twice_as_wide product = (int_twice_as_wide) a * b;
if (product < INT_MIN || product > INT_MAX) Handle_Overflow();
With signed integer math, overflow is undefined behavior (UB), so when wider math not readily available, code could perform various pre-tests for + - * /
as done here.
For unsigned math, overflow "wraps around" ( a module UINT_MAX + 1
). It is easy for + -
(below). Division only need to watch for / 0
.
unsigned a,b;
...
unsigned sum = a + b;
if (sum < a) Handle_Overflow();
The unsigned *
is much like the above referenced signed *
code with fewer tests.
bool is_undefined_umult1(unsigned a, unsigned b) {
if (b > 0) {
return a > UINT_MAX / b;
}
return false;
}
it should return a u8 if it fits, otherwise a u16. But not a u16 in all cases.
C functions do not return different types depending upon value. Instead consider:
uint16_t unt8_mul(unt8_t a, unt8_t b) {
return (uint16_t) a * b;
}
For u8 * u8, avoid a * b
as on 16-bit systems the multiplication is signed, the product may overflow and incur UB.
How to detect overflow of unsigned long multiplication in Java?
Edit
As promised in one of my comments to original post I will now post strict and correct solution. It has less divisions that Nathan's own formula (for those interested see last code line in his answer), but it has additional branching, so I am not sure it will be better performance-wise.
And, alas, it is not one-liner. Here it is:
static boolean unsignedMultiplyOverflows(final long a, final long b) {
if (a == 0 || b == 0) {
return false;
}
// now proceed with non-zero input
// we branch based upon parity of a and b
final long aHalf = a >>> 1;
final long bHalf = b >>> 1;
final byte aLastBit = (byte) (a & 1);
final byte bLastBit = (byte) (b & 1);
if (aLastBit == 0) { // a = 2 * aHalf, meaning unsigned representation of a
return Long.MAX_VALUE / b < aHalf;
} else if (bLastBit == 0) { // b = 2 * bHalf
return Long.MAX_VALUE / a < bHalf; // symmetrical to previous case
} else { // a = 2 * aHalf + 1; b = 2 * bHalf + 1
return (Long.MAX_VALUE - bHalf) / b < aHalf;
}
}
The formal proof is based on investigation of 2 cases, 1. At least one of multipliers is even, and 2. a
,b
both odd. I could add it if anyone is interested.
I have unit-tested it on full range of chars : 0 ~ 0xffff for overflow of 16-bit numbers, and also on some random long
input, comparing results with both Nathan's method and BigInteger
solution as a reference.
Hope that helps.
Related Topics
Using Hibernate's Scrollableresults to Slowly Read 90 Million Records
How to Keep a User Logged into My Site for Months
How to Move a File from One Location to Another in Java
How to Multiply Strings in Java to Repeat Sequences
Finding the Second Highest Number in Array
What Is the Purpose of @Namedarg Annotation in Javafx 8
How to Compile & Run Java Program in Another Java Program
Get MAC Address on Local MAChine with Java
Java 8: Difference Between Method Reference Bound Receiver and Unbound Receiver
How to Sort Date Which Is in String Format in Java
When to Close Connection, Statement, Preparedstatement and Resultset in Jdbc
Java Garbage Collector - When Does It Collect
Java Conditional Compilation: How to Prevent Code Chunks from Being Compiled
How to Compile a Java File with a Different Name Than the Class
How Do Different Retention Policies Affect My Annotations