기본 콘텐츠로 건너뛰기

java.lang.Integer parseInt 메소드 분석

스트링을 숫자로 변화해주는 parseInt 메소드는 

parseInt(String)
parseInt(String, int)

2가지가 존재합니다. 하지만 parseInt(String)의 경우 내부를 보면 parseInt(String,10)으로 구현되어 있기 때문에 parseInt(String, int)만 분석하면 됩니다.
변환할 문자열이 null이면 NumberFormatException이 납니다.
int형의 인자로 진법을 설정할 수가 있습니다. 최소 2진법에서 최대 36진법까지 변환할 수 있습니다. 범위를 넘어가게 되면 NumberFormatException 이 납니다.

코드를 분석하면서 아이러니 했던 것은 문자열이 양수인 경우에도 결과값을 -값으로 누적하면서 계산하게 됩니다. 그 이유는 max보다 min의 절대값 정수현 표현 범위가 1 크기 때문에 -로 누적하면서 계산하면 음수와 양수인 경우 모두 계산가능하기 때문입니다.

내부적으로 보면 각문자열을 digit = Character.digit(s.charAt(i++),radix); 를 이용해 변환하는 것을 확인할 수 있습니다. 그리고 범위를 벗어나는지를 확인하기 위해 3개의 if문이 옵니다. 
첫번째 if문의 경우 digit의 값을 검사하는 루틴으로 0미만의 값 리턴, 즉 -1 리턴을 검사하기 위함입니다. -1 리턴의 경우 Chracter.digit()메소드에서 실패를 의미합니다.
두번째 if문의 경우 범위 검사입니다. 양수와 음수에 상관없이 limit = -214748364 가 됩니다. 결과값이 limit보다 작아지는경우는 -214748365,-214748366,-214748367,-214748368... 등이 값이 오게 되는 데요 이 경우는 무조건 MAX나 MIN값을 벗어나게 되기 때문에 예외가 일어납니다.
세번째 if문의 경우 결과값이 앞의 자리는 양수인 경우 [-2147483647,-2147483640] 인지 음수인 경우 [-2147483648,-2147483640] 인지를 확인하는 루틴입니다. 2번째 루틴에서는 십의 자리를 통해 범위를 확인했다면 세번째 루틴에서는 일의 자리 범위를 확인하는 과정이라고 보시면 됩니다.



439     public static int parseInt(String s, int radix)
440                 throws NumberFormatException
441     {
442         if (s == null) { //문자열 인자가 널이면 예외 발생
443             throw new NumberFormatException("null");
444         }
445 
446         if (radix < Character.MIN_RADIX) { // 2진법 미만이면 예외 발생
447             throw new NumberFormatException("radix " + radix +
448                                             " less than Character.MIN_RADIX");
449         }
450 
451         if (radix > Character.MAX_RADIX) {  //36 진법 초과이면 예외 발생
452             throw new NumberFormatException("radix " + radix +
453                                             " greater than Character.MAX_RADIX");
454         }
455 
456         int result = 0;
457         boolean negative = false;
458         int i = 0, len = s.length();
459         int limit = -Integer.MAX_VALUE;
460         int multmin;
461         int digit;
462 
463         if (len > 0) {
464             char firstChar = s.charAt(0);
465             if (firstChar < '0') { // Possible leading "-"
466                 if (firstChar == '-') {
467                     negative = true;
468                     limit = Integer.MIN_VALUE;
469                 } else
470                     throw NumberFormatException.forInputString(s);
471 
472                 if (len == 1) // Cannot have lone "-"
473                     throw NumberFormatException.forInputString(s);
474                 i++;
475             }
476             multmin = limit / radix;
477             while (i < len) {
478                 // Accumulating negatively avoids surprises near MAX_VALUE
479                 digit = Character.digit(s.charAt(i++),radix);
480                 if (digit < 0) { // Chrater.digit() 메소드 실패인 경우
481                     throw NumberFormatException.forInputString(s);
482                 }
483                 if (result < multmin) { // 십의 자리에서 범위를 벗어나는 경우
484                     throw NumberFormatException.forInputString(s);
485                 }
486                 result *= radix;
487                 if (result < limit + digit) { // 일의 자리에서 범위를 벗어나는 경우
488                     throw NumberFormatException.forInputString(s);
489                 }
490                 result -= digit;
491             }
492         } else {
493             throw NumberFormatException.forInputString(s);
494         }
495         return negative ? result : -result;
496     }

댓글

이 블로그의 인기 게시물

좌표압축

알 고리즘을 풀다 보면 좌표압축이라는 테크닉이 필요합니다. 저는 좌표압축을  "순위가 중요한 알고리즘에서, 입력값의 갯수보다 입력값의 범위가 클 때 사용하는 방법",  이라고 생각하고 있습니다. 1차원의 좌표로 예를 들어보겠습니다. n개의 x값 을 입력 받아, 입력 중 두개의  x1,x2를 선택하여 사이에 존재하는 점의 개수를 구하는 작업이 있다고 가정합시다. x의 범위는 int형의 범위인 -2^31 ~ 2^31-1 이고 중복은 없습니다. n은 5000 이하입니다. 입력은 n : 7, -2^31, -10000, 0 , -2000, 3, 6, 30000 , x1 = -10000, x2 = 30000 대략적으로 보면 그림과 같이 나타나게 됩니다. x1,x2 사이의 값을 구하게 되면 4개의 값이 나오게 됩니다. 이 경우 위의 값들을 아래와 같이 순위를 유지하면서 바꿔주어도 문제를 풀 수가있습니다. 이렇게   바꿔서 풀 수 있는 이유는 값보다 값의 순위가 중요하기 때문 입 니다. 압축좌표가  필요한 예 로, 카카오 코드 페스티벌 5번 캠핑 문제가 될 수 있습니다. 이 경우 좌표  x,y의 범위는 0 ~ 2^31-1  이지만, 입력받는  좌표의 개수는 최대 5000개  입니다. 만약 입력의 좌표를 그대로 반영하여 문제를 푼다고 하면 배열의 크기가 2^31-1 개가 되어야 합니다. 게다가 2차원으로.. 못풉니다. 탐색하다가 시간다 끝날꺼에요. 하지만 입력이 최대의 개수가 최대 5000이라고 했으니 좌표압축을 이용해 입력받은 좌표를 0~5000 으로 매치시키고 풀게되는 것 입니다.