Reverse-engineering the vintage Intel 8087's tangent algorithm: more than CORDIC
빈티지 Intel 8087의 탄젠트 알고리즘 역설계 — CORDIC만 쓰지 않았습니다
Intel 8087의 FPTAN 명령어를 다이 회로와 마이크로코드로 역설계해, CORDIC과 Padé 근사를 결합한 계산 과정을 설명합니다. 이 설계는 64비트 정밀도를 겨냥하면서도 8086에서 소프트웨어로 13,000마이크로초 걸리던 탄젠트 계산을 90마이크로초로 줄였습니다.
- 주제
AI 요약
Intel 8087은 1980년 IBM PC 등에 부동소수점 연산을 제공한 보조 프로세서입니다. 글쓴이는 칩의 다이를 현미경으로 촬영하고 마이크로코드 ROM을 분석해, 탄젠트 명령어 FPTAN이 계산을 수행하는 방식을 복원합니다. 8087은 CORDIC만으로 정밀도를 높이지 않고, 남은 작은 각도에 Padé 근사를 적용한 뒤 다시 CORDIC 회전을 수행합니다.
CORDIC으로 각도를 줄입니다
CORDIC은 곱셈과 나눗셈 없이 시프트와 덧셈, 뺄셈, 표 조회로 삼각함수를 계산하는 알고리즘입니다. 8087은 미리 저장한 특수 각도 arctan(2⁻ⁿ)을 입력 각도와 차례로 비교합니다. 각도를 빼면 1, 빼지 않으면 0을 기록합니다. 이 결정 비트열은 이후 회전에 쓰입니다. 글에서는 이 과정을 몫을 구하는 나눗셈과 닮았다고 설명하며 ‘의사 나눗셈(pseudo-division)’이라 부릅니다.
CORDIC을 16회 수행하면 약 16비트 정밀도를 얻습니다. 64비트 정밀도까지 같은 방식으로 계산하려면 약 64회가 필요하므로, 8087은 남은 작은 각도를 별도 근사식으로 처리합니다. 이 잔여각 x에는 3x/(3−x²)라는 Padé 근사를 적용합니다. x가 약 2⁻¹⁶보다 작아 오차가 2⁻⁶⁴보다 작습니다. 근사식의 분자와 분모를 각각 벡터의 Y와 X로 사용하므로 나눗셈을 따로 하지 않습니다. FPTAN은 탄젠트 값을 직접 반환하지 않고 X와 Y를 스택에 넣으며, 두 값을 나누면 탄젠트가 됩니다.
두 단계의 CORDIC과 마이크로코드
FPTAN은 먼저 입력 지수에 따라 경로를 나눕니다. 입력이 아주 작으면 탄젠트와 입력값의 차이가 정밀도 안에서 구분되지 않으므로 입력값을 그대로 반환하고 분모 1을 추가합니다. 조금 큰 입력은 CORDIC을 생략하고 Padé 근사로 바로 이동합니다. 나머지는 최대 16개 특수 각도를 비교해 잔여각과 결정 비트열을 구합니다.
그 다음 마이크로코드는 잔여각의 제곱을 계산하고 Padé 근사의 분자·분모를 만듭니다. 마지막으로 저장한 결정 비트를 거꾸로 읽으며 벡터에 회전을 적용합니다. 작은 회전부터 처리해 반올림 오차를 줄입니다. 회전은 시프트와 덧셈·뺄셈으로 구현합니다. 이 계산에서 8087은 값의 실제 지수를 레지스터에 매번 저장하지 않고, 단계마다 달라지는 암묵적 지수를 전제로 고정소수점 정수 연산을 합니다. 마이크로코드는 16비트 명령어로 데이터 이동과 조건 분기를 제어하며, 곱셈에 쓰이는 제곱 루틴은 Booth 알고리즘으로 두 비트씩 처리합니다.
성능과 설계의 맥락
8087은 탄젠트 계산에 90마이크로초가 걸렸습니다. 8086에서 소프트웨어로 계산할 때의 13,000마이크로초보다 크게 빨랐습니다. FPTAN은 입력값에 따라 약 30~540클록이 걸리며, 문서상 보통 450클록입니다. 글쓴이가 살펴본 0.95 입력에서는 의사 나눗셈이 전체 시간의 33%, Padé 근사가 15%, 의사 곱셈이 47%, 나머지 처리가 5%를 차지했습니다.
이후 Pentium에서는 빠른 곱셈 회로를 활용해 CORDIC 대신 다항 근사를 사용했습니다. 오늘날 Intel의 MKL과 SVML도 병렬 명령어 SIMD를 활용하는 최적화된 수학 라이브러리를 제공합니다. 이 글은 8087 다이의 회로와 마이크로코드를 실제 연산 절차에 연결해, 당시 하드웨어가 정밀도와 속도를 함께 맞춘 방식을 구체적으로 보여줍니다.
Reddit 반응
- @u/codetillsleep — Ken Shirriff의 글을 정말 좋아합니다.
- @u/kenshirriff — 감사합니다.
원문: righto.com / 번역·요약: Trawling