Rob Pike가 수학의 심연을 들여다볼 때: Ivy 언어의 초월 함수 구현기


최근 Go 언어의 아버지 중 한 명인 Rob Pike가 자신의 블로그에 꽤 흥미로운 글을 올렸습니다. 2014년부터 취미 프로젝트로 만들어오던 APL 스타일의 인터프리터 언어, Ivy 에 고정밀 초월 함수(Transcendental Functions)를 구현한 이야기입니다.

대부분의 엔지니어에게 sin(), cos(), log()는 라이브러리 import 한 줄이면 끝나는 문제입니다. 하지만 “정확도(Precision)“라는 제약 조건이 float64를 넘어 수천 비트 단위로 올라가면, 이 문제는 완전히 다른 차원의 엔지니어링 챌린지가 됩니다.

오늘은 Rob Pike가 어떻게 수학적 난제들을 해결하며 Ivy에 고정밀 연산을 탑재했는지, 그리고 그 과정에서 우리가 배울 점은 무엇인지 Deep Dive 해보겠습니다.

왜 굳이 지금 초월 함수인가?

Ivy는 본래 APL의 문법을 차용하되, ASCII 문자셋을 사용하고 Exact Arithmetic (무한 정수 및 유리수 연산)을 지향하며 만들어졌습니다. 그런데 Go의 math/big 라이브러리를 만든 Robert Griesemer가 고정밀 Floating Point 지원을 추가하면서 상황이 바뀌었습니다.

단순히 sqrt 정도만 구현하려던 것이, sin, cos, log, 그리고 악명 높은 감마 함수($\Gamma$)까지 구현해야 하는 상황이 된 것이죠. 여기서 핵심은 Arbitrary Precision 입니다. 64비트 부동소수점 연산에 최적화된 기존 알고리즘들은 수천 자릿수의 정밀도를 요구하는 환경에서는 무용지물이거나, 수렴 속도가 너무 느려 사용할 수 없습니다.

1. 테일러 급수와 항등식의 마법

기본적인 sin, cos, exp는 테일러 급수(Taylor Series)로 해결이 가능합니다. 하지만 문제는 수렴 속도 입니다.

Arctangent의 악몽

특히 atan(아크탄젠트)는 $x$가 1에 가까울 때 테일러 급수의 수렴이 끔찍하게 느립니다. Rob Pike는 여기서 옛 교과서를 뒤져 흥미로운 항등식을 찾아냅니다.

$$ \text{atan}(x) = \text{atan}(y) + \text{atan}\left(\frac{x-y}{1+xy}\right) $$

여기서 $y$는 자유 변수입니다. Pike는 $y = \sqrt{2}-1$ (즉, $\tan(\pi/8)$)을 대입하여 계산해야 할 $x$의 범위를 획기적으로 줄였습니다. 이 “Argument Reduction” 기법 덕분에 수백만 번 반복해야 할 연산을 획기적으로 줄일 수 있었죠.

Logarithm과 10,000 자리의 log(2)

로그 함수 구현에서는 log(mantissa * 2^exponent) 형태로 분해하여 계산했는데, 이를 위해서는 매우 정확한 log(2) 값이 필요했습니다. 재미있는 점은, Pike가 외부 데이터를 가져오는 대신 Ivy 언어 자체를 사용하여 10,000 자리의 log(2)를 직접 계산 해버렸다는 것입니다.

자신이 만든 도구로 도구를 개선하는 과정, 이것이야말로 엔지니어링의 로망 아닐까요?

2. 최종 보스: 감마 함수 (Gamma Function)

이 글의 하이라이트는 팩토리얼의 일반화 버전인 감마 함수 $\Gamma(z)$ 구현기입니다. 감마 함수는 테일러 급수 같은 예쁜 해법이 없습니다. 오직 근사(Approximation)만이 존재할 뿐입니다.

Lanczos 근사의 한계

처음에는 1964년에 발표된 Lanczos approximation 을 시도했습니다. float64 수준에서는 훌륭하지만, Ivy가 목표로 하는 고정밀 환경에서는 10~12자리 정밀도에서 한계가 드러났습니다. 고정된 계수(Coefficients)를 사용하기 때문입니다.

Spouge 근사와 행렬 연산

결국 그는 1994년의 Spouge approximation 과 2021년 Causley의 논문을 바탕으로 방향을 틉니다. 이 방식은 항(Term)의 개수를 늘리면 정밀도를 높일 수 있지만, 계수 계산이 훨씬 복잡합니다.

여기서 Ivy(APL 계열)의 진가가 드러납니다. 복잡한 행렬 연산을 단 몇 줄로 표현해냅니다. 아래는 Pike가 구현한 행렬 곱셈 코드의 일부입니다.

(D+.*B+.*C)+.*F

이 암호 같은 코드는 내적(Inner Product)과 행렬 곱셈을 수행합니다. Go로 작성했다면 한 페이지가 넘어갔을 행렬 연산이, Ivy에서는 단 한 줄로 끝납니다. Rob Pike가 왜 APL 스타일에 매료되었는지 알 수 있는 대목입니다.

결과적으로 그는 $N=100$ 항을 사용하여 약 50자리의 정밀도를 얻어냈습니다. float64의 16자리를 아득히 뛰어넘는 수치입니다.

Principal Engineer’s View: 왜 이 글을 읽어야 하는가?

이 블로그 포스트는 단순한 “구현기”가 아닙니다. 저는 여기서 세 가지 중요한 인사이트를 얻었습니다.

  1. Fundamental에 대한 존중: 요즘 우리는 npm install이나 AI 코딩 툴에 의존해 “어떻게” 작동하는지 잊어버리곤 합니다. 하지만 수면 아래의 수학적 원리를 이해하는 것은 최적화와 트러블슈팅의 기본입니다.
  2. 언어(Tool)가 사고를 지배한다: 복잡한 수식을 구현할 때, C나 Go가 아닌 Ivy(APL)를 사용함으로써 문제 해결의 접근 방식이 달라졌습니다. 행렬 연산을 Loop 없이 처리하는 사고방식은 데이터 처리 파이프라인을 설계할 때도 유효합니다.
  3. Recreational Programming의 가치: Rob Pike 같은 거장도 “심심풀이(pleasant distraction)“로 코딩을 합니다. 실무와 무관해 보이는 이런 탐구들이 결국 Go 언어의 math/big 라이브러리 개선으로 이어졌다는 점을 기억해야 합니다.

결론: 낭만 합격

솔직히 말해, 현업에서 감마 함수를 50자리 정밀도로 계산할 일이 얼마나 있겠습니까? 하지만 엔지니어링은 효율성만을 위한 것이 아닙니다. 극한의 정밀도를 추구하며 1비트의 오차와 싸우는 그 과정 자체가 엔지니어에게는 최고의 유희이자 훈련입니다.

Rob Pike의 이번 글은 “제대로 된 바퀴를 다시 발명하는 법” 에 대한 훌륭한 교과서입니다.


References: