본문 바로가기

비단뱀과 알/미세 팁

[Python] Incremental development, 점진적 개발

크리스마스 이브면서 토요일인데 난 왜 할 일이 많은 걸까.

 

파이썬에서 함수 짜는 과정은 큰 것부터 작은 것으로 들어가는 게 편하다.

일단 목적하는 밑그림을 설계해 두고, 필요한 부품들을 조금씩 채워 나가는 것이다.

이러한 방식을 'Incremental development' 라고 부른다.

 

입문 시 원하는 일을 설계하면서 뇌정지가 오는 상황을 막을 수 있다.

예를 들면,

 

https://wiki.mathnt.net/index.php?title=%EB%9D%BC%EB%A7%88%EB%88%84%EC%9E%94%EA%B3%BC_%ED%8C%8C%EC%9D%B4 

 

라마누잔과 파이 - 수학노트

개요 라마누잔은 1914년에 다음과 같은 공식을 발표 [RAM1914]\[\frac{1}{\pi}= \frac{2\sqrt2}{9801}\sum_{n=0}^{\infty}\frac{(4n)!(1103+26390n)}{(n!)^{4}396^{4n}}\] Chudnovsky 형제 [CHU88] \[\frac{426880 \sqrt{10005}}{\pi} = \sum_{k=0}^\inf

wiki.mathnt.net

 

$$ \frac{1}{\pi}=\frac{2\sqrt{2}}{9801}\sum_{k=0}^\infty \frac{(4k!)(1103+26390k)}{k!^4396^{4k}} $$

라마누잔의 원주율 공식을 이용해 원주율 근삿값을 찾아보자.

 

일단 식을 그대로 스케치 한다.

import math
def pi():
    k=0
    value=update_res(k)
    res=value
    while value>1e-16:
        k=k+1
        value=update_res(k)
        res=res+value
    return 2*math.sqrt(2)*res/9801

 

  • input 변수는 필요 없다.
  • 라마누잔 공식의 시그마 이하의 값을 return해주는 함수를 update_res(k) 로 만들기로 했다. 저 자리에 계산을 그대로 때려 박기에는 공식이 복잡해서 헷갈릴 것 같다.
  • sqrt를 처리해 주려면 math 모듈이 필요하다.
  • 주피터에서 표시되는 소숫점 아래 숫자가 16자리라서, 시그마 아래의 더해주는 값이 그보다 작으면 연산을 멈추도록 했다.

 

그래서 이제 필요한 것은 update_res(k) 를 정의해 주는 것이다.

 

def update_res(k):
    num=factorial(4*k)*(1103+26390*k)
    denum=(factorial(k)**4)*(396**(4*k))
    value=num/denum
    return value
    
import math
def pi():
    k=0
    value=update_res(k)
    res=value
    while value>1e-16:
        k=k+1
        value=update_res(k)
        res=res+value
    return 2*math.sqrt(2)*res/9801

 

(import math 이하의 라인은 이전의 코드박스와 완전히 동일하다. 전체 그림을 보여주기 위해 복사 붙여넣기 했다)

update_res(k)의 바디는 그냥 내 개인적인 스타일인데, 각 라인이 최대한 간결하도록 간단한 연산이라도 여러 줄에 나눠서 코드를 작성한다. 나중에 문제가 생겼을 때 알아보기가 쉽다.

 

파이썬에서는 \( a^b\)를 a^b가 아니라 a**b로 쓴다는 것만 유의하면 어렵지 않다.

 

그런데 또 update_res(k)를 돌리려면 factorial이 필요하다.

물론 파이썬의 math 모듈에서 팩토리얼 함수를 지원하기는 하지만, 이 포스트는 점진적인 개발 과정의 예시로 쓰고 있으므로 factorial을 새로 짜는 과정이 필요하다고 치자.

 

필요한 걸 또 추가하자.

 

def factorial(k):
    res=1
    while k>0:
        res=res*k
        k=k-1
    return res
    
def update_res(k):
    num=factorial(4*k)*(1103+26390*k)
    denum=(factorial(k)**4)*(396**(4*k))
    value=num/denum
    return value
    
import math
def pi():
    k=0
    value=update_res(k)
    res=value
    while value>1e-16:
        k=k+1
        value=update_res(k)
        res=res+value
    return 2*math.sqrt(2)*res/9801

 

이제 됐다. 코드는 아래서부터 짰지만, 돌리기는 위에서부터 돌리면 된다.

더이상 새로 만들어야만 하는 것이 없으므로 결과를 보자.

 

pi()  # 0.3183098861837907
1/math.pi  # 0.3183098861837907

 

개인적으로 군대에선 초코파이보다 몽쉘 좋아했음