[C] Pi 를 N 자리까지 계산하기

문연수·2024년 2월 24일
0

C

목록 보기
2/2
post-thumbnail

PiN 자리까지 계산하는 프로그램을 만들어보았다. 여기에서 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

1. GMP (GNU Multiple-Precision Library) 라이브러리

 여기에서 사용한 GMP (GNU Multiple-Precision Library) 라이브러리는는 임의의 크기를 가진 수치를 계산하기 위한 자유 소프트웨어 라이브러리이다. - Wikipedia GMP (라이브러리)
처음에는 이런 수학 라이브러리를 직접 만들어볼까 했으나, 워낙 잘 만들어져 있어서 의지가 꺾였다. 바퀴의 재발명이 될 것 같아 그냥 가져다 썼다. 정말 잘 만든 라이브러리이다.

- 설치 및 컴파일 방법

Fedora 38 을 기준으로 간단하게 설명하면 다음과 같다:

sudo dnf install gmp-devel
gcc main.c -lgmp

 그 외 상세한 내용과 API메뉴얼 을 참조. 필자 역시 메뉴얼을 하나하나 읽으며 가져다 사용했는데, 큰 어려움 없이 쉽게 잘 만들었다.

2. Pi 계산 방법

 필자는 Pi 를 계산하기 위해 BBP(Bailey–Borwein–Plouffe) formula 를 사용했는데, 사실 정확한 증명법은 잘 모른다. 아직 더 찾아봐야 하는 내용이 많지만, 일단 참고한 자료를 모아서 아래에 정리했다.

- Veritasium 의 Pi 계산법 소개 영상

 이 영상이 가장 쉽고 직관적이고 단순하다. 가장 먼저 계산을 시도하게 된 계기가 이 영상이다.

- BBP 알고리즘에 대한 소개와 유도

https://blog.naver.com/greengb

 이 블로그에서 Pi 를 엄청나게 깊이있게 다룬다. BBP 알고리즘을 유도하는 과정도 나오는데 솔직히 다 읽어보진 않았다. 일단 유도 과정 자체는 미적분학 지식 정도만 있으면 충분하다. 열정과 끈기가 대단하다. 보면서도 놀랐다.

- N 자릿수 계산까지 필요한 반복 횟수

https://github.com/hellpig/calculate-pi/blob/main/piGMP.c

 N 번째 자릿수까지 계산하는데 필요한 반복 횟수를 찾는 아이디어는 여기에서 얻게 되었다. BBP 의 점근 표기법 (Big-O) 을 통해 N 자리를 계산하기 위해 필요한 반복 횟수를 역산한다.

- 그 외 읽어볼만한 내용

profile
2000.11.30

0개의 댓글