안녕하세요.
이승혁입니다.
오늘은 몬테 카를로 방법(Monte Carlo method)을 사용해 원주율(3.14......)을 구해보도록 하겠습니다.
### 몬테 카를로 방법(Monte Carlo method) ?
난수를 생성해 함수의 값을 확률적으로 계산하는 방법
계산하려는 값이 닫힌 형식으로 표현되지 않거나 복잡한 경우에 근사적으로 계산할 때 사용됩니다.
원주율과 같이 딱 하나의 값으로 수렴하지 않는 경우에 사용합니다.
## 원 그리기
반지름 r, 중심이 (a, b) 인 원의 방정식은 (x - a)2 + (y - b)2 = r2 입니다.
반지름 1 , 중심 (0,0) 인 원의 식은 어떻게 될까요 ?
x^2 + y^2 = 1
파이썬으로 그려서 확인해 보도록 하겠습니다.
import matplotlib.pyplot as plt
circle=plt.Circle((0,0),1,fc='w',ec='b') # plt의 Cricle 사용 중심, 반지름, 면적 색, 테두리색
a=plt.axes(xlim=(-1,1),ylim=(-1,1)) # x축 범위 , y축 범위를 a 변수에 할당
a.add_patch(circle) # 만들어진 a 변수(범위)에 circle patch
a.set_aspect('equal') # x ,y 비율은 같게
plt.grid(True, axis='both',color='black', alpha=1, linestyle='-') # 격자 표시
plt.show()
이렇게 중심이 0,0 이고 반지름이 1인 원을 그려 보았습니다.
우리가 사용할 부분은 2사분면 입니다.
# 직사각형의 꼭지점 좌표
1. 0,0
2. 1,0
3. 0,1
4. 1.1
그 중 원의 테두리에 걸치는 점은 2번과 3번입니다.
x^2 + y^2 = 1 , 원의 방정식에 맞는 모습이죠?
### 원주율 (3.14...) 도출하기
그럼 이제 3.14를 구하기 위해서는 어떻게 해야 할까요 ?
x 좌표 y좌표 값을 각각 제곱해 더합니다 ( x^2 + y^2 )
그 값이 1이면 원의 테두리 입니다 ( x^2 + y^2 = 1 )
그럼 그보다 같거나 작으면 ? ( x^2 + y^2 <= 1 )
원의 안쪽 입니다.
이때의 x , y 좌표의 개수를 확인해 보겠습니다
### Python 원주율 구하기
1. 100개의 난수
import numpy as np
import matplotlib.pyplot as plt
N=100
x=np.random.rand(N)
y=np.random.rand(N)
var_x=[i for i,j in zip(x,y) if i**2+j**2<1]
var_y=[j for i,j in zip(x,y) if i**2+j**2<1]
print('%s 개의 점 중 %s개'%(N,len(var_x)))
c=plt.Circle((0,0),1,fc='w',ec='b')
a=plt.axes(xlim=(-1,1),ylim=(-1,1))
a.add_patch(c)
a.set_aspect('equal')
plt.grid(True, axis='both',color='black', alpha=1, linestyle='-')
plt.plot(var_x,var_y)
plt.show()
보시는 바와 같이 2사분면의 안쪽에 찍혔고, 100개 난수 중 79개가 해당됩니다.
난수의 개수를 늘려서 개수를 확인하겠습니다.
2. 난수 100000
10000개 중 7810개로 안쪽을 빼곡하게 채웠습니다.
그럼 이때의 넓이는 어떻게 될까요 ?
1 x 1 x 3.14 / 4 = 0.785 입니다.
안쪽에 찍힌 점은 7810개 입니다.
뭔가 감이 오시나요 ?
7810개에 해당하는 개수는 부채꼴(1/4)입니다.
따라서 전체 개수 중 해당하는 비율에 4를 곱하게 되면 원주율이 나오게 됩니다.
import numpy as np
import matplotlib.pyplot as plt
N=10000
x=np.random.rand(N)
y=np.random.rand(N)
var_x=[i for i,j in zip(x,y) if i**2+j**2<1]
var_y=[j for i,j in zip(x,y) if i**2+j**2<1]
print('%s 개의 점 중 %s개'%(N,len(var_x)))
print('%s / %s * 4 = %s'%(len(var_x), N ,len(var_x) / N * 4))
c=plt.Circle((0,0),1,fc='w',ec='b')
a=plt.axes(xlim=(-1,1),ylim=(-1,1))
a.add_patch(c)
a.set_aspect('equal')
plt.grid(True, axis='both',color='black', alpha=1, linestyle='-')
plt.rcParams["figure.figsize"] = (10,10)
plt.plot(var_x,var_y)
plt.show()
### SQL 원주율 구하기
SQL을 통해서도 원주율을 구해보았습니다.
0과 1사이의 난수를 10만개 생성해 제곱한 결과를 저장합니다.
제곱해서 더한 결과가 1보다 작은 개수를 카운트합니다.
전체 10만개 중 개수의 비율에 곱하기 4를 하여 원주율을 구합니다.
select (count(*)/100000)*4 pi
from(
select (power(dbms_random.value(0,1),2) + power(dbms_random.value(0,1),2)) as "x^2+y^2"
from dual
connect by level <= 100000
)
where "x^2+y^2"<=1;
오늘은 몬테카를로 방법을 이용해서 원주율을 구해 보았습니다.
또 다시 프로그래밍에 있어 수학의 필요성을 느끼게 됩니다.
원주율을 구하고 시각화 하는 과정을 진행하며
파이썬으로 원 그리기, 난수 생성하기, 그래프 겹치기, 그리드 설정하기 등
추가적인 공부가 더 되어서 좋은 실습이었습니다.
많은 도움이 되었길 바라면서 마치겠습니다.
읽어주셔서 감사합니다!
'알고리즘' 카테고리의 다른 글
[Python algo] 탐욕 알고리즘 | Greedy algorithm (7) | 2021.01.19 |
---|---|
[Python&SQL] 치환문자를 통해 피타고라스 정리 구현 (1) | 2021.01.18 |
[Python&SQL] 각 자리수 합 더하기 (2) | 2021.01.15 |
[Python&SQL] 적어도 불량품 1개일 확률 ? (7) | 2021.01.14 |
[Python] 없는 수가 뭘까 ? 빠진수 찾기 (6) | 2021.01.07 |
[Python] 주사위 던지기 (2) | 2021.01.05 |
[Python&SQL] 동전의 앞면이 나올 확률은 ? Random (0) | 2021.01.04 |
[Python&SQL] 재귀 함수 팩토리얼 구구단 (0) | 2021.01.03 |