본문 바로가기

Library/Numerical Analysis

Arctan Function Implementation

arctan의 구현은, 생각보다 간단한 문제가 아니다. 무엇보다, 지금까지 사용해왔던 최적화 전략 중 하나가 통하지 않기 때문이다. 즉, arctan의 테일러 급수 전개에 의한 근사식을 구해보면 다음과 같은데,

arctan(x) = x - (x^3 / 3) + (x^5 / 5) - (x^7 / 7) + (x^9 / 9) - ....

각 항의 분모를 살펴보면, 이것은 사인(sine) 함수나 코사인(cosine) 함수처럼 팩토리얼 형태가 아니며, 따라서 적절한 값을 구하고자 했을 때 빠르게 수렴하지 않는다. 각 항 하나하나의 값이 무시 못할 값이기 때문에, 아무리 적은 값이라도 적절한 오차 이내의 값으로 계산하기 위해서는 매우 많은 항이 필요하다. 각 항을 계산하는데 빠르게 증가하는 지수값이 있다는 것을 감안하면, 이것은 매우 좋지 않은 소식이다.

따라서, 보통 이런 경우 연분수(Continued Fraction) 형태로 근사식을 다시 쓰게 되는데, 멱급수(Power Seriese)보다 훨씬 빠르게 수렴한다.



그러나, 이 방법도 무한대로 계속 계산할 수 없으며, 오차와 계산 항수 사이의 트레이드 오프 사항이 존재한다. 즉, 최종적으로 .... 부분이 0에 가깝다고 가정하고, 여기서부터 거꾸로 올라가서 계산할 수 있는 형태로 만들어야 하는데, 항이 많을수록 곱셈, 나눗셈이 많아지기 때문에 성능에 직접적인 영향을 주게 된다.

결국, 이전에 삼각 함수를 구현했을 때와 마찬가지로, 입력값의 범위를 제한하거나 다른 삼각 함수의 특징을 활용해서 최대한 오차를 적게, 그리고 빠르게 계산할 수 있게 해야 한다.

그러나, arctan는 tan의 역함수이며, 결국 입력값은 -1 < x < 1이다. 여기서 무엇을 더 줄일 수 있단 말인가? 사실, 이것만으로 생각한다면 여기서 더 할 수 있는 일은 없다. 이미 연분수의 형태로 항을 계산하는 것도 현실적인 이유로 몇 개의 항까지로 제한되며, 해야 할 일은 그냥 여기에 값을 넣고 계산하는 것 뿐이다. 문제는, -1 < x < 1 사이에서 오차가 균일하지 않다는데 있다. 즉, 1에 가까워질수록 오차는 커지고, 0에 가까울수록 오차는 작아진다. 이것은 고려해야 할 문제이다.




그렇다면, 입력값을 좀 더 줄이면서, 오차를 균일하게 할 수 있는 방법은 없을까? 이것은, 다음과 같은 방법을 사용함으로써 해결할 수 있다.

tan(A + B) = (tan(A) + tan(B)) / (1 - tan(A) * tan(B))

즉, 구하고자 하는 x = tan(A + B)일 때, tan(A) = z, tan(B) = k라고 하자.

A = arctan(z), B = arctan(k), ∴ x = (z + k) / (1 - zk)

z에 대해서 정리하면,

z = (x - k) / (1 + kx)

즉, x를 입력값이라 했을 때, arctan(x) = arctan(k) + arctan(z)로 정리할 수 있으며, k는 미리 계산할 수 있다(어떤 입력값에 대해서, 예를 들어 값이 tan(x)에 의해서 몇 도인지 파악할 수 있으며, 구하고자 하는 각은 결국 이 각에서 얼마를 더하고 빼서 표현할 수 있다는 말이다). 결국 구해야 하는 것은 z이며, z는 x 보다 작은 값이다. 결국, z는 입력으로 들어온 x, 미리 계산된 k에 의해서 구할 수 있으며, arctan(x) = arctan(k) + arctan(z)에 의해서 구하고자 하는 arctan(x) 값을 구할 수 있다. 또, 이 방법을 이용한다면, 오차의 균일성 문제도 해결할 있게 된다. 왜냐하면, 실질적으로 계산이 이루어지는 부분은, 위의 그래프의 1에 가까운 영역에서 이루어지는 것이 아니라 k 값보다 작은 영역에서 일어나기 때문이다.

즉, 이렇게 되면 오차의 범위는 다음과 같아진다.




특히, 각을 더 세분화한다면(tan(A + x)에서 A를 더 세분화하여 A는 미리 계산해두고, x는 매우 작은 값으로 주어진 입력값을 정리할 수 있다면), 오차는 더 줄어들 것이고, 작은 값에 대해서 계산하는 것이므로 위의 연분수에서 전개해야 하는 밑의 분수 부분도 조금 더 줄일 수 있다.


Reference
Jack W. Crenshaw, Math Toolkit for Real-Time Programming, CMP Books