프로그래밍/파이썬

[돌아만가는 알고리즘] 10진수 정수를 입력받아 다른 진수로 표현하기

Xaviere 2022. 3. 5. 01:40
def basechange(number,base):
	numberraw = number
	baseraw = base
	result = ''
	while number > 0:
		quotient = number//base
		if number - quotient*base == 0:
			result = result + '0'
		else:
			result = result + str(number-quotient*base)
		number = quotient
	print('{}를 {}진수로 표현하면 : {}'.format(numberraw,baseraw,result[::-1]))

basechange(100,4)

 

우선 어떻게 작동하는지에 대한 설명

basechange라는 함수에 number라는 수와 base라는 진수가 주어지면 (이하 number는 n, base는 b로 표현)

주어진 수 n을 b로 나눈 몫 q를 구한 다음에, n-q*b를 해준다. 즉, 나머지를 구한다.

나머지가 0이 나오면 b진수 표현에서 첫번째 자리는 0,

아니라면 나머지(= n-q*b)가 첫번째 자리가 될 것이다.

이제 한 번 나눴으니, n을 q로 대치한 후,

다시 b로 나눠서 몫을 구하고, 나머지를 구하고 여기서 나온 나머지가 b진수 표현에서 두번째 자리가 된다.

이걸 반복하면 마지막 계산을 끝낸 다음엔 n이 0보다 작아지면서 b진수 표현에서 모든 자리수를 구할 수 있게 된다.

 

예를들어, 10을 2진수로 표현하면

1) 10/2 = 5 -> 나머지가 0, 첫째자리수는 0

2) 5/2 = 2 -> 나머지가 1, 둘째자리수는 1

3) 2/2 = 1 -> 나머지가 0, 셋째 자리수는 0

4) 1/2 = 0 -> 나머지가 1, 넷째 자리수는 1 이후는 더이상 나누는 것에 의미가 없으므로 여기서 끝

그래서 1010(2)로 표현할 수가 있다.

 

코드를 보면

basechange라는 함수를 정의했다. 변수로는 number와 base가 들어가는데

number는 10진수 정수를 받을것이고, base는 주어진 number를 표현할 진수이다.

while문은 조건을 number > 0으로 해준다.

이제 number를 base로 나눈 몫 quotient를 구하고 number에서 base*quotient를 빼서 나머지를 구해준다.

이때 나머지가 0이라면 result라는 빈 string에 0을 붙여주고, 아니라면 해당 나머지를 붙여준다.

그 다음은 위에서 구한 몫을 사용할 것이므로 number = quotient를 이용해서 number를 갈음해준다.

또 base로 number를 나눠서 몫을 구하고 나머지를 구하고 result string에 붙여준다.

이를 반복하다보면 결국은 몫이 0이되어 while문을 탈출하고, 결과를 print해준다.

함수 초반에 baseraw와 numberraw가 여기서 사용되는데 사실 base는 변경되는 값이 아니지만,

while문이 모두 돌아가게 되면 number = 0이 되기 때문에, 따로 저장을 해두지 않았다면

'0을 b진수로 표현하면...'

이라는 문장이 출력되게 된다.

그래서 while문이 시작되기 전에 따로 입력된 number를 numberraw쪽에 한 번 더 저장을 시켜둔것이다.

또, 위 과정을 거치면 우리가 result에 붙여준 값들은 예시와 다르게 각 자리수가 반대로 표현되게 된다.

즉, 10을 2진수로 표현했는데 0101(2)가 되는 것이다. 그렇기 때문에

result[::-1]을 통해 해당 문자열을 반대로 뒤집어 준다.

이제 basechange(100,4)를 실행시키면

'100을 4진수로 표현하면 : 1210' 

이 출력되는 것을 확인할 수 있을것이다.

( 0 + 4 + 16*2 + 64*1 = 100)

 

코드를 보면

1) 왜 quotient를 구할 때 /연산자가 아닌 //연산자를 사용했는가

2) 어차피 나머지를 string에 붙여줄건데 굳이 quotient를 구하고, 또 이걸 base와 곱해서 number에서 빼주는가

가 의문점일 수 있다.

답을 남기자면,

1) quotient를 구할 때 //를 사용하는 이유는 / 연산자는 return type이 정수(int)가 아니기 때문이다.

int(number/base)

로 억지로 int형으로 바꿔주면 가능하긴 하지만... 굳이..?

2) 왜 %연산자를 사용해서 나머지가 구하지 않았는가 하면, 지금 사용한 알고리즘은 주어진 number로 부터 첫째 자릴 수를 구한 이후, 다음 자리 수를 구할 때 반드시 number를 base로 나눈 몫이 필요하기 때문이다.

사실 고치자면,

while number > 0:
	quotient = number//base
    if number%base == 0:
    	result = result + '0'
    else:
    	result = result + str(number%base)
    number = quotient

라고 고쳐도 되겠지만, 아직 프로그래밍 그리고 컴퓨터가 명령어를 어떻게 처리하고, 숫자를 인식하는 과정이 어떻게 되는지에 대해 이해도가 부족하기 때문에 저렇게 코딩을 해봤다.

 

더 고민해보자면

우선 불편했던건 result 문자열을 뒤집어 줘야했다는 점이다.

만약 주어진 number를 base의 거듭제곱을 통해 나눌 수 있는 가장 큰 base의 거듭제곱을 사용해서 나누고

하나 줄여서 나누고 하나 줄여서 나누고 시도해보려했지만, 생각만큼 잘 되질 않았다.

물론, 가능할 것 같긴하다. 단지 고민하기에 귀찮았을 뿐..

 

또 이건 10진수 정수를 다른 진수, 그것도 사실은 2~9진수로 바꿔주는 함수이다.

3진수로 입력된 수를 7진수로 바꿔주진 못한다.

물론 3진수를 10진수로 바꾸고 다시 7진수로 바꾸는 과정을 거치면 되겠지만..

아름답지 못하다. 11진수 이상은 표현하지 못한다는 점도 아쉽다.