진법 변환
아스키 코드
컴퓨터는 0과 1로만 이루어져 있는 이진법으로 이루어져 있는 이진수로만 읽을 수 있다고 아스키 코드 파트에서 잠깐 언급한 적이 있습니다. 하지만 우리가 평소에 사용하고 있는 진법은 10진법이기 때문에 컴퓨터가 문자를 읽으려면 10진법에서 2진법으로 변환하는 과정을 거쳐야 합니다.
참고로 우리가 현재 문자에 번호를 매칭 시키는 방법은 16진법인 유니코드를 사용하고 있는데요. 이것도 컴퓨터가 읽을 수 있게 바꾸려면 16진법에서 2진법으로 변환해야 합니다.
이렇게 컴퓨터 내부에는 진법 변환이 활발하게 이루어져 있습니다. 이 파트에서는 우리가 직접 진법 변환을 하는 방법을 배우고 관련 문제들을 풀어보려고 합니다.
11진법 ~ 36진법 표기법
10진법에서는 0부터 9까지의 수를 모두 사용하였기 때문에 11진법부터는 알파벳을 이용하여 값을 설정하고 있습니다.
왜 알파벳으로 설정하냐면 만약 1010이라는 11진법 수가 있다고 가정해봅시다. 그러면 우리는 1010이 1과 0 따로따로 이루어진 수인지, 혹은 10인 숫자 2개로 이루어진 수인지, 둘 다 섞인 것인지 구분할 수 없습니다. 그래서 8 → 9 다음에는 10이 아닌 알파벳 a 로 수를 표시합니다. 10 2개로 이루어진 값이라면 aa라고 작성할 것이고, 1과 0과 10으로 이루어졌으면 10a로 입력될 것입니다.
진법이 더 커진다면 알파벳을 추가로 사용합니다. 12진법은 b까지 사용하는 것이고, 36진법은 z까지 사용합니다. 알파벳은 문제에 따라 소문자로 설정하는 문제도 있고, 대문자로 설정하는 문제도 있습니다.
X진법 → 10진법 변환
어떠한 진법을 10진법으로 변환하는 방법은 두 가지가 있습니다. 하나는 직접 계산하여 10진법으로 변환하는 방식이고, 다른 하나는 int()함수를 이용하는 것입니다.
직접 계산하기
먼저 10진법으로 변환하기 전에 우리는 먼저 10진법이 어떤 식으로 되어있는지 알아야합니다.
만약 123이라는 숫자가 있으면 아래와 같은 식이 나오게 됩니다.
이렇게 자리수가 바뀔 때마다 10의 지수에 1이 하나씩 더해지고 있습니다.
X진법에서 10진법으로 변환할 때도 마찬가지입니다. 만약 1593이라는 X진법 수가 있다고 가정하면 이것을 10진법으로 변환할 경우 아래와 같은 식으로 값을 구할 수 있게 됩니다.
이번엔 좀 어렵게 알파벳과 숫자가 섞여 있는 수를 10진법으로 구해봅시다. a는 10에 해당하고, c는 12에 해당합니다.
일단 c는 1의 자리이므로 12 * 15 ^ 0 이 되겠고, 7은 10의 자리에 위치하므로 7 * 15 ^ 1입니다. 3은 100의 자리이므로 3 * 15 ^ 2이고, a는 1000의 자리에 있으므로 10 * 15 ^ 3이 되겠네요.
그래서 15진법인 a37c를 10진법으로 변환하면 34542라는 값이 나오게 됩니다.
int()함수 사용하기
사실 이것은 int()함수를 이용하여 쉽게 10진수로 값을 변환할 수 있습니다.
이렇게 첫 번째 값엔 10진법으로 바꾸려고 하는 수를 넣어주고, 두 번째 값에는 해당 수가 현재 몇 진법인지 입력해주시면 됩니다.
위에 적은 a37c라는 수를 int()함수에 넣으면 아래 코드와 같이 34542를 바로 출력할 수 있게 됩니다.
10진법 → X진법 변환
X진법에서 10진법으로 변환하는 방법은 쉬웠지만, 10진법에서 X진법으로 변환하는 방법은 좀 귀찮은 편입니다.
X진법 -> 10진법에서는 X의 곱하기와 X의 거듭 제곱을 이용하여 문제를 풀었는데요. 10진법 -> X진법은 그 반대로 X로 나눠서 나온 몫과 나머지를 이용합니다. 계속 X로 나누면서 나머지는 수로 표현하고, 남은 몫을 계속 X로 나눠주면서 반복하는 형식입니다.
이렇게 글로만 보면 어렵기 때문에 바로 위에서 썼던 예시인 10진법 수인 34542를 15진법으로 바꾸어봅시다.
직접 계산하기
먼저 34542을 15로 나누어보면 몫은 2302이고, 나머지는 12가 나오게 됩니다. 12는 알파벳 c와 같습니다.
그다음 2302을 15로 나누어보면 몫은 153, 나머지는 7이 나오게 됩니다.
153를 15로 나누어주면 몫은 10, 나머지는 3이 나오게 됩니다. 여기서 10을 15로 나누면 몫이 0이기 때문에 멈춰야 합니다. 아니면 한 번 더 15로 나눠서 나머지 10을 얻어도 됩니다. 여기서 10은 알파벳 a와 같습니다.
그래서 이걸 아래에서 위 방향으로 글자를 적어주면 a37c가 나오게 됩니다.
코드로 구현을 해본다면 몫이 0이 아닐 때까지 돌려야 해서 while문을 사용하고, 리스트를 하나 만들어서 거기에 나머지 값을 추가해주는 방식으로 해야 할 것 같습니다.
val이라는 딕셔너리는 0부터 35까지의 출력 값을 0부터 z까지의 문자로 변환해주는 딕셔너리 입니다. 딕셔너리의 update 메소드는 딕셔너리끼리 합칠 때 사용합니다.
이제 n과 나머지를 저장해둘 리스트인 ans를 선언하였습니다. 그리고 무한루프인 while문을 만들어주고, n의 값을 15로 나누어주다가 0이 되면 루프를 빠져나올 수 있게 break문을 추가하였습니다.
ans에 값을 저장하려면 나머지 값만 필요하기 때문에 x = n % 15를 해주고 ans에 val[x]의 값을 추가합니다. 그리고 n은 15로 나눈 몫으로 업데이트합니다.
이러면 이제 ans를 출력해주면 되는데, 거꾸로 출력해야하므로 [::-1]을 사용해주면 됩니다.
함수 사용하기(참고)
10진법 -> X진법으로 변환해주는 함수가 존재하긴 합니다. 하지만 아쉽게도 자주 사용되는 2진법, 8진법, 16진법 밖에 없습니다. 그래서 보통 문제를 풀 때는 이 함수들을 이용하지 않고 직접 계산하여 모든 진법들을 구현할 수 있게 만드는 편입니다.
2진법은 bin이라는 함수를 이용하여 10진수를 2진수로 만들 수 있습니다.
이렇게 bin()함수를 사용하면 0b + 이진수가 나오게 됩니다. 이진수를 없애는 방법은 format을 이용하는 방법이 있습니다. 혹은 bin(n)이 문자열이므로 bin(n)[2:]를 사용해도 됩니다. format을 사용하여 0b를 붙이고 싶으면 b앞에 #을 붙이면 됩니다.
8진법은 oct()라는 함수를 사용하여 10진수를 8진수로 바꿀 수 있습니다.
8진법도 마찬가지로 0o 부분을 삭제할 수 있습니다.
16진법은 hex()라는 함수를 사용합니다. 16진법은 10진법이 넘어가므로 10 -> a, 11 -> b, 12 -> c, 13 -> d, 14-> e, 15 -> f 의 알파벳을 추가적으로 사용합니다.
16진법도 마찬가지로 0x를 삭제하여 출력할 수 있습니다.
연습문제
우리는 이렇게 하여 X진법을 10진법으로 변환하는 방법과 10진법을 X진법으로 변환하는 방법을 배웠습니다.
이 진법 변환 문제는 X진법에서 Y진법으로 변환하는 문제가 주를 이루는데요. 여기서 Y진법이 10진법이 아니라면 X진법 → 10진법 → Y진법으로 10진법으로 한 번 바꾸는 과정을 거쳐서 Y진법으로 바꾸어주시면 됩니다.
BOJ 11005
(10진법) -> (B진법)으로 변환하여 출력하는 문제입니다.
이런 문제는 이미 우리가 10진법 -> X진법으로 직접 계산하여 변환할 때 배웠습니다. 문제랑 다른 점은 우리는 15진법을 정하여 작성했지만, 여기서는 B를 입력 받아서 진법 변환을 해야 합니다. 어려운 문제는 아니고 15가 들어간 내용을 전부 B로 바꾸어주면 됩니다.
일단 입력 값을 받는 코드를 작성합시다.
이 문제도 마찬가지로 n을 b로 반복해서 나누다가 몫이 0이 될 때 반복을 끝내면 됩니다.
직접 계산할 때처럼 n //= b로 n의 값을 업데이트 해주면서 나머지를 리스트에 넣어주면 됩니다. 그 전에 b로 나눈 나머지 값을 어떤 문자로 변환해야 하는지 딕셔너리를 통해 만듭니다.
이제 몫과 나머지를 이용하여 B진수를 만들어봅시다.
출력할 때는 마찬가지로 거꾸로 출력해야 하기 때문에 format과 join을 이용하여 ans[::-1]을 출력해주면 됩니다.
이번엔 좀 더 어려운 문제를 풀어봅시다.
BOJ 12174
숫자 0대신 대문자 알파벳 O가 나오고, 숫자 1대신 대문자 알파벳 I가 적혀있다고 합니다. 그리고 입력값을 보니까 8 * B 형식으로 문자열이 주어진다고 합니다. 그러면 우리는 8칸씩 문자를 확인하면 되겠네요.
문제를 읽어보면 문자열을 1과 0으로 바꾸어주고, 1과 0으로 이루어진 수를 10진수로 바꾸어주고, 이것을 문자열로 변환하여 문제를 출력해야 합니다.
그래서 정리하면 이 문제는 (문자열) -> (2진법) -> (10진법 = 아스키코드) -> (문자열)로 변환하는 문제로 볼 수 있습니다.
일단 입력 값을 전부 받을 수 있게 코딩을 해봅시다.
이제 8칸씩 문자열을 2진법으로 바꾸어봅시다. 입력값은 8의 배수이므로 for문을 이용하여 만들 수 있겠네요.
문자열을 2진법으로 변환하는 방법으로 리스트를 하나 만들고, for문을 이용하여 문자를 확인해서 I는 1로, O는 0으로 바꾸어 리스트에 넣어주면 됩니다. 그리고 join을 이용하여 합쳐줍시다.
(알파벳) -> (2진수)로 변환하였으니 이제 (2진수) -> (10진수 = 아스키 코드)로 변환해주면 됩니다. 여기서는 위에서 배운 int()함수를 이용하여 만들 수 있습니다.
이제 (10진수 = 아스키 코드) -> (문자열)로 변환해야 하는데요. 아스키 코드를 문자로 변환하는 함수는 4주차때 아스키 코드 파트에서 chr()이라는 함수를 배웠습니다.
일단 출력하기 전에 x값을 전부다 저장하고 출력해야하므로 ans라는 리스트를 만들어줍시다. 그리고 chr()함수를 이용하여 아스키 코드로 변환하고 ans에 저장해주면 됩니다.
이제 저장을 하였으니 join과 format을 이용하여 출력해주시면 됩니다.
풀어볼 문제
Last updated