Processing math: 13%
 

컴퓨터가 실수를 연분수 표현(continued fraction)으로 나타내는 방법

1. 유리수의 continued fraction

 

continued fraction은 실수를 수렴하는 유리수의 수열로 표현하는 것이다.

 

이는 problem solving에서 유용할 수 있는데, 쉽게 계산될 수 있으며, 실수의 최적 유리수 근사를 찾는데 효과적으로 사용될 수 있어서 그렇다.

 

게다가 정수론에서 유용하게 사용되는 유클리드 알고리즘과 연관되어있다.

 

어떤 정수 a0,a1,...,ak에 대하여, a1,a2,...,ak가 1이상의 자연수일때,

 

r=a0+1a1+1...+1ak를 유리수 r의 연분수 표현(continued fraction)이라고 부른다.

 

이를 r을 간단하게 r=[a0;a1,a2,...,ak]로 쓴다.

 

1-1) 성질

 

임의의 유리수 r에 대하여 연분수 표현을 정확히 다음 2가지중 하나로 나타낼 수 있다.

 

r=[a0;a1,...,ak,1]=[a0;a1,...,ak+1]

 

그런가..??

 

모든 유리수 p/q의 continued fraction은 위와 같은 유일한 2가지 유한집합으로 표현할 수 있다는 것이다.

 

여기서 a0는 정수이고 a1,a2,...,ak는 자연수이다.

 

 

2. 무리수의 continued fraction

 

rk=[a0;a1,...,ak]에 대하여, 무리수 r의 continued fraction은...

 

r=a0+1a1+1a2+...=lim

 

이때 r = [a_{0};a_{1},a_{2},...]으로 나타낸다.

 

여기서 몇가지를 관찰할 수 있는데..

 

1) 먼저 정수 k에 대하여...

 

r + k = [a_{0} + k; a_{1},...]이다.

 

2) r에 대해 역수를 취하면...?

 

\frac{1}{r} = [0;a_{0}, a_{1}, ...], a_{0} > 0

 

\frac{1}{r} = [a_{1};a_{2}, ... ], a_{0} = 0이다.

 

3) 모든 무리수는 연분수 표현이 무한집합이다. 무한집합으로 나타난 연분수 표현은 무리수가 된다.

 

3. complete quotients

 

s_{k} = [a_{k}; a_{k+1}, a_{k+2},....]라고 정의되는 s_{k}를 r의 k번째 complete quotient라고 한다.

 

이를 이용하면.. 무리수 r의 연분수 표현은..

 

r = [a_{0}; a_{1}, ... , a_{k-1}, s_{k}]

 

특히 정의로부터 s_{0} = [a_{0};a_{1},...] = r이다.

 

또한 s_{k} = [a_{k};s_{k+1}] = a_{k} + \frac{1}{s_{k+1}}이다.

 

이는 a_{k}s_{k}보다 작거나 같은 최대의 정수 a_{k} = \left \lfloor s_{k} \right \rfloor이다.

 

그리고 a_{k}, s_{k}를 모두 안다면.. s_{k+1}은...

 

s_{k+1} = \frac{1}{(s_{k} - a_{k})}로 구할 수 있다.

 

 

4. 구현 예시 - rational to continued fraction

 

유리수 r에 대하여, complete quotients s_{k}에서 s_{k+1}로 가는 점화식은...

 

s_{k} = \left \lfloor s_{k} \right \rfloor + \frac{1}{s_{k+1}}

 

따라서, s_{k+1} = (s_{k} - \left \lfloor s_{k} \right \rfloor)^{-1}

 

r이 유리수라면, s_{k}도 유리수이므로, s_{k} = \frac{p_{k}}{q_{k}}라고 하자.

 

여기서 p_{k}, q_{k}는 정수이다.

 

s_{k+1} = (\frac{p_{k}}{q_{k}} - \left \lfloor \frac{p_{k}}{q_{k}} \right \rfloor)^{-1}

 

여기서 \left \lfloor \frac{p_{k}}{q_{k}} \right \rfloorp_{k}q_{k}로 나눈 몫이므로,

 

p_{k} = q_{k} * (\left \lfloor \frac{p_{k}}{q_{k}} \right \rfloor)  + p_{k} mod q_{k}

 

양변을 q_{k}로 나눠서 다음과 같이 쓸 수 있다.

 

s_{k+1} = (\frac{p_{k} mod q_{k}}{q_{k}})^{-1} = \frac{q_{k}}{p_{k} mod q_{k}}

 

따라서 r = s_{0} = \frac{p_{0}}{q_{0}}부터 시작해서, p_{k+1} = q_{k}, q_{k+1} = p_{k} mod q_{k}

 

q_{k}가 0이 아닐 때까지 반복적으로 구하면 된다.

 

여기서 당연하지만 p,q는 서로소이다.

 

