❗ 이 글의 발단이 궁금하다면? 프로그래머스에서 "3진법 뒤집기" 풀어보기
N진법은 수를 셀 때, 자릿수가 올라가는 단위를 기준으로 하는 셈법의 총칭이다. '위치적 기수법'이라고도 한다.
우리는 태어날 때부터 지금까지 10진법의 세상 속에서 익숙하게 살고 있다. 10 단위로 측정하는 숫자들, 예를 들어서 신발 사이즈나 몸무게 같은 것들 말이다. 시간을 제외한다면 거의 모든 측정 단위들과 우리가 능숙하게 쓰는 숫자들은 대부분 10을 기준으로 셈을 한다.
그리고 수학 시간에 N진법에 대해 배우면서 우리가 쓰는 것이 표준이 아닌 세상도 있다는 걸 알게 되는데 컴퓨터 세상이 바로 대표적인 예시다. 컴퓨터는 이진법(2진법)으로 작성된 비트에서 시작했기 때문이다. 0(거짓), 1(참)으로 모든 걸 판별하기 때문에 2를 기준으로 셈한다.
초등학교 때 배운 기억을 곰곰이 되짚어보면 10진법에서는 변환하고픈 수를 N으로 계속 나눠서 가장 마지막에 나온 몫과 나머지를 순서를 뒤집어 역순으로 기재하면 N진법으로 표현한 수가 된다고 했다.
위 이미지는 10진법 수인 28을 2진법으로 변환한 예시다. 28을 2진법으로 표현하면 11100이 된다. 이걸 다시 10진법으로 바꾸는 방법은 가장 오른쪽 숫자부터 N의 0 제곱, 1 제곱을 자릿수에 각각 곱하는 걸 거듭한 다음 모두 더하면 된다.
이런 방식으로 말이다. 이걸 알고리즘으로 어떻게 만들 수 있을까?
이쯤에서 우리는 JavaScript
개발진에게 감사해야한다. 우리가 굳이 대수적 방법론을 하나하나 함수로 구현하지 않도록 String
과 Number
객체에 포함된 진법 변환 메서드가 있기 때문이다.
k.toString(N): 주어진 수 k를 N진법의 문자열로 변환
toString()
메서드가 단순히 이름대로 문자열로 바꿔주는 용도라고 생각했는데, 진법 변환까지 가능했다. MDN은 이 메서드를 "Number 객체는 Object 객체의 toString()메소드를 오버라이딩하며, Object.prototype.toString() 를 상속받지 않습니다. Number 객체에서 toString() 메소드는 특정 진수로 객체를 표현한 문자열을 환원합니다."라고 설명하고 있다.
즉, Number 객체에 해당하는 숫자를 매개변수 없이 해당 메서드를 썼을 때는 10진수로 문자열로 보여주기 때문에 잘 모르지만 매개변수로 '2 ~ 36' 값이 주어지면 주어진 값의 진법으로 변환된다.
그러므로 문제에서 주어진 대로 10진법 수를 3진법으로 변환하고 싶다면 주어진 수 n
을 n.toString(3)
으로 만들어 출력하면 3진법으로 변환된 걸 확인할 수 있다.
parseInt(k, N): N진법 수 k를 10진법 정수로 변환
parseInt()
함수 또한 문자열을 숫자로 변환할 때 가장 유용하게 쓰는 것 중 하나다. parseInt()
함수는 객체에 포함된 메서드가 아닌 개별적인 함수로 문자열 인자를 파싱하여 특정 진수(수의 진법 체계에서 기준이 되는 값)의 정수를 반환한다. 주어진 인자가 문자열이 아닐 경우에는 임의로 toString()
메서드를 적용시키는 추상 연산 과정을 거쳐 숫자로 변환한다.
그 과정에서 매개변수에 추가로 '2 ~ 36' 값이 옵션으로 주어지면 해당 진법의 숫자임을 인식하고 10진법으로 변환한다.
function solution(n) {
// 3진법으로 변환한 수를 reverse() 메서드 사용을 위해 전개 연산자로 문자열을 배열의 원소로 만들어주고,
// 다시 합쳐준 뒤 10진법으로 변환한다.
return parseInt([...n.toString(3)].reverse().join(''), 3);
}
메서드를 활용하니 풀이 자체는 어렵지 않았다. 이 문제를 계기로 두 메서드에 대해서 좀 더 깊이 있게 이해하게 된 계기가 되어서 유익했다.