8

I'm having problems detecting if a sum/multiplication of two numbers exceeds the maximum value of a long integer.
Example code:

long a = 2 * Long.MAX_VALUE;
System.out.println("long.max * smth > long.max... or is it? a=" + a);

This gives me -2, while I would expect it to throw a NumberFormatException...

Is there a simple way of making this work? Because I have some code that does multiplications in nested IF blocks or additions in a loop and I would hate to add more IFs to each IF or inside the loop.

Edit: oh well, it seems that this answer from another question is the most appropriate for what I need: https://stackoverflow.com/a/9057367/540394
I don't want to do boxing/unboxing as it adds unnecassary overhead, and this way is very short, which is a huge plus to me. I'll just write two short functions to do these checks and return the min or max long.

Edit2: here's the function for limiting a long to its min/max value according to the answer I linked to above:

/**
 * @param a : one of the two numbers added/multiplied
 * @param b : the other of the two numbers
 * @param c : the result of the addition/multiplication
 * @return the minimum or maximum value of a long integer if addition/multiplication of a and b is less than Long.MIN_VALUE or more than Long.MAX_VALUE
 */
public static long limitLong(long a, long b, long c)
{
    return (((a > 0) && (b > 0) && (c <= 0))
        ? Long.MAX_VALUE
        : (((a < 0) && (b < 0) && (c >= 0)) ? Long.MIN_VALUE : c));
}

Tell me if you think this is wrong.

Community
  • 1
  • 1
jurchiks
  • 1,354
  • 4
  • 25
  • 55
  • +1. There should be some library that allows for integer overflow detection. – Thilo Sep 10 '12 at 08:51
  • Or special blocks (something like finally?) which can help developers enable error-on-overflow behaviour for all math code that executes within in. I believe C# has one. EDIT: Found it, [checked and unchecked blocks in C#](http://msdn.microsoft.com/en-us/library/a569z7k8.aspx). – Sanjay T. Sharma Sep 10 '12 at 08:56
  • Well, C# seems to throw errors on overflow (which I'd very much prefer over silence and wrong results that don't make sense to me)... – jurchiks Sep 10 '12 at 09:00
  • Added a function for checking the min/max overflow, could someone please review it? – jurchiks Sep 10 '12 at 09:37
  • possible duplicate of [Long + Long not bigger than Long.MAX_VALUE](http://stackoverflow.com/questions/9057290/long-long-not-bigger-than-long-max-value) – mathieu Sep 10 '12 at 12:40
  • @mathieu - yeah, and you found that out from the link in my post. – jurchiks Sep 10 '12 at 18:41
  • @jurchiks - no, your post was marked for review as a possible duplicate – mathieu Sep 11 '12 at 07:04

3 Answers3

5

If you can't be sure the result will be less than 9 trillion trillion, I would use double or BigInteger Getting an error doesn't help you very much because you still need to know what to do about.

Much better that you don't get an error in the first place by validating your input to ensure they are in range and if the range of the result is larger than long use a type which can handle this.

With BigInteger you can do

BigInteger a = BigInteger.valueOf(2).multiply(BigInteger.valueOf(Long.MAX_VALUE));
long l = a.longValue();
if (a.compareTo(BigInteger.valueOf(l)) == 0) {
    // ok
} else {
    // error
}

With double you can do

double d = 2.0 * Long.MAX_VALUE;
long l = (long) Math.max(Long.MIN_VALUE, Math.min(Long.MAX_VALUE, d));
// or as a helper method.
long l = boundedCast(d);

Note: using double instead of long can result in some loss of precision.

I would prefer to avoid the need for an error block in the first place.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • 1
    The thing is, I need to trim it down to `long` if it exceeds it. Maybe that helps? Getting an error would help a lot in my case; I could just put the whole code in a try/catch block and if an error is thrown, set the value to Long.MAX_VALUE, because that's all I need. – jurchiks Sep 10 '12 at 08:47
  • If it exceed a long, you can't trim it. The best you can do is make it `Long.MAX_VALUE` which is not a great solution. – Peter Lawrey Sep 10 '12 at 08:48
  • 3
    @PeterLawrey I think cap it to `Long.MAX_VALUE` is what OP meant by *trim it down to `long`*. – brimborium Sep 10 '12 at 10:18
5

Exceding the maximum value of a long doesnt throw an exception, instead it cicles back. If you do this:

Long.MAX_VALUE + 1

you will notice that the result is the equivalent to Long.MIN_VALUE

If you want it to throw an exception check if it reached the max value and throw the exception

[Edit]

You can also use the Guava Library to check if there is an overflow when you sum two longs;

long c = LongMath.checkedAdd(a, b);

this throws an exception when an overflow occurs.

You can find the javadoc here

Daniel André
  • 1,158
  • 1
  • 12
  • 28
  • 2
    "simply do an if checking if it reached the max value" - and how do you imagine that? I don't want to throw the exception myself, I shouldn't, to be exact. – jurchiks Sep 10 '12 at 08:50
  • You can also try this: long c = LongMath.checkedAdd(a, b); It throws an exception if there is an overflow when summing 2 longs – Daniel André Sep 10 '12 at 08:54
  • 1
    @DanielA. Maybe you should add, that you need the [Guava library](http://code.google.com/p/guava-libraries/) for this. – Baz Sep 10 '12 at 08:57
  • Alas, a library just for this is not what I'm interested in... I can't believe Java ignores this stuff; it makes absolutely no sense to me to "cycle it back", as you say, when the logical result should be an overflow. Probably some legacy code that nobody wanted to clean up... – jurchiks Sep 10 '12 at 09:08
  • 2
    Disagree. It's a very deliberate and entirely reasonable call for overflows to just take the low bits. For starters, any alternative would incur _massive_ performance overhead for every arithmetic operation in Java. This is how processors do it, and Java's behavior is relatively sensible as far as these things go. – Louis Wasserman Sep 10 '12 at 21:27
0

Long values exceeding MAX_VALUE doesn't throw any exception. You need to check and handle such situations manually.

ALthough as @PeterLawrey suggested you should consider using double and BigInteger.

Bharat Sinha
  • 13,973
  • 6
  • 39
  • 63
  • How do you do this with a double? A BigInteger example has been posted, but double... Assigning a double the value of Long.MAX_VALUE and printing it gives me `9.223372036854776E18`. – jurchiks Sep 10 '12 at 09:12