삼각함수를 구현해보자.

Posted by 적분 ∫2tdt=t²+c
2008.12.07 01:39 프로그래밍/테크닉
여태까지 제곱근함수와 지수함수, 로그함수를 대충 구현해보았다. 이를 이용하면 어지간한 계산들을 다 할 수 있으나, 한 가지 막히는 부분이 있으니 바로 삼각함수이다. 삼각함수는 약방의 감초라할만큼 안 들어가는 곳 없이 두루두루 들어간다.
삼각함수는 비용이 비싼 측에 낀다. (계산량을 줄일만한 획기적 방법이 별로 없는듯하다.) 그래서 삼각함수 연산을 자주 하는 프로그램에서는 대게 테이블을 만들어놓고 참조하는 방법을 쓴다. 이 방법이 대체로 빠른 방법이어서 추천하는 바이다. (가장 좋은 방법은 FPU의 빵빵한 지원이라고나 할까) 아래에 설명하는 계산법은 그냥 이렇게도 계산할수 있다는 거지, 이 식을 활용해서 계산하면 좋다는 의미는 아니다.

공학용으로 삼각함수계산을 어떻게 하나 궁금해서 영어위키백과를 찾아봤더니, 부정확하지만 빠른 오일러 방법을 이용하는 경우도 있고, 정밀한 근사를 위해 체비쇼프 근사나 Padé 근사를 이용하는 경우도 있었지만, 너무 어려운걸 설명하면 머리아프므로(사실 필자가 머리가 아프다.) 그냥 쉬운 걸로만 선택해서 설명하겠다.

먼저 삼각함수의 성질을 이용하여 좀 같은 것들을 추려내보자.
http://www.sitmo.com/gg/latex/latex2png.2.php?z=100&eq=%5Ctan%20x%3D%5Cfrac%7B%5Csin%20x%7D%20%7B%5Ccos%20x%7D
자 먼저 tan x는 sin x와 cos x를 이용해서 구할수 있으므로 sin x, cos x를 이용하여 구현가능하다.
http://www.sitmo.com/gg/latex/latex2png.2.php?z=100&eq=%5Csin%20x%3D%5Ccos(x-%5Cfrac%7B%5Cpi%7D%7B2%7D)
sin x는 cos x를 이용하여 구할 수 있으므로, 최종적으로 cos x만 구하면 모든 삼각함수 계산이 가능하다.
(sin x를 이용해서 cos x를 구해도 되지만, cos x를 이용해 sin x를 구하는 이유는 나중에 알게 될 것이다.)
http://www.sitmo.com/gg/latex/latex2png.2.php?z=100&eq=%5Ccos(x%2B2%5Cpi)%3D%5Ccos%20x
삼각함수의 주기성 때문에 http://www.sitmo.com/gg/latex/latex2png.2.php?z=100&eq=-%5Cpi%3Cx%5Cle%5Cpi 의 범위내의 cos x만 구하면 된다.
http://www.sitmo.com/gg/latex/latex2png.2.php?z=100&eq=%5Ccos(x%2B%5Cpi)%3D-%5Ccos%20x
또 삼각함수의 특징 때문에 부호만 뒤집음으로써 http://www.sitmo.com/gg/latex/latex2png.2.php?z=100&eq=-%5Cpi%3Cx%5Cle%5Cpi의 값을  http://www.sitmo.com/gg/latex/latex2png.2.php?z=100&eq=-%5Cfrac%7B%5Cpi%7D%7B2%7D%3Cx%5Cle%5Cfrac%7B%5Cpi%7D%7B2%7D값을 이용해 구할수 있다. 이제 우리는
http://www.sitmo.com/gg/latex/latex2png.2.php?z=100&eq=-%5Cfrac%7B%5Cpi%7D%7B2%7D%3Cx%5Cle%5Cfrac%7B%5Cpi%7D%7B2%7D 범위의 cos x값을 구하는 것만 구현하면 된다.


