views:

486

answers:

8

I want to handle the special case where multiplying two numbers together causes an overflow. The code looks something like this:

int a = 20;
long b = 30;

// if a or b are big enough, this result will silently overflow
long c = a * b;

That's a simplified version - in the real app, a and b are sourced elsewhere at runtime. What I want to achieve is something like this:

long c;
if (a * b will overflow) {
    c = Long.MAX_VALUE;
} else {
    c = a * b;
}

How do you suggest I best code this?

Update: a and b are always non-negative in my scenario.

A: 

Maybe:

if(b!= 0 && a * b / b != a) //overflow

Not sure about this "solution".

Edit: Added b != 0.

Before you downvote: a * b / b won't be optimized. This would be compiler bug. I do still not see a case where the overflow bug can be masked.

Thomas Jung
Fails on b = 0.
Stefan Kendall
Also fails when overflow causes a perfect loop.
Stefan Kendall
Do you have an example of what you meant?
Thomas Jung
Just wrote a little test: Using BigInteger is 6 times slower than using this division approach. So I assume additional checks for corner cases is worth it performance-wise.
mhaller
Don't know much about java compilers, but an expression like `a * b / b` is likely to be optimized to just `a` in many other contexts.
TokenMacGuy
TokenMacGuy - it cannot be optimised like that if there is a danger of overflow.
Tom Hawtin - tackline
+5  A: 

You could use java.math.BigInteger instead and check the size of the result (haven't tested the code):

BigInteger bigC = BigInteger.valueOf(a) * multiply(BigInteger.valueOf(b));
if(bigC.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) > 0) {
  c = Long.MAX_VALUE;
} else {
  c = bigC.longValue()
}
Ulf Lindback
i find this solution rather slow
Yossarian
It's probably the best way to do it, though. I assumed this was a numerical application, which is why I didn't recommend it offhand, but this really is probably the best way to solve this problem.
Stefan Kendall
I'm not sure you can use the '>' operator with BigInteger. the compareTo method should be used.
Pierre
changed to compareTo, and speed might matter or might not, depends on the circumstances where the code will be used.
Ulf Lindback
+5  A: 

Hi

Use logarithms to check the size of the result.

Mark

High Performance Mark
do you mean: `ceil(log(a)) + ceil(log(b)) > log(Long.MAX)`?
Thomas Jung
Yeah, something like that.
High Performance Mark
Heh, interesting answer given your username. ;-)
John Kugelman
That's right. But maybe it is faster than BigInteger.
Thomas Jung
Thomas Jung
I rather suspect that it may fail in some cases.
Tom Hawtin - tackline
Neil Coffey
P.S. Sorr, I think I need an extra bit set in the AND mask (0xffffffff80000000L)-- it's a bit late, but you get the idea...
Neil Coffey
Oh, if you want it fast, take logs, add, and, if the answer is in range, take antilogs -- you've already computed the resultMark
High Performance Mark
-1 What a terrible answer.
Shakedown
+3  A: 

Does Java has something like int.MaxValue? If yes, then try

if (b != 0 && Math.abs(a) > Math.abs(Long.MAX_VALUE / b))
{
 // it will overflow
}

edit: seen Long.MAX_VALUE in question

Yossarian
why the downvote?
Yossarian
I didn't downvote but `Math.Abs(a)` doesn't work if `a` is `Long.MIN_VALUE`.
John Kugelman
Thomas Jung
@Thomas, a and b are >= 0, that is, non-negative.
Steve McLeod
Right, but in that case no need for the Abs's. If negative numbers are allowed then this fails for at least one edge case. That's all I'm saying, just being nitpicky.
John Kugelman
in Java you must use Math.abs, not Math.Abs (C# guy?)
dfa
+9  A: 

If a and b are both positive then you can use:

if (a != 0 && b > Long.MAX_VALUE / a) {
    // Overflow
}

If you need to deal with both positive and negative numbers then it's more complicated:

long maximum = Math.sign(a) == Math.sign(b) ? Long.MAX_VALUE : Long.MIN_VALUE;

if (a != 0 && (b > 0 && b > maximum / a ||
               b < 0 && b < maximum / a))
{
    // Overflow
}

Here's a little table I whipped up to check this, pretending that overflow happens at -10 or +10:

a =  5   b =  2     2 >  10 /  5
a =  2   b =  5     5 >  10 /  2
a = -5   b =  2     2 > -10 / -5
a = -2   b =  5     5 > -10 / -2
a =  5   b = -2    -2 < -10 /  5
a =  2   b = -5    -5 < -10 /  2
a = -5   b = -2    -2 <  10 / -5
a = -2   b = -5    -5 <  10 / -2
John Kugelman
I should mention that a and b are always non-negative in my scenario, which would simplify this approach somewhat.
Steve McLeod
A: 

To Austin Kelley Way: Java has no unsigned data types.

True Soft
This should be a comment.
Stefan Kendall
Comments kick in at 50. Upvote to allow True Soft to follow your advice.
Ewan Todd
Then will he ever learn? That's like responding "Should be closed" as an answer. It's not the rule of the site, and it should be discouraged.
Stefan Kendall
+2  A: 

I am not sure why nobody is looking at solution like :

if (Long.MAX_VALUE/a > b) { // overflows }

Choose a to be larger of the two numbers.

fastcodejava
+1  A: 

maybe this will help you:

/**
 * @throws ArithmeticException on integer overflow
 */
static long multiply(long a, long b) {
    double c = (double) a * b;
    long d = a * b;

    if ((long) c != d) {
        throw new ArithmeticException("int overflow");
    } else {
        return d;
    }
}
dfa
Wont help as one of the operands is `long`.
Tom Hawtin - tackline
fixed, thanks very much
dfa