로그(log, ln) 함수의 구현은 본질적으로 arctan와 비슷한 문제를 가지고 있다. 먼저, 로그 함수의 x 값을 적절히 바꾸어서 테일러 급수 형태로 전개해보면, 다음과 같은 형태를 얻게 된다.
ln(x) = 2 (z + z^3 / 3 + z^5 / 5 + z^7 / 7 + z^9 / 9 + ....)
z = (x - 1) / (x + 1)
arctan와 마찬가지로, 분모가 대단히 느리게 커지고 있으며, 이것은 매우 천천히 구하고자 하는 값에 수렴하는 것을 의미한다. 로그 함수를 구현해야 한다면, 이것은 매우 치명적인 일이다. 하지만, 앞에서 이미 연분수(continued fraction)를 사용하여 이 문제를 효과적으로 다루었던 것처럼, 로그 역시 연분수를 사용해서 나타낼 수 있다. 그렇다면, 남은 문제는 arctan와 마찬가지로, 적절한 항만 계산하더라도 만족할만한 오차 이내의 값을 얻을 수 있도록 입력값을 통제하는 것이다.
로그 함수에서 입력값의 범위를 제한하는 방법이 있을까? 물론 있다. 그것도, 로그의 성질을 이용하면 아주 우아하게 처리할 수 있다. 예를 들어, ln24를 계산한다고 해보자. 그냥 24를 위의 식에 넣고 계산해야 할까? 24의 경우 수가 작은 편에 속하기 때문에 그럭저럭 만족할만한 오차 이내로 계산 결과를 얻을 수 있을지 모른다. 그러나, 매우 큰 값이 입력으로 들어온다면, 위의 제한된 항의 갯수만으로 원하는 오차 이내의 값을 얻을 수 있다는 것을 보장할 수 없게 된다. 그러나, 로그에서 나눗셈은 빼기로, 곱셈은 더하기로 처리할 수 있다는 것을 생각해보자. 즉, 24라는 값을 적당히 나누어서 원하는 입력범위로 줄이고, 그냥 나눈 값을 로그값으로 더해주면 된다.
예를 들어, 입력값으로 들어오는 값을, 항상 1보다 작게 하고 싶다고 하자. 그렇다면, ln(24 / 100)의 경우, ln(0.24) + 2ln10으로 다시 쓸 수 있으며, 2ln10과 같은 경우 미리 계산이 가능하다. 따라서, 이 트릭(Trick)은 로그 함수의 구현에 있어서, 가능하면 상수 시간에 계산해야 하는 것과, 적정 범위의 오차여야 한다는 조건을 만족할 수 있는 좋은 출발점이 된다.
특히, 이 로그 함수의 입력값으로 부동소수점이 들어온다면, 이 부동소수점은 이미 표준화(normalization)되어 있는 상태이기 때문에, 가수(mantissa)의 범위가 0.5에서 1 안쪽이다. 가수에 대해서만 실제 로그 함수를 통해 그 값을 계산하고, 지수 부분은 그냥 지수 부분을 곱해주면 간편하게 구현할 수 있다.
Reference
Jack W. Crenshaw, Math Toolkit for Real-Time Programming, CMP Books
ln(x) = 2 (z + z^3 / 3 + z^5 / 5 + z^7 / 7 + z^9 / 9 + ....)
z = (x - 1) / (x + 1)
arctan와 마찬가지로, 분모가 대단히 느리게 커지고 있으며, 이것은 매우 천천히 구하고자 하는 값에 수렴하는 것을 의미한다. 로그 함수를 구현해야 한다면, 이것은 매우 치명적인 일이다. 하지만, 앞에서 이미 연분수(continued fraction)를 사용하여 이 문제를 효과적으로 다루었던 것처럼, 로그 역시 연분수를 사용해서 나타낼 수 있다. 그렇다면, 남은 문제는 arctan와 마찬가지로, 적절한 항만 계산하더라도 만족할만한 오차 이내의 값을 얻을 수 있도록 입력값을 통제하는 것이다.
로그 함수에서 입력값의 범위를 제한하는 방법이 있을까? 물론 있다. 그것도, 로그의 성질을 이용하면 아주 우아하게 처리할 수 있다. 예를 들어, ln24를 계산한다고 해보자. 그냥 24를 위의 식에 넣고 계산해야 할까? 24의 경우 수가 작은 편에 속하기 때문에 그럭저럭 만족할만한 오차 이내로 계산 결과를 얻을 수 있을지 모른다. 그러나, 매우 큰 값이 입력으로 들어온다면, 위의 제한된 항의 갯수만으로 원하는 오차 이내의 값을 얻을 수 있다는 것을 보장할 수 없게 된다. 그러나, 로그에서 나눗셈은 빼기로, 곱셈은 더하기로 처리할 수 있다는 것을 생각해보자. 즉, 24라는 값을 적당히 나누어서 원하는 입력범위로 줄이고, 그냥 나눈 값을 로그값으로 더해주면 된다.
예를 들어, 입력값으로 들어오는 값을, 항상 1보다 작게 하고 싶다고 하자. 그렇다면, ln(24 / 100)의 경우, ln(0.24) + 2ln10으로 다시 쓸 수 있으며, 2ln10과 같은 경우 미리 계산이 가능하다. 따라서, 이 트릭(Trick)은 로그 함수의 구현에 있어서, 가능하면 상수 시간에 계산해야 하는 것과, 적정 범위의 오차여야 한다는 조건을 만족할 수 있는 좋은 출발점이 된다.
특히, 이 로그 함수의 입력값으로 부동소수점이 들어온다면, 이 부동소수점은 이미 표준화(normalization)되어 있는 상태이기 때문에, 가수(mantissa)의 범위가 0.5에서 1 안쪽이다. 가수에 대해서만 실제 로그 함수를 통해 그 값을 계산하고, 지수 부분은 그냥 지수 부분을 곱해주면 간편하게 구현할 수 있다.
Reference
Jack W. Crenshaw, Math Toolkit for Real-Time Programming, CMP Books