Pi
를 N
자리까지 계산하는 프로그램을 만들어보았다. 여기에서 N
은-물론 환경에 따라 다르지만 -unsigned long int
까지의 크기를 가질 수 있다.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <gmp.h>
void get_pi(unsigned long int digit, mpf_t result)
{
mp_bitcnt_t backup;
mpf_t n1, n2, n3, n4;
mpf_t part, total;
unsigned long int iteration;
if (digit < 3)
return ;
iteration = (digit / log(16) + 10) * 1.0001;
backup = mpf_get_default_prec();
mpf_set_default_prec(digit * log2(10) + 10);
mpf_inits(n1, n2, n3, n4, NULL);
mpf_inits(part, total, result, NULL);
mpf_set_default_prec(backup);
for (unsigned long long int k = 0; k < iteration; k++)
{
mpf_set_d(n1, 4.0 / ((8 * k) + 1));
mpf_set_d(n2, 2.0 / ((8 * k) + 4));
mpf_set_d(n3, 1.0 / ((8 * k) + 5));
mpf_set_d(n4, 1.0 / ((8 * k) + 6));
mpf_set(part, n1);
mpf_sub(part, part, n2);
mpf_sub(part, part, n3);
mpf_sub(part, part, n4);
mpf_div_2exp(total, part, 4 * k);
mpf_add(result, result, total);
}
mpf_clears(n1, n2, n3, n4, NULL);
mpf_clears(part, total, NULL);
}
char *get_pi_string(int digit)
{
mp_exp_t bitcnt;
mpf_t result;
char *output = malloc(digit + 2);
get_pi(digit, result);
mpf_get_str(&output[1], &bitcnt, 10, digit, result);
output[0] = '3'; output[1] = '.';
mpf_clear(result);
return output;
}
int main(int argc, char *argv[])
{
int digit;
char *output;
if (argc != 2) {
printf("usage: %s <digit>\n", argv[0]);
return 1;
}
digit = strtol(argv[1], NULL, 10);
if (digit < 3) {
printf("<digit> at least greater than 3\n");
return 1;
}
printf("%s\n", (output = get_pi_string(digit)));
free(output);
return 0;
}
출처: https://github.com/Cruzer-S/Get-Pi/blob/main/source/main.c
여기에서 사용한 GMP
(GNU Multiple-Precision Library) 라이브러리는는 임의의 크기를 가진 수치를 계산하기 위한 자유 소프트웨어 라이브러리이다. - Wikipedia GMP (라이브러리)
처음에는 이런 수학 라이브러리를 직접 만들어볼까 했으나, 워낙 잘 만들어져 있어서 의지가 꺾였다. 바퀴의 재발명이 될 것 같아 그냥 가져다 썼다. 정말 잘 만든 라이브러리이다.
Fedora 38
을 기준으로 간단하게 설명하면 다음과 같다:
sudo dnf install gmp-devel
gcc main.c -lgmp
그 외 상세한 내용과 API
는 메뉴얼 을 참조. 필자 역시 메뉴얼을 하나하나 읽으며 가져다 사용했는데, 큰 어려움 없이 쉽게 잘 만들었다.
Pi
계산 방법 필자는 Pi
를 계산하기 위해 BBP(Bailey–Borwein–Plouffe)
formula 를 사용했는데, 사실 정확한 증명법은 잘 모른다. 아직 더 찾아봐야 하는 내용이 많지만, 일단 참고한 자료를 모아서 아래에 정리했다.
Pi
계산법 소개 영상이 영상이 가장 쉽고 직관적이고 단순하다. 가장 먼저 계산을 시도하게 된 계기가 이 영상이다.
BBP
알고리즘에 대한 소개와 유도https://blog.naver.com/greengb
이 블로그에서 Pi
를 엄청나게 깊이있게 다룬다. BBP
알고리즘을 유도하는 과정도 나오는데 솔직히 다 읽어보진 않았다. 일단 유도 과정 자체는 미적분학 지식 정도만 있으면 충분하다. 열정과 끈기가 대단하다. 보면서도 놀랐다.
https://github.com/hellpig/calculate-pi/blob/main/piGMP.c
N 번째 자릿수까지 계산하는데 필요한 반복 횟수를 찾는 아이디어는 여기에서 얻게 되었다. BBP
의 점근 표기법 (Big-O
) 을 통해 N 자리를 계산하기 위해 필요한 반복 횟수를 역산한다.