Quick approach
This could be a solution (note: always use meaningful variable names!):
private static int sum(int i, int... others) {
int sum = i;
if(others!=null)
for(int other : others) {
sum+=other;
}
}
System.out.println("sum:" + sum);
return sum;
}
Notice the arguments. As it is not very meaningful to sum 1 number, this construct ensures that there is at least 1 int coming in. And this one also checks for null value in the vararg.
Overflowing with emotions...
What would happen with the quick approach when executing this:
int veryBigNumber = sum(Integer.MAX_VALUE, 1);
veryBigNumber
would in fact be ==Integer.MIN_VALUE
...
This might be a problem. As Java does not throw an exception when an overflow occurs, you could end up with incorrect results. You could do a check for overflows:
private static int aLittleBitSaferSum(int i, int... others) throws ArithmeticException {
int sum = i;
if(others!=null)
for(int other : others) {
if(Integer.MAX_VALUE-other<sum) {
throw new ArithmeticException("Sum would be too large to fit in int");
}
if(Integer.MIN_VALUE+other>sum) {
throw new ArithmeticException("Sum would be too small to fit in int");
}
sum+=other;
}
}
System.out.println("sum: " + sum);
return sum;
}
Of course, this is just a dumb check... The result could fit very well in an int
, for example with this:
sum(Integer.MAX_VALUE, 1, -1);
Which should result in Integer.MAX_VALUE
- which it would wihtout the checks.
Extending the horizon
Fear not! The aforementioned problem could also be solved. For example, by providing a clever algorithm ordering the operands in a way that the partial result would always fit in the int
range, but I think that is a problem not trivial to be solved... And would cost a lot in computing power.
However, by extending the range of the values the function is dealing with, it can do a lot better:
private static int aLittleBitSaferSum(int i, int... others) throws ArithmeticException {
long sum = i;
if(others!=null)
for(int other : others) {
if(Long.MAX_VALUE-other<sum) {
throw new ArithmeticException("Sum would be too large for this algorithm to deal with");
}
if(Long.MIN_VALUE+other>sum) {
throw new ArithmeticException("Sum would be too small for this algorithm to deal with");
}
sum+=other;
}
}
if(Integer.MAX_VALUE<sum) {
throw new ArithmeticException("Sum would be too large to fit in int");
}
if(Integer.MIN_VALUE>sum) {
throw new ArithmeticException("Sum would be too small to fit in int");
}
System.out.println("sum: " + sum);
return (int)sum;
}
This still has limitations, as long
has too, but as long
is twice the size of an Integer, it is far less likely to cause a problem. This is however a bit slower due to the extra work involved, also a lot less readable because of the checks.
I want it all
... and I want it now. The range can still be a problem, this is a solution to it:
private static int aSafeButSlowerSum(int i, int... others) throws ArithmeticException {
BigInteger sum = BigInteger.valueOf(i);
BigInteger intMax = BigInteger.valueOf(Integer.MAX_VALUE); //should be a private static final class variable
BigInteger intMin = BigInteger.valueOf(Integer.MIN_VALUE); //should be a private static final class variable
if(others!=null)
for(int other : others) {
sum=sum.add(BigInteger.valueOf(i));
}
}
if(intMax.compareTo(sum)<0) {
throw new ArithmeticException("Sum would be too large to fit in int");
}
if(intMin.compareTo(sum)>0) {
throw new ArithmeticException("Sum would be too small to fit in int");
}
System.out.println("sum: " + sum.toString());
return sum.intValue;
}
This is even slower due to all the BigInteger stuff, but shows no problems of the above functions. (so it will be a little bit less "now" as with the other options, but there is a price to pay for the extras..)