상세 컨텐츠

본문 제목

BigFloat로 Pi를 구해보자-9. 제곱근 구현하기

프로그래밍/Multi precision

by ∫2tdt=t²+c 2012. 11. 8. 21:28

본문



최적화하는건 머리가 너무 아프므로, 이번엔 산뜻하게 제곱근 계산하는 함수나 만들어보렵니다. 사칙연산을 다 구현하면 BigFloat 자료형을 다 만들었다고 착각하면 아니되옵니다.ㅋ 이제 시작이지요. 그중에서 제일 기본적인게 제곱근입니다. 계산도 어렵지 않아요.


나눗셈 구현할때 사용했던 Newton-Raphson 방법을 기억하시려는지요? 이를 제곱근 계산에도 이용할 수 있습니다.(바빌론에서 제일 처음 사용되었다고 해서 바빌로니아 방법이라고 부르기도 합니다.)


이 공식 기억나지요? f(x)=0의 근을 근사해주는 Newton-Raphson의 공식이었죠. 우리는 제곱근을 구하고 싶으므로 f(x)를 다음과 같이 놓겠습니다.


(f(x)의 근은 sqrt(S) (혹은 -sqrt(S) )가 되겠지요?)

그럼 아래와 같이 정리가 될겁니다.

나눗셈과 덧셈, 시프트 연산만 가지고 충분히 제곱근을 계산할 수 있겠네요!


Newton-Raphson 공식에서 빠른 수렴을 위해서는 초기값이 좋아야겠지요. 초기값 X0은 어떻게 추정하면 좋을까요?


임의의 양수 S는 다음과 같이 나타낼수 있습니다. 당연히 n은 정수입니다.


정수 n은 비트수를 세는것 만으로 구할수 있습니다. n이 짝수일 경우 m비트 정수는 sqrt(S)와 최대 1.414배밖에 차이나지 않을 겁니다. n이 홀수일 경우 m비트 정수는 sqrt(S)와 최대 2배밖에 차이나지 않습니다.

즉 S의 비트수를 세어 n을 구한뒤, 를 구하면 우리가 구하고자 하는 sqrt(S)와 최악의 경우에도 2배밖에 차이가 나지 않는다는 것이지요. 이정도면 빠르고 괜찮은 근사법입니다.


이제 이 사실들을 바탕으로 코드를 작성해봅시다.




중간에 웃지 못할 코드가 있는데요, stop = 123456789; 여기입니다.

Newton-Raphson 방법은 한 번 반복할때마다 정밀도가 대략 2배씩 늘어납니다. 그런데 실제 구현에서는 여러가지 한계에 의해서 실제로 그렇지 않은 경우도 있어서, 우리가 원하는 정밀도까지 계산해내기 위해 몇번 반복해야할지를 가늠하는게 쉽지 않습니다.(ㅠㅠ)

그래서 frac배열의 제일 마지막 바로 전 자리를 지켜보면서, 이 값이 바뀌지 않는 지점에 다다르면 계산을 중단하는 방법을 사용했어요. (제일 마지막 자리는 오차때문에 매번 반복 때마다 계속 값이 바뀌게 됩니다.)


시간복잡도는 Newton-Raphson 방법으로 나눗셈을 구현했을때와 마찬가지 방법으로 유도하면 O(n2)이 나옵니다.

관련글 더보기

댓글 영역