Take the 2-minute tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

I have a piece of code that takes a couple of integers and check if performing an addition on the inputs would result in an overflow.

I was wondering if this code is SOLID:

public static boolean CanAdd(int me, int... args) { 
    int total = me;
    for (int arg : args) {
        if (total >= 0) {
            if (java.lang.Integer.MAX_VALUE - total >= arg) { // since total is positive, (MaxValue - total) will never overflow
                total += arg;
            } else {
                return false;
            }
        } else {
            if (java.lang.Integer.MIN_VALUE- total <= arg) { // same logic as above
                total += arg;
            } else {
                return false;
            }
        }
    }
    return true;
}

Does anyone have a better (faster) way to achieve the same thing?

share|improve this question
1  
Have you done any profiling which showed that this method is a bottleneck in your application? –  palacsint Nov 24 '11 at 19:08
1  
@palacsint no this isn't a bottleneck in my application.. just that I'm interested in algorithms related to range checking and was wondering if there's a better solution (besides the casting one) =) –  Pacerier Nov 24 '11 at 20:30
    
I have seen some (usually C/C++) questions and answers on SO with nice bitwise code, maybe you want to check them :-) –  palacsint Nov 24 '11 at 22:18
    
I don't know your ultimate purpose, but depending on what you are trying to accomplish, perhaps, you might find Guava's checked arithmetic useful. Note this is not actually a direct response to your query. code.google.com/p/guava-libraries/wiki/MathExplained –  Jubbat Jan 28 '12 at 23:56

3 Answers 3

I haven't found any input which isn't handled well by your code. Here are some tests:

assertTrue(CanAdd(0, Integer.MAX_VALUE));
assertTrue(CanAdd(0, Integer.MIN_VALUE));
assertTrue(CanAdd(Integer.MIN_VALUE, 0));
assertTrue(CanAdd(-1, Integer.MAX_VALUE));
assertFalse(CanAdd(1, Integer.MAX_VALUE));
assertFalse(CanAdd(-1, Integer.MIN_VALUE));

So, it works but it isn't an easy task to read it. If this isn't a bottleneck in an application I would use a long:

public static boolean canAdd(int... values) {
    long sum = 0;
    for (final int value: values) {
        sum += value;
        if (sum > Integer.MAX_VALUE) {
            return false;
        }
        if (sum < Integer.MIN_VALUE) {
            return false;
        }
    }
    return true;
}

I think it's easier to read and maintain.

Finally, a note: according to Code Conventions for the Java Programming Language the name of your method should be canAdd (with lowercase first letter).

Methods should be verbs, in mixed case with the first letter lowercase, with the first letter of each internal word capitalized.

Edit:

Apache Commons Math also uses long conversion:

public static int addAndCheck(int x, int y)
        throws MathArithmeticException {
    long s = (long)x + (long)y;
    if (s < Integer.MIN_VALUE || s > Integer.MAX_VALUE) {
        throw new MathArithmeticException(LocalizedFormats.OVERFLOW_IN_ADDITION, x, y);
    }
    return (int)s;
} 

As well as Guava:

public static int checkedAdd(int a, int b) {
    long result = (long) a + b;
    checkNoOverflow(result == (int) result);
    return (int) result;
}
share|improve this answer

Your logic looks solid to me. It's subtle, though.

Here is another version using long, but with much simpler logic:

public static boolean canAdd(int... values) {
    long longSum = 0;
    int intSum = 0;
    for (final int value: values) {
        intSum += value;
        longSum += value;
    }
    return intSum == longSum;
}

That's the most straightforward way I can think to write it — and it's going to be pretty definitive.

Note that there is no "early out" in this loop, meaning it will always run to the end of the list. However, not having any conditionals, it's likely to be faster in many cases, if that matters.

share|improve this answer

About the current code:

  • I'd rename CanAdd to canAdd (according to the coding conventions).
  • Rename me to value (it's more descriptive), and args to values and arg to currentValue.
  • Remove the unnecessary java.lang package prefix.
public static boolean canAdd(int value, int... values) {
    int total = value;
    for (int currentValue: values) {
        if (total >= 0) {
            // since total is positive, (MaxValue - total) will never
            // overflow
            if (Integer.MAX_VALUE - total >= currentValue) {
                total += currentValue;
            } else {
                return false;
            }
        } else {
            // same logic as above
            if (Integer.MIN_VALUE - total <= currentValue) {
                total += currentValue;
            } else {
                return false;
            }
        }
    }
    return true;
}

I have also moved the comments a line up to avoid horizontal scrolling.

I don't really like the value and values here so I've changed the first two lines a little bit:

public static boolean canAdd(int... values) {
    int total = 0;
    ...
}

If you invert the inner if statements you could eliminate the else keywords:

if (total >= 0) {
    if (Integer.MAX_VALUE - total < currentValue) {
        return false;
    }
    total += currentValue;
} else {
    if (Integer.MIN_VALUE - total > currentValue) {
        return false;
    }
    total += currentValue;
}

The += is the same in both branches therefore it could be moved after the if:

if (total >= 0) {
    if (Integer.MAX_VALUE - total < currentValue) {
        return false;
    }
} else {
    if (Integer.MIN_VALUE - total > currentValue) {
        return false;
    }
}
total += currentValue;

Introducing a explanatory boolean variable could make it shorter and save an indentation level:

 public static boolean canAdd(int... values) {
    int total = 0;
    for (int currentValue: values) {
        final boolean positiveTotal = total >= 0;
        if (positiveTotal && (Integer.MAX_VALUE - total < currentValue)) {
            return false;
        }
        if (!positiveTotal && (Integer.MIN_VALUE - total > currentValue)) {
            return false;
        }
        total += currentValue;
    }
    return true;
}

But I think it's still hard to understand. I'd go with long conversion.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.