def continued_fraction(p,q):
    
    s = []
    
    while q:
        
        s.append(p//q)
        p,q = q,p%q
    
    return s

 

5. convergent

 

유리수 r_{0}, r_{1}, ...은 r의 convergent라고 부른다.

 

각각의 r_{k} = [a_{0};a_{1}, ... , a_{k}] = \frac{p_{k}}{q_{k}}는 k번째 convergent라고 부른다.

 

여기서 r_{k} = \frac{p_{k}}{q_{k}}라고 할 때, 다음 식이 성립한다.

 

\frac{p_{k}}{q_{k}} = \frac{a_{k}p_{k-1} + p_{k-1}}{a_{k}q_{k-1} + q_{k-2}}

 

단, p_{-1} = 1, p_{-2} = 0, q_{-1} = 0, q_{-2} = 1이다.

 

 

연분수 표현 [a_{0};a_{1}, a_{2}, ... , a_{n}]이 주어진다고 해보자.

 

이를 유리수 r_{n} = \frac{p_{n}}{q_{n}}으로 나타내고 싶다면, 위 점화식으로부터 n번째 p,q 항까지 반복적으로 구하면 된다.

 

k = 0이라면,

 

\frac{p_{0}}{q_{0}} = \frac{a_{0}*p_{-1} + p_{-2}}{a_{0}*q_{-1} + q_{-2}} = \frac{a_{0}*1+0}{a_{0}*0+1}

 

여기서 p_{0}, q_{0}를 구할 수 있고,

 

k = 1이라면,

 

\frac{p_{1}}{q_{1}} = \frac{a_{1}*p_{0} + p_{-1}}{a_{1}*q_{0} + q_{-1}} 으로 p_{1}, q_{1}을 구할 수 있다.

 

이런식으로 모든 a_{0}, a_{1}, ... , a_{n}까지 순회하여 p_{n}, q_{n}을 구한다면, 그것이 유리수 표현이 된다.

 

def convergent(f):
    
    p = [0,1]
    q = [1,0]

    for a in f:
        
        p.append(p[-1]*a + p[-2])
        q.append(q[-1]*a + q[-2])
    
    return p[-1],q[-1]

 

 

6. 연습문제

 

10386번: \text{Con}+\cfrac{\text{tin}}{\text{ued}+\cfrac{\text{Frac}}{\text{tions}}} (acmicpc.net)

 

10386번: \text{Con}+\cfrac{\text{tin}}{\text{ued}+\cfrac{\text{Frac}}{\text{tions}}}

For each test case, display the case number followed by the continued fraction representation of r1+r2, r1−r2, r1×r2, and r1/r2 in order, each on a separate line. Use 64-bit integers for all of your calculations (long long in C++ and long in Java).

www.acmicpc.net

 

7. 풀이

 

유리수의 연분수 A,B가 주어질때, A+B, A-B, A*B, A/B를 연분수로 나타내는 문제

 

연분수에 대한 사칙연산 알고리즘이 있는것 같은데 무슨 말인지 모르겠더라고...(기회가 있으면 다시 보도록 하고..)

 

다행히 n이 작다보니 연분수를 유리수 p/q로 나타내고, 유리수에 대한 사칙연산을 직접 구한 다음

 

기약분수로 나타내고, 이를 다시 연분수로 표현하는 과정을 거치면 된다

 

당연히 예를 들어 합의 경우는 p1/q1 + p2/q2 = (p1*q2 + p2*q1)/q1*q2 처럼 통분해서 (p1*q2+p2*q1), (q1*q2)를 구하고 기약분수로 나타내야한다.

 

유리수 a/b를 기약분수로 나타낼려면?

 

a,b의 최대공약수 g를 구하면 a = gr, b = gk, (r,k는 서로소)이므로 a//g, b//g를 구하면 된다.

 

#연분수의 사칙연산
#연분수 > 유리수 > 사칙연산(합,차,곱,나눗셈) > 기약분수 > 연분수

#연분수를 유리수로 바꾸는 함수
#p_k = a_k*p_(k-1) + p_(k-2)
#q_k = a_k*q_(k-1) + q_(k-2)

#p_(-1) = 1, p_(-2) = 0
#q_(-1) = 0, q_(-2) = 1
def convergent(f):
    
    p = [0,1]
    q = [1,0]

    for a in f:
        
        p.append(p[-1]*a + p[-2])
        q.append(q[-1]*a + q[-2])
    
    return p[-1],q[-1]

#유리수 p/q를 연분수로 나타내는 함수
#p,q는 서로소
def continued_fraction(p,q):
    
    f = []

    while q:
        
        f.append(p//q)
        p,q = q,p%q
    
    return f

#a,b의 최대공약수를 구하는 유클리드 알고리즘
def gcd(a,b):
    
    while b != 0:
        
        a,b = b,a%b
    
    return a

#유리수 p/q를 기약분수로 나타내는 함수
#p,q의 최대공약수 g에 대하여 p = gr, q = gk, r,k는 서로소
#p//g, q//g가 기약분수
def reduced(p,q):
    
    g = gcd(p,q)

    return p//g, q//g

t = 1

while 1:
    
    n1,n2 = map(int,input().split())

    if n1 == 0 and n2 == 0:
        
        break
    
    else:
        
        #연분수
        f1 = list(map(int,input().split()))
        f2 = list(map(int,input().split()))
        
        #연분수 > 유리수
        p1,q1 = convergent(f1)
        p2,q2 = convergent(f2)
        
        #유리수 사칙연산
        #> 기약분수
        #> 연분수
        add = continued_fraction(*reduced(p1*q2+p2*q1,q1*q2))
        minus = continued_fraction(*reduced(p1*q2-p2*q1,q1*q2))
        multiply = continued_fraction(*reduced(p1*p2,q1*q2))
        divide = continued_fraction(*reduced(p1*q2,q1*p2))

        print(f'Case {t}:')
        print(' '.join(map(str,add)))
        print(' '.join(map(str,minus)))
        print(' '.join(map(str,multiply)))
        print(' '.join(map(str,divide)))
        t += 1

 

728x90