본문 바로가기

프로그래밍/Python

[Python] 분수의 무제한 소수표현 구하기

반응형

분수의 십진수 소수 표현을 자릿수 제한없이 구하는 함수.

from typing import List, Tuple


def get_div_decimals(n: int, m: int = 1, limit: int = 0) -> Tuple[int, List[int], List[int]]:
    q = m // n
    m = (m % n) * 10

    dividend = m
    dividend_list = []
    digit_list = []

    while True:
        # print(digit_lst)
        if dividend in dividend_list:
            break
        dividend_list.append(dividend)
        digit = dividend // n
        dividend = (dividend % n) * 10
        digit_list.append(digit)

    idx = dividend_list.index(dividend)

    # print(digit_list, idx)

    non_cyc = digit_list[:idx]
    cyc = digit_list[idx:]
    return q, non_cyc, cyc


def get_div_decimals_repr(n: int, m: int = 1, limit: int = 0) -> str:

    q, non_cyc, cyc = get_div_decimals(n, m, limit)
    s = f"{q}." + "".join(map(str, non_cyc)) + "(" + "".join(map(str, cyc)) + ")"

    return s


for a, b in [(1, 3), (1, 6), (1, 8), (4, 3), (15, 13), (100, 94)]:
    print(f"{a}/{b} =", get_div_decimals_repr(b, a))
    # print(f"{a}/{b} =", a / b)

손으로 한자리 한자리 구하는 걸 그냥 코드로 옮긴 것이다. 순환마디를 구하기 위해서, 매 단계마다 나누는 피젯수를 dividend_list 에 차례대로 저장해 놓는다. 이번에 만들어진 피젯수가 이미 list 에 담겨있다면, 똑같은 짓이 반복된다.

딱 떨어지는 소수도, 마지막에 0이 반복되는 소수로 표현한다.

1/3 = 0.(3)
1/6 = 0.1(6)
1/8 = 0.125(0)
4/3 = 1.(3)
15/13 = 1.(153846)

- float 연산의 신뢰할 수 있는 자릿수 갯수를 정확히 안다면, 한자리씩 나눗셈을 하지 않고, 좀 더 여러자리를 해도 된다.

- 처음 주어진 피젯수를 10^n 하여서 정수결과를 구하고, 자릿수만 n자리 거꾸로 옮겨주는 방식을 취할 수도 있다. 파이썬은 큰 자릿수 연산에 제한이 없으니까.

see also : daewonyoon.tistory.com/353 , https://daewonyoon.tistory.com/458 , http://daewonyoon.pythonanywhere.com/fraction/

----

2021년 10월 21일 수정 : 100/94 같은 분수에 대해 순환마디를 잘 못 구하는 버그가 있어서, 수정하였음. 소수점 위의 몫을 구할 때의 나머지는 잊어버려야 하는데, 기억하고 있어서 순환마디가 하나씩 더 나왔었다.

728x90