Java에서 진법 변환 시 꿀팁

0

알고리즘

목록 보기
16/16

백준 문제를 해결하던 중 여러 종류의 진법 수를 10진법으로 변환하는 문제가 나왔다.

https://www.acmicpc.net/problem/2745

주어진 문제에서 변환 전 숫자를 10부터는 알파벳을 이용해 표현한다.

B진법 수 N이 주어진다. 이 수를 10진법으로 바꿔 출력하는 프로그램을 작성하시오.
10진법을 넘어가는 진법은 숫자로 표시할 수 없는 자리가 있다. 이런 경우에는 다음과 같이 알파벳 대문자를 사용한다.
A: 10, B: 11, ..., F: 15, ..., Y: 34, Z: 35


1. 값 수동 매핑 - 성공!

나의 처음 접근 방식은
BufferedReader로 받아온 N을 문자열의 각 인덱스 값마다 아스키코드에서 55를 뺀 값을 사용해서 수동으로 매핑하는 방법을 떠올렸다.

import java.io.*;
import java.util.StringTokenizer;

public class Test_01_PositionalNumeralSystemConversion {
    static int convertChar(char c) {
        if ('0' <= c && c <= '9') {
            return c - '0';
        } else {
            return c - 55;
        }
    }

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        String num = st.nextToken();
        int base = Integer.parseInt(st.nextToken());

        long answer = 0;
        for (int i = 0; i < num.length(); i++) {
            char c = num.charAt(i);
            int value = convertChar(c);
            answer = answer * base + value;
        }

        System.out.println(answer);
    }
}

받아온 값 N이 0부터 9사이인 경우에는 아스키코드를 이용해 48을 빼고,
그 외에 A~Z인 경우에는 마찬가지로 55를 빼서 직접 값을 수동으로 계산하는 코드이다.


2. 내장 메서드 사용 - 성공!

정답을 맞춘 후 다른 사람들은 어떻게 코드를 작성했나 확인하기 위해 구글링을 해보니
Long.parseLong(num, b) 내장 메서드를 사용하는 경우가 많이 보였다.

import java.io.*;
import java.util.StringTokenizer;

public class Test_01_PositionalNumeralSystemConversion {
    static int toInt(String s) {
        return Integer.parseInt(s);
    }

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        String num = st.nextToken();
        int b = toInt(st.nextToken());
        Long answer = Long.parseLong(num, b);

        System.out.println(answer);
    }
}

코드가 훨씬 간결하고 속도도 빠르다.

이 코드는 b진법 값인 num을 10진법으로 바꿔주는 코드인건 다른 문제들을 통해 많이 사용해봐서 알 수 있었는데
내가 의아했던 점은 문제에 주어진

10진법을 넘어가는 진법은 숫자로 표시할 수 없는 자리가 있다. 이런 경우에는 다음과 같이 알파벳 대문자를 사용한다.
A: 10, B: 11, ..., F: 15, ..., Y: 34, Z: 35

이 내용을 코드에 따로 작성하지 않고도 매핑 정보를 어떻게 알고있는거지???

내 궁금증을 속시원하게 긁어줄 수 있는 gpt에게 물어보니

Q. Long.parseLong("ZZZZZ", 36)
이 메서드를 사용할 때 따로 작성을 안했는데
A = 10, Z = 35라는 거에대한 정보는 어떻게 알고있는거야?
아스키코드로 A = 65잖아

A. ✅ 자바는 어떻게 알파벳을 숫자로 바꾸는가?
Java에서 parseInt(String s, int radix)나 parseLong(String s, int radix) 메서드는 내부적으로 진법 변환 규칙을 이미 정의하고 있습니다.
이는 모든 진법 변환 시스템에서 일반적으로 쓰이는 표준이예요. 이 규칙은 ASCII 코드와는 무관하게 정의된 진법 문자 체계입니다.

즉, 정리해보자면
1. A = 10, Z = 35는 진법 표기 방식의 표준 규칙이다.
2. Java는 parseInt나 parseLong에서 이 표준 규칙을 자동으로 적용한다.
3. ASCII 코드와는 별개로 정의된 진법 전용 문자 체계를 따른다.

진법 변환을 할 때 Java에서 표준으로 정해진 A ~ Z에 대한 진법 전용 규칙이 있었고,
백준 문제에서는 그 규칙을 이용하라는 힌트를 대놓고 준거였다.
물론 나는 그 규칙을 모르고있었지만 ㅎㅎ

지금까지 안해봤던 수동 매핑도 직접 해보고, 간단한 내장 메서드의 엄청난 활용 방법도 알게되었다.


추가 활용 문제

반대로 10진법 -> B진법으로 변환한다면?

  1. 수동 매핑
import java.io.*;
import java.util.StringTokenizer;

public class Main {
    static int toInt(String s) {
        return Integer.parseInt(s);
    }

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        int n = toInt(st.nextToken());
        int b = toInt(st.nextToken());

        StringBuilder sb = new StringBuilder();

        while (n > 0) {
            int remainder = n % b;

            if (remainder >= 10) {
                sb.append((char)(remainder - 10 + 'A'));
            } else {
                sb.append((char)(remainder + '0'));
            }

            n /= b;
        }

        System.out.println(sb.reverse());
    }
}
  1. 내장 메서드
import java.io.*;
import java.util.StringTokenizer;

public class Main {
    static int toInt(String s) {
        return Integer.parseInt(s);
    }

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        int n = toInt(st.nextToken());
        int b = toInt(st.nextToken());

        System.out.println(Integer.toString(n, b).toUpperCase());
    }
}

Integer.toString(n, b)는 값이 소문자로 반환되기 때문에 대문자로 추가 변환이 필요하다.

0개의 댓글