코드 저장소

공부에는 끝이 없다!

JAVA/코딩 테스트

백준 문제 풀이 - 일반 수학 1단계 - 2745번 진법 변환 (브론즈 2)

VarcharC2K 2023. 8. 23. 15:26

어느덧 일반 수학 단계까지 넘어왔다.

이번 문제는, B진법의 수 N이 주어졌을 때, 이 숫자를 10진법으로 바꾸어 출력하는 프로그램을 구현하는 문제이다.

우선, 내가 수학에 좀 약한지라 진법의 변환을 어떤식으로 하는지 이해를 못해서 진법에 대해서 먼저 찾아봐야 했다.

 

해당 문제를 chatGPT를 이용하여 질문을 해보았더니 다음과 같은 답변을 얻을 수 있었다.

 

36진법을 10진법으로 변환하는 과정은 다음과 같이 진행됩니다. 각 자릿수의 값을 계산하고 해당 값을 36진법에서 10진법으로 변환하여 더해주면 됩니다.
예를 들어, ZZZZZ의 36진법 값을 10진법으로 바꿔보겠습니다:
ZZZZZ(36진법) = Z * 36^4 + Z * 36^3 + Z * 36^2 + Z * 36^1 + Z * 36^0 = 35 * 36^4 + 35 * 36^3 + 35 * 36^2 + 35 * 36^1 + 35 * 36^0 = 60466175
따라서 ZZZZZ(36진법)는 60466175라는 값으로 10진법으로 표현됩니다.

 

해석해보면, Z라는 값은 36진법에서 10진법의 35라는 값과 동일하다.

여기서 알파벳을 사용하는 이유는 10진법의 표현 한계상 한자리에 10을 넘는 숫자가 들어갈 수 없기 때문에, 이를 대체하기 위하여 사용하는 것이다.

즉, ZZZZZ라는 값을 10진법으로 바꾸기 위해서는 Z에 해당하는 35에 진법인 36의 각 자리 수만큼의 제곱을 모두 더한 값과 같다. (자세한 식은 위의 인용문을 참고한다.)

 

결과적으로 위의 식을 보면, Z의 10진법 변환값 * (진법의 수 * Index 값) 이라는 것을 알 수 있다.

따라서 나는 다음과 같이 코드를 구성하였다.

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

class Main{
    public static int n,temp,result;
    public static String s;

    public static void main(String[] args) throws IOException{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String[] str = br.readLine().split(" ");
        s = str[0];
        n = Integer.parseInt(str[1]);
        result = 0;

        for(int i = 0; i < s.length(); i++){
            temp = (int)s.charAt(i);
            if(temp > 58){
                temp = temp - 55;
            }

            result += temp * Math.pow(n,i);
        }

        System.out.println(result);
    }
}

코드를 살펴보면, 문자열의 각 문자를 가져와서 int 값으로 변환하고 58(문자로 치면 ":" 이다. 즉, 9를 넘어서는 값)이 넘어가면 -55를 해줘 A라는 문자의 값이 10으로 변환 되도록 하였다.

그후 계산에 따라 Math의 Pow()메서드를 사용하여 진법의 숫자 n에 인덱스 값 i를 곱하게 한 후 출력하였다.

위 계산식을 돌려보면 ZZZZZ를 넣었을때 60466175라는 정상적인 값을 얻을 수 있는데, 실제로 제출을 해보니 오류가 뜨는 것을 확인하였다.

 

결과적으로 내 코드에는 2가지 문제점이 있었는데, 한가지는 pow 메서드를 사용할때 인덱스 값을 i로 넣어주면서 문자가 다른 경우를 상정하지 않았다는 점이다.

즉, ZAZAA라는 값이 들어오면 나는 가져올때는 Z라는 값을 가지고 왔으때, 해당 인덱스는 가장 높은 값인 4가 되어야 한다. 하지만 나는 반복문에서 쓰는 값을 그대로 가지고 왔으므로 첫번째 자리인 Z는 0의 인덱스를 가지게 되어 결과 값이 맞지 않게 된다.

 

다른 하나는 아무리 생각해 봐도 반례가 생각이 나지 않아서 꽤나 고전했는데, chatGPT에게 정상 코드를 작성 시키고 비교를 해보니 기초적인 실수였다는 것을 알 수 있었다.

우선 ChatGPT가 작성해 준 코드는 다음과 같다.

 

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

class Main {
    public static int n, result;
    public static String s;

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String[] str = br.readLine().split(" ");
        s = str[0];
        n = Integer.parseInt(str[1]);
        result = 0;

        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            int digit = Character.isDigit(c) ? c - '0' : c - 'A' + 10;
            result = result * n + digit;
        }

        System.out.println(result);
    }
}

나와 로직은 동일 하지만, 좀더 간결하게 잘 짜여진 것 같다.

눈여겨 볼 점은, int 변수인 digit에 값을 넣을 떄인데, 잘보면 chatGpt는 isDigit() 메서드를 사용하여 해당 인덱스의 문자가 숫자인지 아닌지를 검증 한 후, 각 문자를 정확한 int 값으로 변환한다.

 

무엇이 잘못 된 것인지 알겠는가?

나는 문자가 숫자로 들어오는 경우 변환을 해주지 않았다.

 

즉, 실제로 9999라는 값이 들어와도 해당 값은 int 9로 들어오는 것이 아닌 아스키 코드값인 57로 들어오게 되므로 계산이 맞질 않는 것이다.

따라서 내 코드를 다음과 같이 변환하였다.

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

class Main{
    public static int n,temp,result;
    public static String s;

    public static void main(String[] args) throws IOException{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String[] str = br.readLine().split(" ");
        s = str[0];
        n = Integer.parseInt(str[1]);
        result = 0;

        for(int i = s.length()-1; i >= 0; i--){
            temp = (int)s.charAt(i);

            if(temp >= 65){
                temp = temp - 55;
            } else {
                temp = Integer.parseInt(String.valueOf(s.charAt(i)));
            }

            result += temp * Math.pow(n,s.length()-i-1);
        }


        System.out.println(result);
    }
}

우선, 인덱스를 정상적으로 잡아 주고, else 문을 이용하여 해당 문자가 숫자인 경우 int로 파싱하여 계산하도록 코드를 변경하였다.

제출을 해보니 정상적으로 값이 나오는 것을 확인 할 수 있었다.

 

아스키 코드 값으로 변환해주는건 기초적인 것이였는데 문제를 풀다보니 오히려 작은 부분에서 실수가 잦은 것 같다.

로직도 로직이지만, 기초적인 부분을 간과하지 않도록 유의가 필요할 것 같다.