계산 결과가 틀렸을 때 책임은 둘 중 하나에 있습니다. 문제가 원래 예민해서 입력의 작은 오차가 답을 크게 흔드는 경우, 아니면 알고리즘이 계산 도중에 필요 없는 오차를 키운 경우입니다. 앞의 것은 어떤 알고리즘으로도 고칠 수 없고, 뒤의 것은 식을 바꾸면 고칠 수 있습니다. 이 장은 둘을 재는 두 개의 자를 만듭니다. 문제의 민감도는 조건수κ로, 알고리즘의 품질은 후방 오차로 잽니다. 그리고 수치해석에서 가장 많이 쓰는 어림식 하나로 둘을 묶습니다. 전방 오차 ≲ 조건수 × 후방 오차. 1장의 반올림 단위 u가 "후방 오차"의 단위가 되고, 이 장의 조건수가 그 오차가 답에서 몇 배로 보일지를 알려 줍니다.
문제의 민감도(조건)와 알고리즘의 품질(안정성)을 구별하고, 같은 오차가 어느 쪽 책임인지 판정한다.
상대 조건수 κf(x)=∣xf′(x)/f(x)∣를 유도하고, 기본 함수·뺄셈·다변수 함수의 조건수를 계산한다.
방정식의 근이 계수 교란에 얼마나 민감한지 계산하고, 중근과 윌킨슨 다항식이 왜 예민한지 설명한다.
1940년대 말 전자계산기가 처음 큰 선형계를 풀기 시작했을 때, 많은 사람이 비관했습니다. 소거 한 번마다 반올림 오차가 생기고, 미지수가 수십 개면 연산이 수만 번이니 오차가 걷잡을 수 없이 쌓일 것이라는 계산이었습니다. 영국 국립물리연구소에서 튜링(Alan Turing)과 함께 일한 윌킨슨(James H. Wilkinson)은 질문을 뒤집었습니다. "계산된 답은 참값과 얼마나 다른가"를 묻는 대신 "계산된 답은 어떤 조금 다른 문제의 정확한 답인가"를 물은 것입니다. 이것이 후방 오차 분석입니다. 그는 부분 피벗팅 가우스 소거 같은 알고리즘이 원래 행렬을 반올림 단위 수준으로만 바꾼 문제를 정확히 푼다는 것을 보였고, 이 업적으로 1970년 튜링상을 받았습니다.
이 관점 덕분에 오차 분석이 두 조각으로 나뉩니다. 알고리즘이 후방 안정한가(라이브러리 설계자의 일), 문제의 조건수가 얼마인가(사용자가 알아야 할 일). LAPACK 같은 선형대수 라이브러리가 해와 함께 조건수 추정값을 돌려주는 이유가 여기에 있습니다. 시뮬레이션, 회로 해석, 기계 학습의 모든 계산이 이 분업 위에서 신뢰를 얻습니다.
답이 틀렸다→문제 탓인가, 알고리즘 탓인가→전방 오차 ≲ κ × 후방 오차→믿을 수 있는 계산
문제의 민감도와 알고리즘의 품질
4자리밖에 맞지 않는 두 계산
(가) 센서가 x=1.0001을 상대 오차 10−8으로 측정했습니다. 이 값으로 lnx를 계산했더니 답의 상대 오차가 10−4입니다. (나) x=10−10은 정확히 주어졌는데, Math.log(1 + x)로 ln(1+x)를 계산했더니 상대 오차가 8.3×10−8입니다. 두 경우 모두 기대보다 많은 자릿수를 잃었습니다. 그런데 하나는 어떤 방법으로도 더 나아지지 않고, 다른 하나는 함수 하나만 바꾸면(Math.log1p(x)) 16자리가 다 맞습니다. 어느 쪽이 어느 쪽일까요?
(가)에서는 계산이 완벽해도 소용이 없습니다. 입력 x 자체가 10−8만큼 불확실하고, ln이 1 근처에서 입력의 상대 변화를 1만 배로 키우기 때문입니다. 이것은 문제의 성질입니다. (나)에서는 문제 x↦ln(1+x)가 전혀 예민하지 않습니다. 입력이 10−8 바뀌면 답도 약 10−8 바뀝니다. 오차는 계산 순서 탓입니다. 1+x를 먼저 반올림하는 순간 x의 아래 자리가 u≈10−16만큼 잘려 나가는데, 그 잘림은 x에 견주면 10−16/10−10=10−6 정도입니다. 이것은 알고리즘의 성질입니다.
정의 2.1 (문제와 알고리즘) 수치 계산의 문제는 입력 x에서 정확한 출력 y=f(x)로 가는 사상 f다. 알고리즘은 부동소수점 연산의 유한한 나열로 f의 근삿값 y^=f^(x)를 만드는 절차다. 같은 f를 계산하는 알고리즘은 여러 가지다. 문제가 입력의 작은 교란에 얼마나 민감한지를 문제의 조건(conditioning)이라 하고, 알고리즘이 반올림 오차를 얼마나 억제하는지를 알고리즘의 수치적 안정성(numerical stability)이라 한다.
그림 2-1. 결과 오차의 두 출처. 왼쪽: 문제는 입력의 불확실성(측정 오차, 저장할 때의 반올림 u)을 조건수 κ배로 키운다. 오른쪽: 알고리즘의 결과 y^를 "조금 다른 입력 x^에 대한 정확한 답"으로 볼 때, x^가 x에서 u 정도만 떨어져 있으면 알고리즘은 할 일을 다 한 것이다. 둘을 합치면 결과의 상대 오차는 약 κ×(x^의 상대 거리)다(정리 2.9).
이 구분은 실무에서 질문을 바꿔 줍니다. 결과가 이상하면 먼저 "조건수가 얼마인가"를 묻습니다. 조건수가 1012이면 배정밀도의 16자리 중 12자리는 원래 믿을 수 없는 것이니, 알고리즘을 고칠 것이 아니라 문제를 바꿔야 합니다(측정을 더 정확히, 모델을 다르게, 변수를 바꿔서). 조건수가 작은데 결과가 나쁘면 그때는 알고리즘을 바꿉니다. MathBook의 조건수 맛보기와 LinearBook의 행렬 조건수를 여기서 일반적인 틀로 다시 세웁니다.
상대 조건수: 입력 오차가 몇 배로 퍼지는가
사인 값이 6자리를 잃는 곳
x=3.14159에서 sinx를 계산합니다. 입력의 마지막 자리 하나가 바뀌면(상대 변화 3×10−6) 답은 얼마나 바뀔까요? sinx≈π−x=2.65×10−6이므로 x가 10−5만 움직여도 답이 네 배쯤 달라집니다. 반면 x=1에서는 같은 입력 변화가 답을 거의 같은 비율로만 바꿉니다. 같은 함수인데 어디서 계산하느냐에 따라 예민함이 백만 배 다릅니다. 이것을 하나의 수로 재고 싶습니다.
입력이 x에서 x+Δx로 바뀌면 출력은 f(x+Δx)−f(x)≈f′(x)Δx만큼 바뀝니다(1차 테일러 근사, CalculusBook의 미분과 오차 전파). 양변을 f(x)로 나누고 오른쪽에 x/x를 끼워 넣으면 상대 변화끼리의 관계가 나옵니다.
f(x)f(x+Δx)−f(x)≈증폭인자f(x)xf′(x)⋅xΔx
정의 2.2 (상대 조건수) 미분 가능한 f와 x=0, f(x)=0에 대해
κf(x)=f(x)xf′(x)
를 x에서 f의 상대 조건수(relative condition number)라 한다. ∣f′(x)∣는 절대 조건수다. κ가 1 정도면 조건이 좋다(well-conditioned), 매우 크면 조건이 나쁘다(ill-conditioned)고 한다.
정리 2.3 (조건수와 출력 오차)f가 x 근처에서 두 번 연속 미분 가능하고 x^=x(1+δ)이면
실용적인 읽기: 입력이 u 정도 정확하면(저장만 해도 그렇다) 출력의 상대 오차는 약 κu이고, 10진 자릿수로 log10κ자리를 잃는다.
함수 f(x)
κf(x)
조건이 나쁜 곳
예: κ 값
xa (√x는 a = 1/2)
|a|
없음(어디서나 |a|)
√x: 0.5
ex
|x|
|x|가 클 때
x = 100: 100
ln x
1/|ln x|
x ≈ 1
x = 1.0001: 1.0×10⁴
sin x
|x cot x|
x ≈ kπ (k ≠ 0)
x = 3.14159: 1.18×10⁶
cos x
|x tan x|
x ≈ π/2 + kπ
x = 1.5707: 1.63×10⁴
tan x
|2x / sin 2x|
x ≈ kπ/2 (k ≠ 0)
x = 1.57: 1.97×10³
x − 1
|x / (x − 1)|
x ≈ 1
x = 1.0001: 1.0×10⁴
1/x
1
없음
1
표에서 몇 가지 규칙이 보입니다. 곱셈형 연산(거듭제곱, 역수)은 언제나 조건이 좋습니다. 조건이 나빠지는 곳은 거의 언제나 출력이 0에 가까워지는 곳(ln1=0, sinπ=0, cos(π/2)=0)이거나 출력이 무한대로 가는 곳(tan의 극점)입니다. 0 근처에서 상대 오차는 작은 절대 변화에도 크게 바뀌기 때문입니다. 지수 함수는 특별합니다. ex의 조건수 ∣x∣는 x=700이면 700이라, 입력의 u가 출력에서는 700u≈8×10−14가 됩니다. 공학의 아레니우스 식 e−E/RT처럼 지수가 큰 모델이 온도 측정 오차에 예민한 이유입니다.
실험: x에 [−10−8,10−8]의 무작위 상대 교란 δ를 1000번 주고 ∣Δy/y∣/∣δ∣의 평균을 구하면 ln은 10000.50, tan은 1971.55다. 정리 2.3 그대로다.
교란이 크면 1차 근사가 깨진다. tan(1.57)=1255.766, tan(1.57×(1+10−6))=1258.246으로 상대 변화는 1.98×10−3이다. κδ=1.97×10−3과 거의 같지만, 교란을 10−3으로 키우면 x가 극점 π/2=1.5708을 넘어가 부호까지 바뀐다.
SIMULATOR
입력 교란 → 출력 퍼짐: 조건수 실험
κ(x) (로그 축) · 세로선 = 현재 x
입력 상대 교란 δ → 출력 상대 변화
교란 크기 |δ| ≤
교란 실험 한 번예측 기울기 ±κ
x · f(x)—
이론 κ = |x f′/f|—
실험 max |Δy/y| / |δ|—
잃는 자릿수 log₁₀κ—
해볼 것: ① ln x에서 x를 1 쪽으로 끌면 아래 그림의 점들이 가파른 직선 위에 늘어섭니다. 기울기가 곧 κ입니다. ② sin x를 π 근처로, tan x를 π/2 근처로 옮겨 κ가 폭발하는 것을 보세요. ③ 교란을 10⁻³으로 키우면 조건이 나쁜 곳에서 점들이 직선을 벗어나 휘어집니다. 정리 2.3의 O(δ²) 항이 보이는 것입니다. 모델: x̂ = x(1 + δ), δ는 균등 분포, f는 배정밀도 라이브러리 함수.
함수별 조건수: 빼기, 여러 변수, 방정식의 근
입력이 여러 개인 문제도 같은 생각으로 다룹니다. 각 입력이 상대적으로 δi만큼 흔들릴 때 출력의 상대 변화는 1차까지 ∑i(xi∂f/∂xi)/f⋅δi입니다.
정의 2.4 (성분별 상대 조건수)f(x1,…,xn)과 ∣δi∣≤δ인 교란 x^i=xi(1+δi)에 대해 ∣f(x^)−f(x)∣/∣f(x)∣≤κδ+O(δ2)을 만족하는 가장 작은 수는
κf(x)=∣f(x)∣∑i=1n∣xi∣∣∂f/∂xi∣.
연산
κ (정의 2.4)
읽는 법
x + y (같은 부호)
(|x| + |y|)/|x + y| = 1
양수끼리의 덧셈은 언제나 안전
x − y (같은 부호)
(|x| + |y|)/|x − y|
x ≈ y이면 무한히 커진다: 자릿수 상쇄
x · y, x / y
2
두 입력의 상대 오차가 더해질 뿐
√(x² + y²)
1
조건이 좋다(1장의 빗변 문제는 중간값의 범위 문제였다)
xy
|y| + |y ln x|
지수가 크거나 밑이 0·∞에서 멀 때
뺄셈의 조건수 (∣x∣+∣y∣)/∣x−y∣는 1장 정리 1.9의 증폭 인자 그대로입니다. 1장에서는 "뺄셈이 오차를 키운다"고 했지만, 이제 더 정확히 말할 수 있습니다. 뺄셈 연산은 정확하거나 거의 정확합니다. 키우는 것은 x≈y에서 조건이 나쁜 뺄셈이라는 문제이고, 그 문제에 들어가는 입력이 이미 오차를 품고 있을 때 피해가 드러납니다. 예를 들어 1.0001−1의 조건수는 2.0001/0.0001≈2.0×104입니다.
아래 지도는 입력이 둘인 문제의 조건수를 평면 전체에 색으로 칠합니다. 조건이 나쁜 곳은 대개 곡선 하나를 따라 몰려 있습니다. 뺄셈은 대각선 x=y, 이차방정식의 근은 판별식이 0인 포물선 위입니다.
SIMULATOR
조건수 지도: 입력 평면에서 예민한 곳 찾기
지도를 클릭·드래그해 입력 고르기
κ ≈ 1κ ≈ 10⁶κ ≥ 10¹²정의 안 됨(복소근 등)
입력—
출력 f—
조건수 κ—
실험 (교란 10⁻⁹, 200번)—
해볼 것: ① x − y에서 대각선 가까이 가면 κ가 10⁶, 10⁹로 뛰고, 대각선에서 멀어지면 1에 가까워집니다. 반대 부호 영역(제2·4사분면)은 사실 덧셈이라 κ ≤ 1입니다. ② x · y는 어디서나 2라 지도가 한 색입니다. ③ 이차방정식은 판별식 b² − 4c = 0인 포물선 위에서 κ가 무한대입니다. 중근은 조건이 나쁩니다(정리 2.6). 모델: 정의 2.4의 성분별 조건수, 실험은 각 입력에 독립 균등 상대 교란.
방정식의 근은 얼마나 예민한가
3장에서 푸는 문제 f(x)=0도 하나의 문제입니다. 입력은 함수 f(실제로는 그 계수나 매개변수), 출력은 근 r입니다. f를 f+εg로 조금 바꾸면 근이 r+Δr로 움직이고, 0=f(r+Δr)+εg(r+Δr)≈f′(r)Δr+εg(r)에서 Δr을 구할 수 있습니다.
정리 2.5 (단순근의 조건수)f(r)=0, f′(r)=0이면 f+εg의 근 r(ε)은
r(ε)=r−εf′(r)g(r)+O(ε2).
특히 다항식 p(x)=∑kakxk의 계수를 ak(1+εk), ∣εk∣≤ε로 바꾸면
분모 f′(r)이 핵심입니다. 근에서 그래프가 납작하면, 곧 f′(r)이 작으면 f를 위아래로 조금만 흔들어도 그래프가 0을 지나는 자리가 크게 미끄러집니다. 3장 멈춤 조건에서 본 "불확실 구간"이 바로 이것입니다. f′(r)=0인 중근에서는 정리 2.5가 아예 쓸모없고, 더 나쁜 일이 일어납니다.
정리 2.6 (중근의 민감도)r이 f의 m중근(f(r)=⋯=f(m−1)(r)=0=f(m)(r))이고 g(r)=0이면, f+εg의 근은 r 근처에서
∣Δr∣≈f(m)(r)m!εg(r)1/m
만큼 움직인다. 교란이 ε이면 근의 오차는 ε1/m에 비례한다. 조건수(비)가 유한하지 않다.
ε=10−16(배정밀도로 f를 계산할 때 생기는 크기)이면 근이 10−8 움직인다. 16자리 정확한 함숫값으로 8자리 근밖에 얻지 못한다.
ε<0이면 실근이 사라지고 1±i∣ε∣가 된다. 아래 지도의 포물선 바깥(회색)으로 나가는 것이다.
3중근이면 ε1/3≈5×10−6, 곧 5자리 남짓만 남는다. 3장 예제 3.7의 7중근에서는 ε1/7이 되어 불확실 구간의 반지름이 0.0093에 이른다.
윌킨슨 다항식: 서로 멀리 떨어진 단순근도 예민할 수 있다
근이 1, 2, …, 20인 다항식
윌킨슨 다항식(Wilkinson's polynomial)w(x)=(x−1)(x−2)⋯(x−20)의 근은 정수 1부터 20까지로 서로 1씩 떨어져 있고 모두 단순근입니다. 겉보기에는 아무 문제가 없습니다. 이 다항식을 전개하면 x20−210x19+20615x18−⋯+20!이고, 계수는 x2의 계수 1.38×1019까지 커집니다. 1959년 윌킨슨은 x19의 계수 −210을 −210−2−23으로, 곧 상대적으로 5.7×10−10만 바꾸면 근이 어떻게 되는지 계산했습니다.
결과는 충격적입니다. 아래 표는 이 장의 시뮬레이터와 같은 방법(곱 꼴로 정확히 계산한 w에 교란 항을 더하고 에를리히–애버스 반복으로 20개 근을 동시에 구함)으로 얻은 값입니다. 근 10부터 19까지가 복소수 쌍 다섯 개로 바뀌고, 그중 하나는 실수축에서 2.81이나 떨어집니다. 이 값은 윌킨슨이 발표한 16.730737±2.812625i와 일치합니다.
원래 근
교란 후 근
∂r/∂a₁₉
κr (a₁₉만)
κr (모든 계수)
1
1.000000000
8.2×10⁻¹⁸
1.7×10⁻¹⁵
4.2×10²
5
4.999999928
0.61
2.6×10¹
8.2×10⁸
8
8.007267603
−6.0×10⁴
1.6×10⁶
3.9×10¹¹
9
8.917250249
8.4×10⁵
2.0×10⁷
1.7×10¹²
10, 11
10.095266 ± 0.643501i
−7.6×10⁶ · 4.6×10⁷
1.6×10⁸ · 8.9×10⁸
5.6×10¹² · 1.4×10¹³
12, 13
11.793634 ± 1.652330i
−2.0×10⁸ · 6.1×10⁸
3.5×10⁹ · 9.8×10⁹
2.8×10¹³ · 4.4×10¹³
14, 15
13.992358 ± 2.518830i
−1.3×10⁹ · 2.1×10⁹
2.0×10¹⁰ · 3.0×10¹⁰
5.4×10¹³ · 5.0×10¹³
16, 17
16.730737 ± 2.812625i
−2.4×10⁹ · 1.9×10⁹
3.2×10¹⁰ · 2.3×10¹⁰
3.5×10¹³ · 1.8×10¹³
18, 19
19.502439 ± 1.940330i
−1.0×10⁹ · 3.1×10⁸
1.2×10¹⁰ · 3.4×10⁹
6.4×10¹² · 1.4×10¹²
20
20.846908101
−4.3×10⁷
4.5×10⁸
1.4×10¹¹
정리 2.5가 이유를 말해 줍니다. 근 16에서 ∂r/∂a19=−r19/w′(r)=−1619/(15!⋅4!)≈−2.4×109입니다. 분자 1619≈7.6×1022이 분모 ∣w′(16)∣=15!4!≈3.1×1013보다 압도적으로 큽니다. 상대 조건수 3.2×1010에 교란 5.7×10−10을 곱하면 18로, 1차 근사가 의미 없을 만큼 큰 변화입니다. 근이 서로 충돌해 복소수로 튀어나간 것입니다.
더 놀라운 사실이 있습니다. 계수 21개 가운데 x3부터 x7까지의 계수 다섯 개는 253보다 커서 배정밀도에 정확히 담기지 않습니다. 계수를 double로 저장만 해도(상대 교란 10−16 이하) 근 13의 오차가 6.2×10−4가 됩니다. "모든 계수" 열의 조건수 5.4×1013과 u를 곱한 6×10−3이 그 상한입니다. 그래서 고유값을 특성 다항식의 근으로 구하지 않습니다(14장). 고유값 문제 자체는 조건이 좋을 수 있는데, 다항식 계수로 옮기는 순간 훨씬 예민한 문제로 바꾸게 됩니다. 반대로 동반 행렬의 고유값으로 다항식의 근을 구하는 방법(4장)은 계수에 대해 후방 안정해서, 오차가 이 조건수가 허락하는 만큼만 생깁니다.
SIMULATOR
윌킨슨 다항식 근 흔들기: 계수 하나에 근 열 개가 튄다
복소 평면: 가로 Re, 세로 Im
교란 방식
원래 근 1, …, 20교란된 다항식의 근무작위 시행 12번(모든 계수)
교란—
가장 많이 움직인 근—
복소근 개수—
1차 예측 max κr·ε·r—
해볼 것: ① k를 60에서 줄여 가며 근 15, 16 근처가 먼저 움직이고, k = 32에서 처음으로 이웃한 근들이 만나 복소수 쌍으로 갈라지는 것을 보세요(k = 33까지는 모두 실근이지만 이미 0.3이나 움직였습니다). ② '윌킨슨 k = 23'은 위 표를 재현합니다. ③ '모든 계수'에서 k = 53(반올림 단위 수준)이면 근 11–16이 10⁻²에 가깝게 흩어집니다. 저장만 해도 생기는 오차입니다. 모델: w(z)를 곱 꼴 ∏(z − j)로 계산하고 교란 항 Σ εjajzj를 더한 뒤, 교란을 0에서 조금씩 키우며 에를리히–애버스 반복으로 근을 따라갑니다.
전방 오차와 후방 오차, 후방 안정
참값을 모르는데 알고리즘을 어떻게 평가할까
y^가 참값 y와 얼마나 다른지(전방 오차)는 보통 알 수 없습니다. 참값을 알면 계산할 필요가 없으니까요. 그런데 거꾸로 "y^는 어떤 입력의 정확한 답인가"는 계산할 수 있는 경우가 많습니다. 선형계라면 잔차 b−Ax^를 보면 되고, 근이라면 f(r^)을 보면 됩니다. 이 거꾸로 된 질문이 알고리즘을 판정하는 깔끔한 자가 됩니다.
정의 2.7 (전방 오차, 후방 오차) 문제 y=f(x)와 알고리즘의 결과 y^에 대해
전방 오차(forward error): ∣y^−y∣/∣y∣. 출력 공간에서 잰 오차.
후방 오차(backward error): η(y^)=min{∣Δx∣/∣x∣:y^=f(x+Δx)}. y^를 정확한 답으로 갖는 입력이 원래 입력에서 상대적으로 얼마나 떨어져 있는가.
그림 2-2. 후방 오차의 뜻. 알고리즘이 낸 y^를 정확한 f가 내도록 하는 입력 x+Δx를 찾는다. Δx가 입력의 원래 불확실성(최소한 u)보다 작다면, 알고리즘은 "데이터를 저장하는 것만큼만" 틀린 셈이다. 전방 오차는 이 Δx를 문제의 조건수가 키운 결과다.
정의 2.8 (후방 안정) 모든 입력 x에 대해 후방 오차가 η(f^(x))≤cu(상수 c는 문제 크기에만 약하게 의존)인 알고리즘을 후방 안정(backward stable)이라 한다. 조금 약하게, y^+Δy=f(x+Δx)이고 ∣Δy∣/∣y∣, ∣Δx∣/∣x∣가 모두 O(u)이면 혼합 전방–후방 안정(mixed stable), 흔히 그냥 "수치적으로 안정"이라 한다.
정리 2.9 (오차의 어림 규칙) 알고리즘의 후방 오차가 η이고 문제의 상대 조건수가 κ이면
∣y∣∣y^−y∣≤κη+O(η2).
증명.y^=f(x+Δx), ∣Δx∣/∣x∣=η. 정리 2.3을 δ=Δx/x에 적용하면 된다. ∎ 후방 안정 알고리즘은 따라서 κu 정도의 전방 오차를 낸다. 이것은 입력을 저장하는 반올림만으로도 생기는 오차이므로, 후방 안정 알고리즘은 그 문제에서 기대할 수 있는 최선이다.
가장 단순한 예는 사칙연산 자체입니다. 표준 모형 fl(x−y)=(x−y)(1+δ)는 =x(1+δ)−y(1+δ)로 읽을 수 있습니다. 입력을 각각 상대적으로 u 이하만큼 바꾼 문제의 정확한 답이므로 뺄셈은 후방 안정합니다. 그런데도 x≈y이면 전방 오차가 큽니다. 문제(뺄셈)의 조건수가 크기 때문입니다. "뺄셈은 불안정하다"는 말은 틀린 말이고, "x≈y인 뺄셈은 조건이 나쁘다"가 맞는 말입니다.
예제 2.3 (호너 방법: 큰 전방 오차, 작은 후방 오차)p(x)=(x−2)9를 전개한 계수 1,−18,144,…,−512로 호너 방법을 써서 계산하고, 참값 (x−2)9과 비교하라. 호너 방법은 계수를 상대적으로 γ18≈18u 이하만큼 바꾼 다항식의 정확한 값을 준다(정리 2.15). 다항식 값의 조건수는 ∑∣ak∣∣x∣k/∣p(x)∣=(∣x∣+2)9/∣x−2∣9이다.
x
호너 값
참값 (x − 2)⁹
상대 오차
조건수
상한 γ₁₈·조건수
2.5
0.001953125
0.001953125
0
3.9×10⁸
7.7×10⁻⁷
2.1
9.98057×10⁻¹⁰
1.00000×10⁻⁹
1.9×10⁻³
3.3×10¹⁴
0.65
2.01
−3.75167×10⁻¹²
1.00000×10⁻¹⁸
3.8×10⁶
2.7×10²³
5.4×10⁸
2.001
6.25278×10⁻¹²
1.00000×10⁻²⁷
6.3×10¹⁵
2.6×10³²
5.3×10¹⁷
x=2.01에서 계산값은 부호조차 틀렸지만 상한 안에 있습니다. 호너 방법은 할 일을 다 했고, 전개된 계수로 근 근처의 값을 묻는 문제가 1023만큼 조건이 나쁜 것입니다. 3장 예제 3.7의 (x−1)7 잡음과 같은 현상입니다. 처방은 알고리즘이 아니라 표현을 바꾸는 것입니다. 곱 꼴 (x−2)9이나 근 근처의 테일러 계수로 저장하면 조건수가 9가 됩니다.
아래 시뮬레이터는 여러 계산에서 전방 오차를 재고, 정리 2.9를 거꾸로 써서 후방 오차를 η≈(전방오차)/κ로 추정합니다. 안정한 알고리즘은 η가 u 근처에 붙어 있고, 불안정한 알고리즘은 η가 u보다 훨씬 위로 올라갑니다.
SIMULATOR
후방 오차 그림: 문제 탓과 알고리즘 탓 가르기
알고리즘
전방 오차 (측정)후방 오차 η ≈ 전방/κκu: 안정 알고리즘이 낼 오차
계산값 ŷ—
조건수 κ—
전방 오차—
후방 오차 η / u—
해볼 것: ① ln(1 + x) '식 그대로'에서 κ ≈ 1인데 전방 오차가 u/x 기울기로 커집니다. η도 같이 커지므로 알고리즘 탓입니다. '다시 쓴 식'(카한의 log1p 공식)으로 바꾸면 η가 u 아래로 내려갑니다. ② 'ln x, x = 1 + t'는 반대입니다. 전방 오차는 크지만 η는 u 수준이라, 문제 탓입니다. 어떤 식으로 바꿔도 x가 double로 주어진 한 나아지지 않습니다. ③ 1 − cos x는 κ ≈ 2인데 식 그대로면 x ≈ 10⁻⁸에서 결과가 0이 됩니다. 모델: 참값은 Math.log1p, Math.expm1, 테일러 급수(1 − cos x)로 계산, η는 1차 근사.
안정한 알고리즘과 불안정한 알고리즘
조건이 좋은 문제를 불안정하게 계산하는 알고리즘은 대개 조건이 나쁜 중간 단계를 거칩니다. ln(1+x)를 "w=1+x, 그다음 lnw"로 계산하면 둘째 단계의 조건수가 1/∣lnw∣≈1/∣x∣입니다. 첫째 단계에서 생긴 u의 오차가 둘째 단계에서 1/∣x∣배로 커집니다. 문제 전체의 조건수는 1인데 알고리즘이 스스로 예민한 하위 문제를 만든 것입니다.
정리 2.10 (단계별 조건수와 오차 전파) 알고리즘이 f=g∘h를 w=fl(h(x)), y^=fl(g(w))로 계산하고 두 단계가 각각 상대 오차 u 이하로 정확하면
∣y∣∣y^−y∣≲κg(h(x))u+u.
따라서 문제의 조건수 κf=κgκh가 작더라도 κg가 크고 κh가 작으면(둘째 단계가 첫째 단계의 반올림을 키우고, 첫째 단계는 그 반대로 줄여 주지 못하면) 불안정하다.
증명의 핵심.w=h(x)(1+δ1)이므로 정리 2.3에서 g(w)=g(h(x))(1+κgδ1+O(δ12)). 여기에 마지막 반올림 (1+δ2)를 곱한다. ∎
점화식: 같은 식, 반대 방향, 정반대의 결과
양수여야 할 적분이 −30이 되었다
In=∫01xnex−1dx를 n=0,1,…,20에 대해 구하려고 합니다. 부분 적분을 한 번 하면 In=1−nIn−1이고 I0=1−1/e이니, 차례대로 계산하면 됩니다. 피적분 함수가 양수이므로 In>0이고, ex−1≤1에서 In<∫01xndx=1/(n+1)입니다. 그런데 배정밀도로 계산하면 I18=−0.0295, I20=−30.19가 나옵니다.
원인을 추적해 봅시다. 계산값 I^n−1=In−1+en−1을 점화식에 넣으면 I^n=1−nI^n−1=In−nen−1이므로 오차는 en=−nen−1, 곧
∣en∣=n!∣e0∣.
I0을 저장할 때의 오차 ∣e0∣≈10−17이 20!≈2.4×1018배 커져 30 정도가 된다. 각 단계의 반올림 오차도 같은 식으로 커진다. 점화식의 한 단계는 앞 값의 오차를 n배로 키우는, 조건수 n짜리 단계다.
처방은 점화식을 거꾸로 쓰는 것입니다. In−1=(1−In)/n이면 오차는 en−1=−en/n, 단계마다 n으로 나뉩니다. 시작값을 아무렇게나, 예를 들어 IN=0으로 놓아도 오차 ∣eN∣=IN<1/(N+1)이 N!/n!로 나뉘어 곧 사라집니다. 베셀 함수처럼 점화식으로 계산하는 특수 함수 라이브러리가 쓰는 밀러 알고리즘(Miller's algorithm)이 이 생각입니다.
예제 2.4 (앞으로와 뒤로) 앞으로는 I0=fl(1−1/e)에서, 뒤로는 I20=0과 I30=0에서 시작한다. 참값은 I100=0에서 거꾸로 계산한 값(심프슨 적분으로 10−15까지 확인)이다.
n
참값 In
앞으로 În
상대 오차
뒤로 (I₂₀ = 0)
상대 오차
뒤로 (I₃₀ = 0) 오차
0
0.632120558829
0.6321205588
0
0.6321205588
0
0
5
0.145532940573
0.1455329406
1.0×10⁻¹⁴
0.1455329406
0
0
10
0.083877070103
0.08387707006
5.4×10⁻¹⁰
0.08387707010
8.1×10⁻¹³
0
15
0.059017540879
0.05903379364
2.8×10⁻⁴
0.05901756536
4.2×10⁻⁷
0
17
0.052771119169
0.05719187060
8.4×10⁻²
0.05277777778
1.3×10⁻⁴
0
18
0.050119854958
−0.02945367075
1.6
0.05000000000
2.4×10⁻³
0
20
0.045544884076
−30.19239489
6.6×10²
0 (시작값)
1
6.3×10⁻¹⁵
뒤로 가는 계산은 시작값이 완전히 틀렸는데도(I20=0, 상대 오차 100%) 열 단계 만에 12자리가 맞습니다. 앞으로 가는 계산은 시작값이 16자리 정확한데도 18단계 만에 부호가 틀립니다. 같은 수학 공식이 계산 방향에 따라 안정하기도, 불안정하기도 합니다.
SIMULATOR
점화식 앞으로 vs 뒤로: Iₙ = 1 − n·Iₙ₋₁
방향
앞으로: I₀의 오차
계산값의 상대 오차예측: 앞으로 n!·|e₀|, 뒤로 |eN|·n!/N!
현재 n—
계산값 În—
참값 In—
상대 오차—
해볼 것: ① '앞으로'를 끝까지 돌리면 오차가 로그 축에서 점점 가팔라지는 곡선(n!)을 따라 올라가 n ≈ 17에서 100%를 넘습니다. ② I₀의 오차를 10⁻⁴로 키우면 같은 곡선이 위로 평행 이동할 뿐입니다. 시작 오차가 얼마든 n!배가 됩니다. ③ '뒤로'에서 N을 바꿔 보세요. 시작값이 완전히 틀려도 N − n 단계 뒤에는 오차가 N!/n!로 나뉘어 사라집니다. 모델: 배정밀도 계산, 참값은 I₁₀₀ = 0에서 뒤로 계산.
급수: x < 0에서 eˣ의 테일러 급수
e⁻²⁰을 테일러 급수로
ex=∑k≥0xk/k!는 모든 x에서 수렴합니다. x=−20을 넣고 항이 합을 더 바꾸지 못할 때까지 95개 항을 더하면 6.15×10−9이 나옵니다. 참값은 e−20=2.06×10−9입니다. 한 자리도 맞지 않습니다. 급수는 수렴했고 절단 오차는 10−30보다 작은데 무엇이 잘못되었을까요?
항의 크기를 보면 답이 나옵니다. x=−20이면 ∣x∣k/k!는 k=19,20에서 최대 4.31×107이 되고, 부호가 번갈아 바뀌는 이 큰 항들이 서로 지워져 2×10−9이 남아야 합니다. 그런데 4.3×107 크기의 수를 더할 때마다 반올림 오차가 u×4.3×107≈5×10−9씩 생깁니다. 답보다 큰 오차입니다. 1장 정리 1.10의 합산 오차 상한 ∝u∑∣tk∣가 정확히 이 상황입니다.
ex∣S^−ex∣≲cuex∑k∣x∣k/k!=cue∣x∣−x=cue2∣x∣(x<0).
문제 ex의 조건수는 ∣x∣=20으로 작다. 그런데 이 알고리즘(교대 급수 합)의 증폭 인자는 e40≈2.4×1017이다. 문제는 조건이 좋은데 알고리즘이 불안정한 전형적인 예다.
고치는 법은 간단합니다. x<0이면 ex=1/e∣x∣로 계산합니다. e∣x∣의 급수는 항이 모두 양수라 상쇄가 없고(합의 조건수 1), 역수는 조건수 1입니다.
x
참값 eˣ
최대 항 |x|ᵏ/k!
급수 그대로
상대 오차
1/e|x| (급수)
상대 오차
−1
0.3678794412
1
0.3678794412
3.0×10⁻¹⁶
0.3678794412
1.5×10⁻¹⁶
−5
6.737947×10⁻³
26.0
6.737947×10⁻³
1.2×10⁻¹³
6.737947×10⁻³
0
−10
4.539993×10⁻⁵
2.76×10³
4.539993×10⁻⁵
2.0×10⁻⁹
4.539993×10⁻⁵
1.5×10⁻¹⁶
−15
3.059023×10⁻⁷
3.35×10⁵
3.059100×10⁻⁷
2.5×10⁻⁵
3.059023×10⁻⁷
0
−20
2.061154×10⁻⁹
4.31×10⁷
6.147562×10⁻⁹
2.0
2.061154×10⁻⁹
4.0×10⁻¹⁶
−30
9.357623×10⁻¹⁴
7.76×10¹¹
6.103042×10⁻⁶
6.5×10⁷
9.357623×10⁻¹⁴
2.7×10⁻¹⁶
SIMULATOR
e⁻ˣ 급수 vs 1/eˣ: 큰 항들의 상쇄
알고리즘
항의 크기 |tₖ|부분합의 오차 |Sₖ − eˣ|반올림 바닥 u·max|tₖ|참값 eˣ
항 수 k—
부분합 (결과)—
참값 eˣ—
상대 오차 · 예측 u·Σ|tₖ|/eˣ—
해볼 것: ① x = −20에서 '자동'을 누르면 빨간 오차가 처음에는 항을 따라 커졌다가 줄어들지만, 주황 바닥(약 5×10⁻⁹)에서 멈춥니다. 그 바닥이 초록 참값보다 위에 있으면 답이 쓸모없습니다. ② '1 / Σ |x|ᵏ/k!'로 바꾸면 바닥이 참값의 u배 아래로 내려갑니다. ③ x를 양수로 옮기면 두 방법이 같아지고 둘 다 정확합니다. 모델: 배정밀도로 tₖ = tₖ₋₁·x/k, 참값은 Math.exp.
다시 쓰기로 정확도 구하기: log1p, expm1, 근의 공식
1초마다 붙는 이자
연이율 5%를 1년에 n번 나누어 복리로 붙이면 원금은 (1+0.05/n)n배가 되고, n→∞이면 e0.05=1.0512710963760241입니다. 이 식을 그대로 계산하면 n=1012에서 1.0512290843으로 다섯째 자리가 틀리고, n=1015에서는 정확히 1이 나옵니다. 이자가 사라졌습니다.
정리 2.10으로 진단합니다. 첫 단계 w=1+0.05/n에서 0.05/n의 아래 자리가 잘려 나가고(10−15이면 u와 비슷한 크기), 다음 단계 wn은 w에 대해 조건수가 n입니다. 처방은 wn=exp(nln(1+r/n))으로 쓰고, ln(1+z)를 1+z를 만들지 않고 계산하는 함수 log1p(z)를 쓰는 것입니다.
n
(1 + 0.05/n)ⁿ 그대로
상대 오차
exp(n · log1p(0.05/n))
상대 오차
365
1.0512674964674473
1.5×10⁻¹⁴
1.0512674964674626
< 10⁻¹⁵
10⁶
1.0512710949759108
8.2×10⁻¹¹
1.0512710950619353
< 10⁻¹⁵
10⁹
1.051271100723838
4.1×10⁻⁹
1.05127109637471
< 10⁻¹⁵
10¹²
1.0512290843310912
4.0×10⁻⁵
1.0512710963760228
< 10⁻¹⁵
10¹⁵
1
4.9×10⁻²
1.0512710963760241
< 10⁻¹⁵
(표의 상대 오차는 같은 n에서의 정확한 (1+0.05/n)n에 대한 것이다.) 수치 라이브러리가 log1p와 expm1(ex−1)을 따로 제공하는 이유입니다. 두 함수는 작은 x에서 조건이 좋은 문제(κ≈1)인데, 이름 그대로의 식으로 계산하면 상쇄가 끼어드는 경우입니다.
x
ln(1 + x) 그대로
상대 오차
log1p(x)
eˣ − 1 그대로
상대 오차
expm1(x)
10⁻⁵
9.999950000398841×10⁻⁶
6.6×10⁻¹²
9.999950000333332×10⁻⁶
1.000005000006965×10⁻⁵
9.7×10⁻¹²
1.000005000016667×10⁻⁵
10⁻¹⁰
1.000000082690371×10⁻¹⁰
8.3×10⁻⁸
9.9999999995×10⁻¹¹
1.000000082740371×10⁻¹⁰
8.3×10⁻⁸
1.00000000005×10⁻¹⁰
10⁻¹⁵
1.110223024625156×10⁻¹⁵
0.11
9.999999999999995×10⁻¹⁶
1.110223024625157×10⁻¹⁵
0.11
1.000000000000001×10⁻¹⁵
10⁻¹⁷
0
1
1×10⁻¹⁷
0
1
1×10⁻¹⁷
라이브러리가 없다면 어떻게 할까요? 카한이 알려 준 놀라운 요령이 있습니다. w=fl(1+x)는 틀렸지만, 틀린 w에 대해 lnw와 w−1은 모두 정확히 계산됩니다(w−1은 스테르베즈 보조정리로 정확). 그러면 매끄러운 함수 lnw/(w−1)은 w 대신 1+x에서의 값과 거의 같으므로, 여기에 x를 곱하면 오차가 상쇄됩니다.
// 카한의 log1p: ln(1 + x)를 상쇄 없이 (작은 |x|)
w ← fl(1 + x)
if w = 1 then return x // |x| < u: ln(1 + x) ≈ xreturn ln(w) · x / (w − 1) // ln(w)/(w − 1)은 w의 오차에 둔감// 같은 생각의 expm1: e^x − 1
v ← exp(x)
if v = 1 then return x
if v − 1 = −1 then return −1 // x가 매우 작은 음수return (v − 1) · x / ln(v)
앞의 시뮬레이터에서 '다시 쓴 식'이 이 두 공식입니다. 이 장과 1장에서 본 다시 쓰기를 모으면 몇 가지 원칙이 보입니다.
다시 쓰기로 고칠 수 없는 것 다시 쓰기는 알고리즘의 불안정을 고친다. 입력이 이미 반올림된 상태에서 문제의 조건이 나쁘면 어떤 식도 소용없다. 예를 들어 x=1+10−10이 double로 주어졌다면 lnx의 답은 10−6 정도의 상대 오차를 피할 수 없다. 하지만 원래 데이터가 t=10−10이었다면 ln(1+t)를 log1p(t)로 계산할 수 있다. 조건이 나쁜 문제는 종종 변수를 잘못 고른 문제다. 작은 양 t를 직접 들고 다니는 편이 1+t를 들고 다니는 것보다 낫다.
행렬 조건수 맛보기
거의 평행한 두 직선
연립방정식 x+y=2, x+1.0001y=2.0001의 해는 (1,1)입니다. 둘째 식의 우변을 측정 오차로 2.0002라고 적으면(상대 변화 5×10−5) 해는 (0,2)가 됩니다. 해가 100% 바뀌었습니다. 두 직선이 거의 평행해서 교점이 직선을 따라 멀리 미끄러지기 때문입니다.
그림 2-3. 조건이 나쁜 2×2 선형계. 두 직선이 이루는 각이 작을수록 한 직선을 조금 옮겼을 때 교점이 크게 움직인다. 행렬 조건수 κ(A)가 이 각의 역수 같은 역할을 한다. 이 행렬의 κ2(A)=4.0×104이다.
스칼라 조건수를 벡터로 옮기려면 크기를 재는 도구, 곧 노름이 필요합니다. 벡터 노름 ∥x∥과 그에 맞는 행렬 노름 ∥A∥=maxx=0∥Ax∥/∥x∥(12장에서 자세히)을 쓰면 다음이 성립합니다.
정의 2.11 (행렬 조건수) 가역 행렬 A의 행렬 조건수(matrix condition number)는 κ(A)=∥A∥∥A−1∥이다. 2-노름이면 κ2(A)=σmax/σmin(최대·최소 특이값의 비, LinearBook SVD)이고, 언제나 κ(A)≥1이다.
정리 2.12 (선형계의 민감도)Ax=b, A(x+δx)=b+δb이면
∥x∥∥δx∥≤κ(A)∥b∥∥δb∥.
증명.δx=A−1δb이므로 ∥δx∥≤∥A−1∥∥δb∥. 또 ∥b∥=∥Ax∥≤∥A∥∥x∥에서 1/∥x∥≤∥A∥/∥b∥. 두 부등식을 곱한다. ∎ A가 δA만큼 흔들릴 때도 1차까지 같은 κ(A)가 증폭 인자다.
위 문제에서 ∥δb∥2/∥b∥2=10−4/2.83=3.5×10−5, ∥δx∥2/∥x∥2=1이므로 증폭은 2.8×104배로, 상한 κ2=4.0×104 안에 있습니다. 조건이 나쁜 행렬의 대표는 힐베르트 행렬Hij=1/(i+j−1)입니다. 다항식 최소제곱 맞춤에서 자연스럽게 나오는 행렬입니다(7장). 아래 표는 Hx=H1을 부분 피벗팅 가우스 소거로 풀어 참해 1과 비교한 결과입니다(κ2는 H와 정확한 정수 행렬 H−1의 최대 고유값의 곱).
n
κ₂(Hₙ)
κ₂·u
해의 최대 오차
잔차 max|b − Hx̂|
4
1.55×10⁴
1.7×10⁻¹²
6.1×10⁻¹³
1.1×10⁻¹⁶
6
1.50×10⁷
1.7×10⁻⁹
5.3×10⁻¹⁰
0
8
1.53×10¹⁰
1.7×10⁻⁶
4.2×10⁻⁷
4.4×10⁻¹⁶
10
1.60×10¹³
1.8×10⁻³
3.2×10⁻⁴
2.2×10⁻¹⁶
12
1.71×10¹⁶
1.9
0.36
8.9×10⁻¹⁶
이 표는 이 장 전체의 요약입니다. 잔차는 n과 상관없이 10−16 수준입니다. 부분 피벗팅 가우스 소거가 (실제로는) 후방 안정하다는 뜻입니다. 해의 오차는 κ2u를 거의 그대로 따라갑니다(정리 2.9). n=12이면 배정밀도로 한 자리도 믿을 수 없는데, 알고리즘 탓이 아니라 문제 탓입니다. 그래서 잔차가 작다고 해가 정확한 것은 아닙니다. 반복 해법의 멈춤 조건(13장), 반데르몽드 행렬과 보간(5장), 정규 방정식의 조건수 제곱 문제(7장)가 모두 이 사실에서 출발합니다. 노름의 정의, 오차 한계의 증명, 반복 개선은 12장에서 다룹니다.
반올림 오차 모형과 혼합 정밀도
지금까지 "알고리즘의 후방 오차가 u 정도"라고 말했습니다. 이것을 실제로 증명하는 도구가 1장의 표준 반올림 오차 모형입니다. 부동소수점 수 x,y와 ∘∈{+,−,×,÷}에 대해
fl(x∘y)=(x∘y)(1+δ),∣δ∣≤u.
긴 계산에서는 이런 (1+δi)가 여러 개 곱해진다. 이들을 한 덩어리로 묶는 보조정리가 오차 분석의 기본 계산 규칙이다.
정리 2.13 (반올림 인자의 곱)∣δi∣≤u, ρi=±1이고 nu<1이면
i=1∏n(1+δi)ρi=1+θn,∣θn∣≤γn:=1−nunu.
증명의 핵심.n에 대한 귀납법. ρ=1이면 (1+θn−1)(1+δ)−1의 크기가 γn−1+u+γn−1u≤γn이고, ρ=−1이면 1/(1+δ)=1−δ/(1+δ)로 바꿔 같은 계산을 한다. ∎ nu≪1이면 γn≈nu다.
증명의 핵심. 곱셈마다 (1+εi), 덧셈마다 (1+δk)를 붙여 펼치면 xiyi는 곱셈 1번과 덧셈 최대 n−1번의 반올림을 겪는다. 정리 2.13을 쓴다. ∎ 첫째 식은 "x를 성분마다 상대적으로 γn 이하만큼 바꾼 정확한 내적"이라는 뜻이므로 내적은 후방 안정하다. 둘째 식의 분수는 내적 문제의 조건수이고, 부호가 섞여 ∣s∣≪∑∣xiyi∣이면 커진다.
정리 2.15 (호너 방법의 후방 안정성) 차수 n인 p(x)=∑akxk를 호너 방법 bn=an, bk=bk+1x+ak로 계산하면 p^=∑kak(1+θk)xk, ∣θk∣≤γ2n이다. 따라서 ∣p^−p∣/∣p∣≤γ2n∑∣ak∣∣x∣k/∣p(x)∣이다(예제 2.3, 4장 호너 방법).
이 결과들은 정밀도를 바꿔 쓸 때 진가를 발휘합니다. 그래픽 처리 장치와 기계 학습 가속기는 16비트 형식을 즐겨 씁니다. 반정밀도(binary16)의 u=2−11≈4.9×10−4, bfloat16의 u=2−8≈3.9×10−3입니다(1장 표). 정리 2.14의 상한 γn은 반정밀도에서 n=1000이면 0.95, n≥2048이면 아예 무의미합니다. 실제로도 그렇습니다. 덧셈 결과가 2048을 넘으면 반정밀도의 간격이 2라 1보다 작은 항은 더해지지 않습니다.
혼합 정밀도(mixed precision)는 이 상황의 표준 처방입니다. 데이터는 낮은 정밀도로 저장하고(메모리와 대역폭이 절반 이하), 누적만 높은 정밀도로 합니다. 16비트 두 수의 곱은 가수가 22비트 이하라 단정밀도에 정확히 담기므로, 곱은 정확하고 덧셈만 단정밀도 u=6×10−8으로 반올림됩니다. 오차 상한의 u가 누산기의 u로 바뀌는 것입니다. 행렬 곱 전용 하드웨어(텐서 코어 등)가 "16비트 입력, 32비트 누적"으로 설계된 이유입니다.
예제 2.5 (16비트 내적)[0,1)의 난수 벡터 두 개를 해당 형식으로 반올림해 두고 내적을 구한다. 오차는 반올림된 입력들의 정확한 내적에 대한 상대 오차(곧 누적 과정의 오차만)다.
입력 / 누산기
n = 100
n = 1000
n = 10000
n = 10000에서의 결과
binary16 / binary16
2.6×10⁻³
7.8×10⁻³
0.25
1868 (참값 2497)
binary16 / binary32
1.5×10⁻⁷
8.5×10⁻⁷
2.6×10⁻⁶
2496.96
bfloat16 / bfloat16
8.3×10⁻³
0.18
0.90
256 (합이 멈춤)
bfloat16 / binary32
3.1×10⁻⁸
4.2×10⁻⁷
2.5×10⁻⁷
2497.02
binary32 / binary64
4.0×10⁻¹⁶
1.1×10⁻¹⁵
5.5×10⁻¹⁶
2496.98
bfloat16 누적은 합이 256에 이르자 멈췄습니다. 256 근처에서 bfloat16의 간격은 2이고, 1보다 작은 항은 반 간격보다 작아 반올림으로 사라집니다. 1장의 조화급수가 멈춘 것과 같은 현상입니다. 누산기를 32비트로 바꾸면 같은 입력으로 오차가 백만 배 줄어듭니다. 이 생각을 선형계로 넓힌 것이 혼합 정밀도 반복 개선입니다. 낮은 정밀도로 LU 분해를 하고, 잔차 r=b−Ax^만 높은 정밀도로 계산해 보정 Aδx=r을 되풀이하면, κ(A)와 낮은 정밀도의 u의 곱이 1보다 충분히 작은 한 높은 정밀도 수준의 해를 얻습니다(12장).
해볼 것: ① binary16 입력에서 빨간 선(16비트 누적)이 n ≈ 수천에서 꺾여 오차가 급격히 커집니다. 합이 2048을 넘은 순간입니다. ② 파란 선(32비트 누적)은 같은 입력으로 10⁻⁶ 아래에 머뭅니다. 입력 정밀도가 아니라 누적 정밀도가 오차를 정합니다. ③ '부호 섞임'으로 바꾸면 내적의 조건수가 커져 모든 선이 올라갑니다. 문제 탓인 부분입니다. 모델: 곱 xᵢyᵢ를 누산기 형식으로 반올림한 뒤 같은 형식으로 더함(가장 가까운 수로, 동률이면 짝수). 참값은 반올림된 입력들의 배정밀도 보정 합.
이 도구가 쓰이는 곳
"문제의 조건수 × 알고리즘의 후방 오차"라는 틀은 이 책의 모든 장에서 오차를 읽는 기본 문법입니다.
후방 오차는 "y^를 정확한 답으로 갖는 입력이 얼마나 먼가". 후방 오차가 O(u)인 알고리즘은 후방 안정이며, 전방 오차 ≲κ× 후방 오차이므로 κu 정도의 오차를 낸다. 그것이 최선이다.
조건이 좋은 문제를 불안정하게 푸는 알고리즘은 조건이 나쁜 중간 단계를 거친다. 앞으로 가는 점화식 In=1−nIn−1은 오차를 n!배로, x<0인 ex 급수는 e2∣x∣배로 키운다. 뒤로 가는 점화식, 1/e∣x∣는 안정하다.
다시 쓰기(log1p, expm1, 카한 공식, 비에트 공식, 유리화, 항등식)는 알고리즘의 불안정을 고친다. 문제의 조건이 나쁘면 표현(변수, 기저)을 바꿔야 한다.
행렬 조건수 κ(A)=∥A∥∥A−1∥는 선형계의 증폭 인자다. 힐베르트 행렬처럼 잔차가 10−16이어도 해의 오차는 κu까지 커질 수 있다.
표준 모형 fl(x∘y)=(x∘y)(1+δ)와 γn=nu/(1−nu)로 내적·호너의 후방 안정성을 증명한다. 저정밀도 데이터는 높은 정밀도로 누적한다(혼합 정밀도).
확인 퀴즈
Q1. x = 1.0001에서 ln x의 상대 조건수는 대략?
κ = |x · (1/x) / ln x| = 1/|ln x| = 1/ln(1.0001) ≈ 10000.5. 입력의 상대 오차가 만 배로 커진다. 출력 ln x가 0에 가까운 곳이라 조건이 나쁘다.
Q2. Math.log(1 + x)로 x = 10⁻¹⁰의 ln(1 + x)를 계산하면 상대 오차가 약 10⁻⁷이다. 이 오차의 원인은?
문제 x ↦ ln(1 + x)의 조건수는 x/((1 + x)ln(1 + x)) ≈ 1이다. 하지만 중간 단계 w = fl(1 + x)에서 상대 u의 오차가 생기고, 다음 단계 ln w의 조건수가 1/|ln w| ≈ 10¹⁰이라 오차가 10⁻⁶ 수준까지 커질 수 있다. log1p(x)를 쓰면 해결된다.
Q3. 후방 안정한 알고리즘에 대한 설명으로 옳은 것은?
정의 2.8. 전방 오차는 κ × 후방 오차 ≈ κu이므로 조건이 나쁜 문제에서는 클 수 있다(예: 힐베르트 행렬). 그래도 입력을 저장하는 오차만으로 생기는 수준이라 그 이상은 기대할 수 없다.
Q4. 조건수 10¹⁰인 선형계를 후방 안정한 알고리즘으로 배정밀도에서 풀었다. 해는 대략 몇 자리가 맞을까?
상대 오차 ≈ κu = 10¹⁰ × 1.1×10⁻¹⁶ ≈ 10⁻⁶. 16자리 중 log₁₀κ = 10자리를 잃어 약 6자리가 남는다. 힐베르트 행렬 n = 8(κ ≈ 1.5×10¹⁰)의 오차 4.2×10⁻⁷과 맞는다.
Q5. Iₙ = 1 − n·Iₙ₋₁을 I₀에서 앞으로 계산할 때 I₀의 오차 e₀는 I₂₀에서 대략 몇 배가 되는가?
eₙ = −n·eₙ₋₁이므로 |eₙ| = n!|e₀|. 뒤로 가는 점화식 Iₙ₋₁ = (1 − Iₙ)/n에서는 반대로 단계마다 n으로 나뉘어 안정하다.
Q6. 배정밀도에서 e⁻³⁰을 정확히 계산하는 방법은?
eˣ의 조건수는 |x| = 30으로 작다. 교대 급수는 최대 항 7.8×10¹¹이 상쇄되어 9.4×10⁻¹⁴을 남겨야 하므로 오차가 u × 7.8×10¹¹ ≈ 10⁻⁴로 답보다 훨씬 크다. 양항 급수의 역수는 상쇄가 없다.
Q7. 다항식의 단순근 r이 계수 교란에 예민해지는 주된 이유는?
정리 2.5: κ_r = Σ|aₖ||r|ᵏ / (|r||p′(r)|). 윌킨슨 다항식의 근은 간격이 1인데도 r = 16에서 분자 ~10²³이 분모 ~10¹³보다 압도적으로 커서 κ가 10¹⁰을 넘는다.