본문 바로가기

Studying/Computer Programs

C/C++ 원주율 계산 프로그램

여기서는 수학 상수 중 하나인 원주율을 계산하는 간단한 프로그램을 소개해볼까 하는데요. 물론 원주율의 값은 이미 잘 알려져 있고 C언어 수학 함수 라이브러리에도 있지만, 단순히 값만 외우는거랑 직접 계산해보는 것은 다르다고 생각했기 때문에 이 포스팅을 하게 되었습니다.

 

반응형

 

원주율을 계산하기 위한 방법으로는 무한 급수나 몬테-카를로 (Monte-Carlo) 방법등 여러가지가 있습니다만, 여기서는 정적분을 통해서 원주율을 구해 보겠습니다.

 

equation to evaluate the mathematical constant pi

 

이는 역삼각함수 중 하나인 아크탄젠트 함수가 특정한 값을 인자로 받는 경우에, 원주율에 비례하는 값을 돌려준다는 사실을 이용한 방법인데요. 원주율과 삼각함수에 대한 자세한 내용이 궁금하시다면, 다음 포스팅을 참고하면 도움이 되리라 생각합니다.

 

 

수학 상식 : 원주율과 삼각함수

여기서는 기하학에 관련된 중요한 상수인 원주율과, 과학 및 공학 분야에서 가장 흔하게 접할 수 있는 주기함수인 삼각함수에 대해 얘기해볼까 합니다. 원주율과 호도법 먼저 유클리드 공간에

swstar.tistory.com

 

정적분의 값을 계산하기 위해서 사다리꼴 공식 (trapezoidal rule)을 적용하게 될텐데요. 적분구간을 여러개로 나누고, 함수의 형태에 따라 결정되는 여러개의 사다리꼴의 면적에 입각해서 정적분의 근사값을 구하는 방법입니다. 다음 포스팅에 더 자세한 내용이 소개되어 있습니다.

 

 

사다리꼴 공식을 이용한 C/C++ 수치 적분

여기서는 사다리꼴 공식 (trapezoidal rule)을 적용하여 주어진 함수의 정적분을 수치적으로 구하는 법에 대해서 알아봅시다. 사다리꼴 공식으로 얻을 수 있는 것은 적분의 근사값입니다만, 원하는

swstar.tistory.com

 

C언어 소스 코드입니다. 참고로 C++ 에서도 같은 코드를 적용할 수 있습니다.

 

#include<stdio.h>
#include<stdlib.h>
#include<math.h>

double eps_precision = 1e-8;

double func_integrand(double u);

int main(int argc, char *argv[]) {
    double pi_now = 0.;
    double pi_prev;
    int converging = 0;

    unsigned long int nbin_u = 1;
    double u_min = 0.;
    double u_max = 1.;
    double delta_u =
        fabs(u_max - u_min) / (double)nbin_u;

    int istep = 1;
    while (converging == 0) {
        pi_prev = pi_now;

        unsigned int iu;
        if (istep == 1) {
            pi_now = 0.;
            for (iu = 0; iu < nbin_u; iu++) {
                double u0 = u_min + delta_u * (double)iu;
                double u1 = u0 + delta_u;
                pi_now +=
                    0.5 * delta_u * (func_integrand(u0) +
                                     func_integrand(u1));
            }
        } else {
            pi_now = 0.5 * pi_prev;
            for (iu = 0; iu <= nbin_u; iu++) {
                if (iu % 2 == 0) {
                    continue;
                }

                double u_now = u_min + delta_u * (double)iu;
                pi_now +=
                    delta_u * func_integrand(u_now);
            }
        }

        fprintf(stdout,
            "    step %d : pi = %.8f\n", istep, pi_now);
            
        if (fabs(pi_now - pi_prev) <
            0.5 * eps_precision *
            fabs(pi_now + pi_prev)) {
            converging = 1;
        }

        istep += 1;
        nbin_u = 2 * nbin_u;
        delta_u = 0.5 * delta_u;
    }

    fprintf(stdout, "\n");
    fprintf(stdout, "pi from numerical integration\n");
    fprintf(stdout, "  > pi = %.8f\n", pi_now);
    fprintf(stdout, "pi from C math library\n");
    fprintf(stdout, "  > pi = %.8f\n", M_PI);

    return 0;
}

