I have written a method to reverse a signed int. If the reversed number is not in range of INT_MAX and INT_MIN it will return 0. It is working for almost all cases except for -2147483648 While debugging i have found that the code is not handling sign properly for -2147483648 while its working for different signed inputs.
Can someone explanin why Math.abs(x) is not working properly for this testcase. Method is given below.
public int reverse(int x) {
boolean flag = (x>0);
x = Math.abs(x);
String num = new StringBuilder(Integer.toString(x)).reverse().toString();
long temp = Long.parseLong(num);
if(!flag){
temp = -temp;
}
if((Integer.MAX_VALUE < temp) || ( temp < Integer.MIN_VALUE)){
return 0;
}
return (int) temp;
}
In Java, the integer representation goes from Integer.MIN_VALUE
= -2^31
= -2147483648
to Integer.MAX_VALUE
= 2^31-1
= 2147483647
.
There is no positive value opposite to -2147483648
that can be properly represented in Java's integer range when performing Math.abs(x)
. Hence, when the parameter -2147483648
is passed to the method, the result overflows back to the smallest representable integer, which is -2147483648
again, since Math.abs()
simply negates the given parameter when this is negative. Therefore, in your line
String num = new StringBuilder(Integer.toString(x)).reverse().toString();
you're actually reversing -2147483648
into 8463847412-
, which causes the NumberFormatException
being thrown when performing
long temp = Long.parseLong(num);
since 8463847412-
is not a long
.
In Java, error cases should be handled with an appropriate Exception
describing the nature of the problem. Although your current version does throw an exception (NumberFormatException
), it doesn't really address the actual issue, i.e. x
not being representable as a positive integer when equal to Integer.MIN_VALUE
.
As others have already suggested, you could use Math.absExact()
instead of Math.abs()
, as it throws an ArithmeticException
if the result overflows the positive int range.
public int reverse(int x) {
boolean flag = (x > 0);
x = Math.absExact(x);
// ... rest of the implementation
}
However, Math.absExact()
is available only from Java 15. Furthermore, personally speaking, I would throw an IllegalAegumentException
, as I prefer the users of my API to receive a "higher-level" exception closer to what they're doing, rather than re-throwing an exception closer to my internal implementation.
public int reverse(int x) {
if (x == Integer.MIN_VALUE)
throw new IllegalArgumentException(String.format("%d cannot be represented as a positive integer... More detailed explanation...", x));
boolean flag = (x > 0);
x = Math.abs(x);
// ... rest of the implementation
}
However, this is purely a matter of style; both exceptions (ArithmeticException
and IllegalAegumentException
) are completely fine. Nonetheless, the thing that everybody can agree on is that, regardless of the exception used, an appropriate exception must be thrown when the actual error occurs. The NumberFormatException
is not an appropriate way, as it is just a consequence of an error not handled when presented itself.