백준 문제를 해결하던 중 여러 종류의 진법 수를 10진법으로 변환하는 문제가 나왔다.
주어진 문제에서 변환 전 숫자를 10부터는 알파벳을 이용해 표현한다.
B진법 수 N이 주어진다. 이 수를 10진법으로 바꿔 출력하는 프로그램을 작성하시오.
10진법을 넘어가는 진법은 숫자로 표시할 수 없는 자리가 있다. 이런 경우에는 다음과 같이 알파벳 대문자를 사용한다.
A: 10, B: 11, ..., F: 15, ..., Y: 34, Z: 35
나의 처음 접근 방식은
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를 빼서 직접 값을 수동으로 계산하는 코드이다.
정답을 맞춘 후 다른 사람들은 어떻게 코드를 작성했나 확인하기 위해 구글링을 해보니
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진법으로 변환한다면?
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());
}
}
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)
는 값이 소문자로 반환되기 때문에 대문자로 추가 변환이 필요하다.