본문 바로가기

프로그래밍/알고리즘

[Python] 분수의 순환소수, 순환마디 구하기

반응형

예전에 순환소수를 구하는 코드를 만들어서 포스팅을 했었다. ( https://daewonyoon.tistory.com/354 ) 손으로 하는 나누기를 그대로 따라하면서, 나머지를 기억하고, 이전에 나왔던 나머지가 다시 나오면, 싸이클이 반복되어 순환마디를 구할 수 있다는 아이디어였다.

다른 방법이 좀 더 간단할지 어쩔지 궁금해서 대충 실험을 해 봤다. 이번 아이디어는 이렇다. 순환소수는 결국 999...99 를 분모로 하는 소수로 바꿀 수 있다. 그러니, 주어진 분수의 분모가, 999...99 를 떨어지게 나눌 때까지, 9, 99, 999, 9999, ... 를 늘려가고, 나누어 떨어지면, 그 배수를 분자에도 곱하면, 분자가 순환마디가 된다.

테스트를 해 본 것은 다음과 같다.

def solve(a):
	qq = 9
	n = 1
	while True:
		if qq % a[1] == 0:
			m = qq // a[1]
			repeat = str(m * a[0])
			while len(repeat) < n:
				repeat = "0" + repeat
			break
		qq = qq*10 + 9
		n += 1
	return f"0.({repeat})"

a = (4, 17)
solve(a)
## '0.(2352941176470588)'
4/17
## 0.23529411764705882
solve((1, 7))
## '0.(142857)'
solve((1, 3))
## '0.(3)'

대충 원하는 결과가 나온다. 위 결과에서 소수점 아래의 괄호는 반복되는 순환부분을 표시한다. 즉, 0.(3) 은 0.33333.... 을 뜻한다.

그런데, 결과가 안 나오는 경우도 있다. solve((1, 316)), solve((1, 130)) 등은 결과가 나오지 않고 무한루프에 걸린다. 이유는, 316, 130 등은 짝수이니까, 999...999 가 아무리 커져도, 나누어 떨어지게 할 수 없다. 하지만, 1/316 은 무한순환소수는 맞거든? 이런 경우는 어떻게 해야 하나?

10은 2, 5의 배수이다. 분모에서 2, 5 인자를 다 빼야 한다. 1/130 = 1/10 x (1/13) 이니까 1/13 의 소수표현을 구하면, 0.0xxxxxxxxxx 이렇게 된다. (여기서 xxxxxxx 가 1/13 의 소수자리) 이런식으로 분모가 2의 n승, 5의 m승이라면, 2의 m승, 5의 n 승을 구하고, 10의 (m+n) 승을 빼놓고, 소수를 구한 뒤 소수자리수만 뒤로 밀면 되겠다.

시간나면 나머지 구현 해봐야지.

--

 

728x90