이전 블로그에서 적었듯, ln()을 구현한 김에 sin()도 함께 구현해봤고, 원주율 계산도 간단하게 구현해봤다.
1. sin(x)의 구현
물론, 이번에도 테일러 급수다.
sin(x)는 아래와 같이 전개된다.
이번에도 역시 구현 자체는 그리 어렵지 않지만 적절한 횟수를 정하는 것이 필요하다.
const static double PI = 3.141592653589796323846;
void SIN_v1(double x, double limit, double& result, int& count) {
result = 0;
count = 0;
while (x > 2 * PI) { x -= 2 * PI; }
while (x < 0) { x += 2 * PI; }
double xxxx = x * x * x * x;
double t1 = x;
double t2 = -x * x * x / 6;
result = t1 + t2;
count = 0;
int i4 = 0;
while (true) {
++count;
i4 += 4;
t1 = t1 * xxxx / ((i4 - 2) * (i4 - 1) * i4 * (i4 + 1));
t2 = t2 * xxxx / (i4 * (i4 + 1) * (i4 + 2) * (i4 + 3));
if (isinf(t1) || isinf(t2)) {
break;
}
result += (t1 + t2);
if (fabs(t1) < limit) {
break;
}
}
}
ln()과 유사하게, 약 10회 정도 루프를 돌리니 상당히 정확한 값이 나온다.
이 점을 고려해서 작성한 결과는 아래와 같다.
const static double PI = 3.141592653589796323846;
double SIN_v2(double x) {
while (x > 2 * PI) { x -= 2 * PI; }
while (x < 0) { x += 2 * PI; }
double xxxx = x * x * x * x;
double t1 = x;
double t2 = -x * x * x / 6;
double result = t1 + t2;
int i4 = 0;
for (int i = 0; i < 20; ++i) {
i4 += 4;
t1 = t1 * xxxx / ((i4 - 2) * (i4 - 1) * i4 * (i4 + 1));
t2 = t2 * xxxx / (i4 * (i4 + 1) * (i4 + 2) * (i4 + 3));
if (isinf(t1) || isinf(t2)) {
break;
}
result += (t1 + t2);
}
return result;
}
2. pi()의 구현
뉴튼과 같은 시대에 미적분학을 창시한 라이프니츠[각주:1]는 원주율을 아래와 같이 전개하였다.
약 두 세대 쯤 뒤의 수학자인 그 위대하신 오일러[각주:2]는 아래와 같이 전개하였다.
1995년에는 데이빗 베일리 - 피터 보어와인 - 시몽 플루프가 π에 관련된 새로운 무한급수를 발견[각주:3]했다.
데이빗 베일리는 수학자이기도 했지만, 또한 나사에서 14년을 컴퓨터 과학자(Computer Scientist)로서도 근무했었다.
이런 그의 특기가 반영된 식답게 수렴속도도 빠르다.
루프의 적절한 횟수를 정하기 위해 일단 작성한 코드는 아래와 같다.
void PI_v1(double limit, double& result, int& count) {
count = 0;
result = 4 - 0.5 - 0.2 - (1 / 6.0);
int sixteen = 1;
double temp;
int i8 = 0;
while (true) {
++count;
i8 += 8;
sixteen *= 16;
temp = ((4.0 / (i8 + 1)) - (2.0 / (i8 + 4)) - (1.0 / (i8 + 5)) - (1.0 / (i8 + 6))) / sixteen;
if (isinf(temp)) {
--count;
break;
}
result += temp;
if (temp < limit) {
break;
}
}
}
이렇게 돌려보면 7회까지만 돌릴 수 있다.
이 점을 고려해서 작성한 코드는 아래와 같다.
double PI_v2() {
double result = 4 - 0.5 - 0.2 - (1 / 6.0);
int sixteen = 1;
double temp;
int i8 = 0;
for (int i = 0; i < 7; ++i) {
i8 += 8;
sixteen *= 16;
temp = ((4.0 / (i8 + 1)) - (2.0 / (i8 + 4)) - (1.0 / (i8 + 5)) - (1.0 / (i8 + 6))) / sixteen;
result += temp;
}
return result;
}
이렇게 계산된 결과는 아래와 같다.
대각선에서 소수의 비율이 10% 이하가 되는 값 찾기 (0) | 2020.03.26 |
---|---|
ln(), pow(), exp() 함수 구현 / 마무리 (0) | 2020.03.22 |
테일러 급수로 구현한 ln() 함수 (0) | 2020.03.22 |
C/C++/C# 에서 간단하게 inf/NaN 확인하는 방법 (0) | 2020.02.07 |
세제곱수의 순열(permutation) (0) | 2019.12.03 |