I was looking at the source code for java.lang.Integer's parseInt method.
public static int parseInt(String s, int radix)
throws NumberFormatException
{
/*
* WARNING: This method may be invoked early during VM initialization
* before IntegerCache is initialized. Care must be taken to not use
* the valueOf method.
*/
if (s == null) {
throw new NumberFormatException("s == null");
}
if (radix < Character.MIN_RADIX) {
throw new NumberFormatException("radix " + radix +
" less than Character.MIN_RADIX");
}
if (radix > Character.MAX_RADIX) {
throw new NumberFormatException("radix " + radix +
" greater than Character.MAX_RADIX");
}
int result = 0;
boolean negative = false;
int i = 0, len = s.length();
int limit = -Integer.MAX_VALUE;
int multmin;
int digit;
if (len > 0) {
char firstChar = s.charAt(0);
if (firstChar < '0') { // Possible leading "+" or "-"
if (firstChar == '-') {
negative = true;
limit = Integer.MIN_VALUE;
} else if (firstChar != '+')
throw NumberFormatException.forInputString(s);
if (len == 1) // Cannot have lone "+" or "-"
throw NumberFormatException.forInputString(s);
i++;
}
multmin = limit / radix;
while (i < len) {
// Accumulating negatively avoids surprises near MAX_VALUE
digit = Character.digit(s.charAt(i++),radix);
if (digit < 0) {
throw NumberFormatException.forInputString(s);
}
if (result < multmin) {
throw NumberFormatException.forInputString(s);
}
result *= radix;
if (result < limit + digit) {
throw NumberFormatException.forInputString(s);
}
result -= digit;
}
} else {
throw NumberFormatException.forInputString(s);
}
return negative ? result : -result;
}
I can see that the multmin
is somehow being used to detect Integer overflow on both the negative and positive sides. But I am having a hard time understanding how.
I also do not understand why we are keeping the result negative while calculating and then making it positive at the end if it was not detected as a negative number.
multmin
work? multmin
is used in below code:
if (result < multmin) {
throw NumberFormatException.forInputString(s);
}
If current result is less than multmin
, next generation result must overflow, so an exception is thrown:
if result < multmin, ------> result < limit / radix (beacause multmin = limit / radix) ------> result * radix < limit ------> result * radix - digit < limit (overflow).
If current result is greater than or equals multmin
, we can assert result * radix >= limit
not overflow, so continue check if result * radix - digit
overflow with:
if (result < limit + digit) { throw NumberFormatException.forInputString(s); }
Because the absolute value of Integer.MIN_VALUE(-2147483648)
is greater than Integer.MAX_VALUE (2147483647)
.
Suppose we have a POSITIVE version, when input number start with '+', we can set limit
as Integer.MAX_VALUE
. But, when input number start with '-', we can not set limit
as 2147483648
, it's an overflow value.
This method is designed to throw an exception if s
represents an integer that is outside the [Integer.MIN_VALUE, Integer.MAX_VALUE]
ie [-2147483648, 2147483647]
range.
The algorithm performs repeated multiplication and addition which could eventually lead to overflow. The algorithm avoids overflow by checking the operands in advance.
The simplest way of checking if result + digit
will cause an overflow without actually adding them is to check:
if (result > limit - digit) // result, limit and digit are positive
The simplest way of checking if result * radix
will cause an overflow without actually multiplying them is to check:
if (result > limit / radix) // result, limit and radix are positive
So this explains what limit = Integer.MAX...
and multmin = limit / radix
do.
The algorithm separates out the sign and operates on remaining digits (it is easier to deal with one case). One special case it must handle is that of -2147483648
; in which case the limit must be set to 2147483648
which is outside the range of Integer
.
With negative accumulation, the limit could be set to -2147483648
. Note that "if" conditions described above must be adjusted for negative numbers as follows:
if (result < limit + digit) // result and limit are negative
if (result < limit / radix) // result and limit are negative
Here is a rough outline of that happens inside the algorithm at each step:
// parseInt("123", 10)
limit: -2147483647 (-Integer.MAX_VALUE)
multmin: -214748364
result: -1
result: -12
result: -123
// parseInt("2147483648", 10)
limit: -2147483647 (-Integer.MAX_VALUE)
multmin: -214748364
result: -2
result: -21
result: -214
result: -2147
result: -21474
result: -214748
result: -2147483
result: -21474836
result: -214748364
result: Overflow (after multiplication, before subtraction)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.