double func_integrand(double u) {
    return 2. / (fabs(u * u) + fabs((1. - u) * (1. - u)));
}

 

실수형 변수 eps_precision을 통해서 원하는 정밀도를 상정하고, 원주율의 값이 그만큼 정확해질때까지 수치적분의 격자 갯수를 증가시키는 방식의 프로그램입니다. 즉 분할된 구간의 갯수를 늘려가면서 리만 합을 계산하고 있죠. 이전 단계와 현재 단계에서의 원주율의 추정치를 저장하기 위한 실수형 변수 pi_prevpi_now가 선언되어 있습니다.

 

추가로 수렴을 체크하기 위한 정수형 제어변수 converging이 있는데요. pi_nowpi_prev의 값을 대조한 다음, 그 차이가 현재 추정치보다 매우 작다면 수렴한다고 가정하고 반복문을 정지시키는 방식입니다. 만약 수렴을 하지 않고 더 정밀한 계산이 필요하다면, 분할된 구간의 갯수 nbin_u를 2배로 늘려서 리만 합을 새로 계산하고 pi_now의 값을 업데이트합니다.

 

코드를 컴파일하고 실행해 보면, 다음과 같은 결과를 얻을 수 있습니다.

 

execution of a program to evaluate the mathematical constant pi

 

C언어 수학 함수 라이브러리에 정의된 값과 비교했을때, 소수점 7번째 자리까지 일치한다는 것을 볼 수 있습니다.

 

만일 원주율의 값을 더 정밀하게 구하고 싶다면 eps_precision의 값을 줄이면 됩니다만, 그만큼 실행시간은 늘어나겠죠. 뿐만 아니라 리만 합을 위한 분할 구간의 갯수를 저장하는 nbin_u가 unsigned long 정수형 변수이기 때문에, 한계가 존재합니다. 이러한 난점들을 타개하기 위한 방법 중 하나는 병렬 프로그램을 작성하는 것인데요. 정적분의 구간을 여러 개로 나눈 다음 각 프로세스나 스레드에 할당하면, 시간도 절약되고 정밀도도 더 높일 수 있을 것입니다.

 

병렬 프로그래밍을 위한 방법은 대표적으로 OpenMP와 MPI (Massage Passing Interface)가 있습니다. 이들을 활용하여 C언어 또는 C++ 병렬 프로그램을 작성하는 방법은 다음 포스팅들에 소개되어 있습니다.

 

OpenMP 병렬 프로그래밍

 

OpenMP C/C++ 를 이용한 병렬 프로그래밍

개요 여기서는 여러개의 CPU 코어를 동시에 사용하는 병렬 프로그램을 만들기 위한 방법 중 하나인 OpenMP에 대해 알아봅시다. OpenMP는 여러 개의 명령문들이 동시에 실행되는 프로그램을 작성하기

swstar.tistory.com

 

MPI 병렬 프로그래밍

 

MPI C/C++ 를 이용한 병렬 프로그래밍

개요 프로그램이 여러 개의 CPU 코어에서 돌아갈 수 있게 소스 코드를 작성하면, 생산성을 높이는 데 도움이 됩니다. 필요한 연산을 여러 개의 코어들이 나누어서 수행하기 때문에, 프로그램 실

swstar.tistory.com

 


 

여기서는 C언어를 통해 프로그램을 작성했지만, C#을 통해서도 원주율을 계산할 수 있습니다. 다음 포스팅에 더 자세한 내용이 소개되어 있습니다.

 

 

C# 전산수학 - 정적분을 통한 원주율 계산

여기서는 C#으로 원주율의 근사값을 계산하는 간단한 프로그램을 만들어 봅시다. 원주율을 계산하는 방법은 여러가지가 있습니다만, 이번 포스팅에서는 정적분을 이용해서 근사값을 구해보도

swstar77x.blogspot.com