오일러의 방법(Euler's Method)을 이용하기
오일러의 방법을 가장 간단하게 설명하자면

http://www.sitmo.com/gg/latex/latex2png.2.php?z=100&eq=f(x%2Bh)%3Df(x)%2Bh%20%5Ccdot%20f%27(x)
h가 충분히 작을때 좌변과 우변이 거의 같아진다. 이렇게 함수의 초기값과 도함수를 이용해서 다음 값을 추정해내는 방법이다. 물론 h가 클수록 오차가 커진다.
이 방법을 삼각함수에 적용해보자.
http://www.sitmo.com/gg/latex/latex2png.2.php?z=100&eq=%5Ccos(x%2Bh)%3D%5Ccos%20x-h%5Csin%20x
http://www.sitmo.com/gg/latex/latex2png.2.php?z=100&eq=%5Csin(x%2Bh)%3D%5Csin%20x%2Bh%5Ccos%20x (물론 x는 라디안이다.)
그리고http://www.sitmo.com/gg/latex/latex2png.2.php?z=100&eq=%5Ccos0%3D1, http://www.sitmo.com/gg/latex/latex2png.2.php?z=100&eq=%5Csin0%3D0 이다.
위의 두 식을 번갈아 가면서 계속 계산하면 대략 원하는 값이 나올것이다. (원래 정밀도가 낮은데에 부동소수점 데이터형식의 한계 때문에 연산을 반복할수록 정밀도가 떨어진다.)

이 방식을 약간 변형해서 쓰는 경우도 있지만, 별반 다를거 없으므로 생략하겠다.

테일러 전개를 이용하기
역시 테일러 전개가 여기저기 쓸모가 많다. 삼각함수 계산할때도 테일러 전개를 이용할 수 있다.
http://www.sitmo.com/gg/latex/latex2png.2.php?z=100&eq=%5Ccos%20x%3D1-%5Cfrac%7B1%7D%7B2%7Dx%5E2%2B%5Cfrac%7B1%7D%7B24%7Dx%5E4-%5Cfrac%7B1%7D%7B720%7Dx%5E6%2B%5Cldots x는 물론 라디안이고 모든 실수에 대해 성립한다.
모든 실수 x에 대해 위 전개식이 성립한다고 해도 x가 클때는 수렴속도가 느리기 때문에 x값을 최대한 작게 해볼 필요가 있다. 그럼 이쯤에서 체비쇼프 다항식을 소개하겠다.
체비쇼프 다항식은 다음 식을 만족하는 Tn(x)를 말한다. (n은 자연수)
http://www.sitmo.com/gg/latex/latex2png.2.php?z=100&eq=%5Ccos%20n%5Ctheta%3DT_n%20(%5Ccos%5Ctheta)
체비쇼프 다항식을 이용하면 http://www.sitmo.com/gg/latex/latex2png.2.php?z=100&eq=%5Ccos%20n%5Ctheta 값을 http://www.sitmo.com/gg/latex/latex2png.2.php?z=100&eq=%5Ccos%20%5Ctheta을 이용하여 구할수 있다.
아까 sin x을 쓰지 않은 이유는 이 때문이다. cos x는 체비쇼프 다항식을 이용하여 x를 더 작은 값으로 바꾸어놓을수 있기때문에 수렴속도를 높일수 있다.
n이 2일때의 체비쇼프 다항식을 소개한다.
http://www.sitmo.com/gg/latex/latex2png.2.php?z=100&eq=T_2(x)%3D2x%5E2-1
따라서
http://www.sitmo.com/gg/latex/latex2png.2.php?z=100&eq=%5Ccos%5Ctheta%3DT_2(%5Ccos%5Cfrac%7B%5Ctheta%7D%7B2%7D)%3D2(%5Ccos%5Cfrac%7B%5Ctheta%7D%7B2%7D)%5E2-1가 된다.
따라서 우리는 http://www.sitmo.com/gg/latex/latex2png.2.php?z=100&eq=%5Ctheta가 충분히 작아질때까지 재귀를 써서 http://www.sitmo.com/gg/latex/latex2png.2.php?z=100&eq=%5Ctheta를 0에 가깝게 만들고 테일러 전개식에 대입시키면 되는것이다. 그러나 여기서 주의해야할것은 부동소수점 데이터형식의 특성상 연산을 반복할수록 정밀도가 떨어지므로 재귀를 적절히 써야한다는 것이다.

이 댓글을 비밀 댓글로