計算機は無限に長い小数を持てないので、実数を有限の桁で丸めて記憶し、計算のたびにまた丸めます。この記事は、その丸めが何度も重なると答えがどれだけずれるのかを、不等式で見積もる方法を学びます。読み終えると、足し算や多項式の計算で誤差がどの程度になるかを式で説明でき、0.1 + 0.2 が 0.3 にならない理由も数字で追えるようになります。
計算機の実数は IEEE 754 の浮動小数点数 (有限桁の 2 進数で実数を近似して表す方式)です。binary64(倍精度)は符号 1 ビット・指数 11 ビット・仮数 52 ビットで、精度 p = 53 p=53 p = 53 桁の 2 進数を表します。
四則と平方根は正しく丸められる (厳密な結果を最も近い浮動小数点数に丸めたものが返る)と規格が定めています。ここから、オーバーフローとアンダーフローがなければ f l ( x ∘ y ) = ( x ∘ y ) ( 1 + δ ) \mathrm{fl}(x\circ y)=(x\circ y)(1+\delta) fl ( x ∘ y ) = ( x ∘ y ) ( 1 + δ ) , ∣ δ ∣ ≤ u = 2 − p |\delta|\le u=2^{-p} ∣ δ ∣ ≤ u = 2 − p という標準モデル が従います。
Sterbenz の補題 : y / 2 ≤ x ≤ 2 y y/2\le x\le 2y y /2 ≤ x ≤ 2 y なら x − y x-y x − y は誤差なく計算されます。桁落ちで失われる精度は、引き算そのものではなく、引く前の値に含まれていた誤差から来ます。
n n n 個の逐次和の誤差は γ n − 1 ∑ ∣ x i ∣ \gamma_{n-1}\sum|x_i| γ n − 1 ∑ ∣ x i ∣ (γ k = k u / ( 1 − k u ) \gamma_k=ku/(1-ku) γ k = k u / ( 1 − k u ) )以下、隣どうしを足していく対ごとの和 は γ ⌈ log 2 n ⌉ ∑ ∣ x i ∣ \gamma_{\lceil\log_2n\rceil}\sum|x_i| γ ⌈ l o g 2 n ⌉ ∑ ∣ x i ∣ 以下です。
Horner 法 で計算した多項式の値は、各係数を相対 γ 2 n \gamma_{2n} γ 2 n 以内で動かした多項式の正確な値です(後退誤差)。この「計算結果は少し違う入力に対する正確な答え」という見方が、数値解析と数値線形代数の誤差解析の出発点になります。
この記事で使う事前知識
仮数と指数 : 数を「仮数 × 2 の指数乗」の形で書くときの、仮数(有効数字にあたる部分)と指数のこと。→ 定義 2.1
オーバーフローとアンダーフロー : 結果が表せる最大の値を超えること、または 0 でないのに表せる最小の正規化数より小さくなること。→ 定義 2.1[浮動小数と区間演算]
相対誤差 : 誤差の大きさを、真の値の大きさで割ったもの。桁数の感覚に対応します。
Horner 法 : 多項式 a n x n + ⋯ + a 0 a_nx^n+\cdots+a_0 a n x n + ⋯ + a 0 を ( ⋯ ( a n x + a n − 1 ) x + ⋯ ) x + a 0 (\cdots(a_nx+a_{n-1})x+\cdots)x+a_0 ( ⋯ ( a n x + a n − 1 ) x + ⋯ ) x + a 0 の順に、掛け算と足し算だけで計算する方法(第 6 節で定義します)。
条件数 : 入力が少し変わったとき、答えがどれだけ大きく変わりうるかを表す量(問題の側の性質)。→ 条件数 (相対条件数)
Python で 0.1 + 0.2 == 0.3 を評価すると False になります。数値計算を始めた人がまず出会う現象ですが、これは計算機の「誤り」ではありません。十進の 0.1 0.1 0.1 は 2 進では有限桁で書けないので、読み込んだ時点で最も近い 2 進数に置き換わり、足し算の結果もまた最も近い 2 進数に置き換わります。どの段階でどれだけずれるかは、規格によって正確に 決まっています。
数値解析の仕事は、この「置き換え」が積み重なったときに答えがどれだけずれるかを、定理として評価することです。ずれには 2 種類あります。
種類 原因 例 丸め誤差 実数を有限桁の浮動小数点数で表すこと 和・内積・多項式の値の誤差 打ち切り誤差 無限の操作(極限・級数・積分)を有限で止めること 差分商、数値積分、反復の停止
この記事は前者を扱います。丸めの基本的な誤差モデルと誤差因子の積の補題は、計算機援用証明のテーマの浮動小数と区間演算 の章で証明されているので、ここではその主張を引用して使い、IEEE 754 の形式と、和・桁落ち・多項式の誤差解析を積み上げます。
精度 p p p と指数の範囲 e min < e max e_{\min}\lt e_{\max} e m i n < e m a x を固定した浮動小数点数の集合 F \mathbb{F} F は、既存の定義(定義 2.1[浮動小数と区間演算] )を使います。要点を再掲します。
正規化数 は ± M ⋅ 2 e − p + 1 \pm M\cdot2^{e-p+1} ± M ⋅ 2 e − p + 1 (M M M は整数で 2 p − 1 ≤ M < 2 p 2^{p-1}\le M\lt2^p 2 p − 1 ≤ M < 2 p 、e min ≤ e ≤ e max e_{\min}\le e\le e_{\max} e m i n ≤ e ≤ e m a x )、非正規化数 は ± M ⋅ 2 e min − p + 1 \pm M\cdot2^{e_{\min}-p+1} ± M ⋅ 2 e m i n − p + 1 (0 < M < 2 p − 1 0\lt M\lt2^{p-1} 0 < M < 2 p − 1 )で、これらと 0 0 0 を合わせたものが F \mathbb{F} F です。
最小の正規化数は x min = 2 e min x_{\min}=2^{e_{\min}} x m i n = 2 e m i n 、最大の数は x max = ( 2 − 2 1 − p ) 2 e max x_{\max}=(2-2^{1-p})2^{e_{\max}} x m a x = ( 2 − 2 1 − p ) 2 e m a x 、単位丸め は u = 2 − p u=2^{-p} u = 2 − p です。
[ 2 e , 2 e + 1 ] [2^e,2^{e+1}] [ 2 e , 2 e + 1 ] の中の浮動小数点数は間隔 2 u ⋅ 2 e 2u\cdot2^e 2 u ⋅ 2 e で等間隔に並びます(補題 2.2[浮動小数と区間演算] )。間隔は 2 2 2 の冪をまたぐたびに 2 倍になり、相対的な間隔は u u u から 2 u 2u 2 u の間にあります。
1/2 1 2 間隔 2⁻⁴ 間隔 2⁻³ 間隔 2⁻²
1 の近くの浮動小数点数(p = 4 の場合)。[1/2, 1) では間隔 2⁻⁴、[1, 2) では 2⁻³、[2, 4) では 2⁻²。間隔は 2 の冪をまたぐたびに 2 倍になる。
IEEE 754 は、この集合を固定長のビット列で表す方法を定めています。次の定義は記号が多いですが、考え方は「符号 1 ビット、指数 E E E 、仮数の小数部 f f f の 3 つの整数から、± 2 ( 指数 ) × 1. ( 小数部 ) \pm2^{(\text{指数})}\times1.(\text{小数部}) ± 2 ( 指数 ) × 1. ( 小数部 ) の形の数を作る」というだけです。たとえば binary64 では、E = 1023 E=1023 E = 1023 , f = 0 f=0 f = 0 が 1 1 1 、E = 1024 E=1024 E = 1024 , f = 0 f=0 f = 0 が 2 2 2 、E = 1023 E=1023 E = 1023 , f = 2 51 f=2^{51} f = 2 51 が 1 + 2 51 ⋅ 2 − 52 = 1.5 1+2^{51}\cdot2^{-52}=1.5 1 + 2 51 ⋅ 2 − 52 = 1.5 を表します。
s E f 1 ビット 11 ビット 52 ビット 符号 指数部 仮数部
binary64 のビット配置。符号 1 ビット、指数部 E が 11 ビット、仮数部 f が 52 ビット。
定義 2.1 (IEEE 754 の 2 進交換形式 ) ↗
正の整数 w w w (指数部の幅)と t t t (仮数部の幅)を固定し、b i a s = 2 w − 1 − 1 \mathrm{bias}=2^{w-1}-1 bias = 2 w − 1 − 1 とする。1 + w + t 1+w+t 1 + w + t ビットの列を、符号ビット s ∈ { 0 , 1 } s\in\{0,1\} s ∈ { 0 , 1 } 、指数部 E ∈ { 0 , 1 , … , 2 w − 1 } E\in\{0,1,\ldots,2^w-1\} E ∈ { 0 , 1 , … , 2 w − 1 } (w w w ビットの符号なし整数)、仮数部 f ∈ { 0 , 1 , … , 2 t − 1 } f\in\{0,1,\ldots,2^t-1\} f ∈ { 0 , 1 , … , 2 t − 1 } (t t t ビットの符号なし整数)に分け、次の値を表すものとする。
1 ≤ E ≤ 2 w − 2 1\le E\le2^w-2 1 ≤ E ≤ 2 w − 2 のとき 正規化数 ( − 1 ) s 2 E − b i a s ( 1 + f 2 − t ) (-1)^s\,2^{E-\mathrm{bias}}\,(1+f\,2^{-t}) ( − 1 ) s 2 E − bias ( 1 + f 2 − t ) 。
E = 0 E=0 E = 0 , f ≠ 0 f\ne0 f = 0 のとき 非正規化数 ( − 1 ) s 2 1 − b i a s ( f 2 − t ) (-1)^s\,2^{1-\mathrm{bias}}\,(f\,2^{-t}) ( − 1 ) s 2 1 − bias ( f 2 − t ) 。E = 0 E=0 E = 0 , f = 0 f=0 f = 0 のとき ( − 1 ) s 0 (-1)^s\,0 ( − 1 ) s 0 (+ 0 +0 + 0 と − 0 -0 − 0 )。
E = 2 w − 1 E=2^w-1 E = 2 w − 1 , f = 0 f=0 f = 0 のとき ( − 1 ) s ∞ (-1)^s\infty ( − 1 ) s ∞ 。E = 2 w − 1 E=2^w-1 E = 2 w − 1 , f ≠ 0 f\ne0 f = 0 のとき NaN (数でない値)。
binary32 は ( w , t ) = ( 8 , 23 ) (w,t)=(8,23) ( w , t ) = ( 8 , 23 ) 、binary64 は ( w , t ) = ( 11 , 52 ) (w,t)=(11,52) ( w , t ) = ( 11 , 52 ) である。
1 と 2 の値の全体は、p = t + 1 p=t+1 p = t + 1 , e min = 1 − b i a s e_{\min}=1-\mathrm{bias} e m i n = 1 − bias , e max = b i a s e_{\max}=\mathrm{bias} e m a x = bias とした F \mathbb{F} F に一致します。実際、1 の値は M = 2 t + f M=2^t+f M = 2 t + f (2 p − 1 ≤ M < 2 p 2^{p-1}\le M\lt2^p 2 p − 1 ≤ M < 2 p )、e = E − b i a s e=E-\mathrm{bias} e = E − bias として M ⋅ 2 e − p + 1 M\cdot2^{e-p+1} M ⋅ 2 e − p + 1 と書け、2 の値は M = f M=f M = f (0 < M < 2 p − 1 0\lt M\lt2^{p-1} 0 < M < 2 p − 1 )として M ⋅ 2 e min − p + 1 M\cdot2^{e_{\min}-p+1} M ⋅ 2 e m i n − p + 1 と書けます。正規化数では先頭の 1 を格納しない(隠れビット )ので、t t t ビットの仮数部で p = t + 1 p=t+1 p = t + 1 桁の精度が得られます。
形式 全体 w w w t t t p p p bias e min e_{\min} e m i n e max e_{\max} e m a x u = 2 − p u=2^{-p} u = 2 − p binary32(単精度) 32 8 23 24 127 − 126 -126 − 126 127 ≈ 5.96 × 10 − 8 \approx5.96\times10^{-8} ≈ 5.96 × 1 0 − 8 binary64(倍精度) 64 11 52 53 1023 − 1022 -1022 − 1022 1023 ≈ 1.11 × 10 − 16 \approx1.11\times10^{-16} ≈ 1.11 × 1 0 − 16
非正規化数があるおかげで、0 0 0 と x min x_{\min} x m i n の間も等間隔 2 e min − p + 1 2^{e_{\min}-p+1} 2 e m i n − p + 1 で埋まります。x ≠ y x\ne y x = y の浮動小数点数について x − y x-y x − y が 0 0 0 に丸められることはありません(漸進アンダーフロー )。非正規化数がなければ、x min x_{\min} x m i n と 1.5 x min 1.5\,x_{\min} 1.5 x m i n の差は表せず 0 0 0 になり、if x != y: z = 1/(x - y) のような計算が 0 除算を起こします。
± 0 \pm0 ± 0 は比較では等しく、1 / ( + 0 ) = + ∞ 1/(+0)=+\infty 1/ ( + 0 ) = + ∞ , 1 / ( − 0 ) = − ∞ 1/(-0)=-\infty 1/ ( − 0 ) = − ∞ のように符号が意味をもつ演算があります。NaN は 0 / 0 0/0 0/0 , ∞ − ∞ \infty-\infty ∞ − ∞ , − 1 \sqrt{-1} − 1 などの結果で、自分自身とも等しくない(x != x が真)ことで判定できます。
定義 2.2 (丸めの方向と正しい丸め ) ↗
∣ x ∣ ≤ x max |x|\le x_{\max} ∣ x ∣ ≤ x m a x の実数 x x x について、次の 4 つの丸めを考える。
最近接偶数丸め f l ( x ) \mathrm{fl}(x) fl ( x ) : x x x に最も近い F \mathbb{F} F の元。2 つあれば M M M が偶数の方(定義 2.3[浮動小数と区間演算] の f l \mathrm{fl} fl )。
下向き丸め ∇ ( x ) \nabla(x) ∇ ( x ) 、上向き丸め Δ ( x ) \Delta(x) Δ ( x ) (同じ定義の ∇ \nabla ∇ , Δ \Delta Δ )、0 方向への丸め (x ≥ 0 x\ge0 x ≥ 0 なら ∇ ( x ) \nabla(x) ∇ ( x ) 、x < 0 x\lt0 x < 0 なら Δ ( x ) \Delta(x) Δ ( x ) )。
演算 ∘ ∈ { + , − , × , ÷ } \circ\in\{+,-,\times,\div\} ∘ ∈ { + , − , × , ÷ } と x , y ∈ F x,y\in\mathbb{F} x , y ∈ F について、計算機が返す値が厳密な実数 x ∘ y x\circ y x ∘ y をいずれかの丸め(既定は最近接偶数丸め)で丸めたものであるとき、その演算は正しく丸められる という。平方根 x \sqrt{x} x (x ≥ 0 x\ge0 x ≥ 0 )と融合積和 x y + z xy+z x y + z についても同様に定める。
IEEE 754 は、四則・平方根・融合積和(fma)が正しく丸められることを要求 します。以下、計算機の演算の結果を f l ( x ∘ y ) \mathrm{fl}(x\circ y) fl ( x ∘ y ) と書きます。これは「厳密な x ∘ y x\circ y x ∘ y を計算してから丸めた値」という意味で、どのように計算するかには立ち入りません。一方、exp・sin などの初等関数については、規格は正しい丸めを推奨するにとどめているので、以下の評価をそのまま適用できません。
定義 2.3 (機械イプシロンと単位丸め ) ↗
1 1 1 と、1 1 1 より大きい最小の浮動小数点数との差 ε M = 2 1 − p \varepsilon_M=2^{1-p} ε M = 2 1 − p を機械イプシロン という。その半分 u = 2 − p u=2^{-p} u = 2 − p を単位丸め という。
ε M \varepsilon_M ε M は 1 1 1 の右側の間隔で、u u u は最近接丸めの相対誤差の上界です(定理 2.4[浮動小数と区間演算] )。1 1 1 の左側の間隔は u u u です([ 1 / 2 , 1 ) [1/2,1) [ 1/2 , 1 ) の間隔は 2 u ⋅ 2 − 1 2u\cdot2^{-1} 2 u ⋅ 2 − 1 )。困ったことに、文献ごとに同じ記号が違う量を指します。
文献・環境 2 1 − p 2^{1-p} 2 1 − p の呼び名2 − p 2^{-p} 2 − p の呼び名Higham machine epsilon ϵ M \epsilon_M ϵ M unit roundoff u u u Golub–Van Loan — unit roundoff u \mathbf{u} u Trefethen–Bau — ϵ machine \epsilon_{\text{machine}} ϵ machine C の DBL_EPSILON、NumPy の finfo.eps、MATLAB の eps eps —
論文やライブラリの誤差評価を読むときは、どちらの量かを確かめてください。この記事では u = 2 − p u=2^{-p} u = 2 − p を使います。
例 2.4 (NumPy で単位丸めと間隔を確かめる )
np.finfo と np.nextafter で、binary32 と binary64 の精度・指数の範囲・1 の両側の間隔・最小の正規化数と非正規化数・最大値を出します。
# Python 3.12.10 / NumPy 2.5.2(x86-64)
for t in (np.float32, np.float64):
up = np. nextafter ( one , t ( 2 )) - one # 1 の右の間隔
dn = one - np. nextafter ( one , t ( 0 )) # 1 の左の間隔
print ( fi.dtype , fi.nmant + 1 , fi.minexp , fi.maxexp - 1 )
print ( f " eps= {fi.eps :.3e } up= {up :.3e } dn= {dn :.3e } " )
print ( f " tiny= {fi.tiny :.3e } sub= {fi.smallest_subnormal :.3e } "
eps=1.192e-07 up=1.192e-07 dn=5.960e-08
tiny=1.175e-38 sub=1.401e-45 max=3.403e+38
eps=2.220e-16 up=2.220e-16 dn=1.110e-16
tiny=2.225e-308 sub=4.941e-324 max=1.798e+308
検算. (a) 既知値: p = 24 , 53 p=24,53 p = 24 , 53 、e min = − 126 , − 1022 e_{\min}=-126,-1022 e m i n = − 126 , − 1022 、e max = 127 , 1023 e_{\max}=127,1023 e m a x = 127 , 1023 は表と一致し、eps = 2 − 23 ≈ 1.192 × 10 − 7 =2^{-23}\approx1.192\times10^{-7} = 2 − 23 ≈ 1.192 × 1 0 − 7 , 2 − 52 ≈ 2.220 × 10 − 16 2^{-52}\approx2.220\times10^{-16} 2 − 52 ≈ 2.220 × 1 0 − 16 、tiny = 2 − 126 =2^{-126} = 2 − 126 , 2 − 1022 2^{-1022} 2 − 1022 、sub = 2 − 149 =2^{-149} = 2 − 149 , 2 − 1074 2^{-1074} 2 − 1074 です。(b) 別の求め方: nextafter で測った右の間隔 up は finfo.eps と一致し、左の間隔 dn はその半分の u u u です。(c) 次数: 左右の間隔の比が 2 であることは、間隔が 2 2 2 の冪をまたぐと 2 倍になること(補題 2.2[浮動小数と区間演算] )のとおりです。
正しい丸めの規約と、丸めの誤差モデル(定理 2.4[浮動小数と区間演算] )を組み合わせると、すべての誤差解析の出発点になる次の形が得られます。
系 3.1 (四則の標準モデル ) ✓
x , y ∈ F x,y\in\mathbb{F} x , y ∈ F 、∘ ∈ { + , − , × , ÷ } \circ\in\{+,-,\times,\div\} ∘ ∈ { + , − , × , ÷ } (÷ \div ÷ では y ≠ 0 y\ne0 y = 0 )とし、厳密な値 z = x ∘ y z=x\circ y z = x ∘ y が z = 0 z=0 z = 0 または x min ≤ ∣ z ∣ ≤ x max x_{\min}\le|z|\le x_{\max} x m i n ≤ ∣ z ∣ ≤ x m a x を満たす(オーバーフローもアンダーフローも起きない)とする。演算が最近接偶数丸めで正しく丸められるとき、
f l ( x ∘ y ) = ( x ∘ y ) ( 1 + δ ) , f l ( x ∘ y ) = x ∘ y 1 + δ ′ , ∣ δ ∣ , ∣ δ ′ ∣ ≤ u \mathrm{fl}(x\circ y)=(x\circ y)(1+\delta),\qquad\mathrm{fl}(x\circ y)=\frac{x\circ y}{1+\delta'},\qquad|\delta|,|\delta'|\le u fl ( x ∘ y ) = ( x ∘ y ) ( 1 + δ ) , fl ( x ∘ y ) = 1 + δ ′ x ∘ y , ∣ δ ∣ , ∣ δ ′ ∣ ≤ u を満たす δ , δ ′ \delta,\delta' δ , δ ′ がある。x ∘ y ∈ F x\circ y\in\mathbb{F} x ∘ y ∈ F ならば δ = δ ′ = 0 \delta=\delta'=0 δ = δ ′ = 0 にとれる。x ≥ 0 x\ge0 x ≥ 0 の平方根 f l ( x ) \mathrm{fl}(\sqrt{x}) fl ( x ) についても同じことが成り立つ。
証明(系 3.1) 正しい丸めの規約(定義 2.2 )により、計算結果は f l ( z ) \mathrm{fl}(z) fl ( z ) です。z ∈ F z\in\mathbb{F} z ∈ F (z = 0 z=0 z = 0 を含む)なら丸めの定義から f l ( z ) = z \mathrm{fl}(z)=z fl ( z ) = z で、δ = δ ′ = 0 \delta=\delta'=0 δ = δ ′ = 0 とします。そうでなければ x min ≤ ∣ z ∣ ≤ x max x_{\min}\le|z|\le x_{\max} x m i n ≤ ∣ z ∣ ≤ x m a x なので、丸めの誤差モデル(定理 2.4[浮動小数と区間演算] の 1)により、f l ( z ) = z ( 1 + δ ) \mathrm{fl}(z)=z(1+\delta) fl ( z ) = z ( 1 + δ ) , ∣ δ ∣ ≤ u |\delta|\le u ∣ δ ∣ ≤ u であり、さらに ∣ f l ( z ) − z ∣ ≤ u ∣ f l ( z ) ∣ |\mathrm{fl}(z)-z|\le u\,|\mathrm{fl}(z)| ∣ fl ( z ) − z ∣ ≤ u ∣ fl ( z ) ∣ です。後者から f l ( z ) ≠ 0 \mathrm{fl}(z)\ne0 fl ( z ) = 0 (f l ( z ) = 0 \mathrm{fl}(z)=0 fl ( z ) = 0 なら z = 0 z=0 z = 0 となり仮定に反する)なので、δ ′ = ( z − f l ( z ) ) / f l ( z ) \delta'=(z-\mathrm{fl}(z))/\mathrm{fl}(z) δ ′ = ( z − fl ( z )) / fl ( z ) とおくと ∣ δ ′ ∣ ≤ u |\delta'|\le u ∣ δ ′ ∣ ≤ u かつ z = f l ( z ) ( 1 + δ ′ ) z=\mathrm{fl}(z)(1+\delta') z = fl ( z ) ( 1 + δ ′ ) 、すなわち f l ( z ) = z / ( 1 + δ ′ ) \mathrm{fl}(z)=z/(1+\delta') fl ( z ) = z / ( 1 + δ ′ ) です。平方根も z = x z=\sqrt{x} z = x として同じです。
∎
2 つ目の形 z / ( 1 + δ ′ ) z/(1+\delta') z / ( 1 + δ ′ ) は、誤差因子を分母に置きたいとき(割り算や、計算値の側から評価したいとき)に便利です。以下、この 2 つの形を単に「標準モデル」と呼び、途中でオーバーフローとアンダーフローが起きないことを常に仮定します。
丸めが何回も重なったときは、誤差因子をまとめる記号 γ n = n u / ( 1 − n u ) \gamma_n=nu/(1-nu) γ n = n u / ( 1 − n u ) (n u < 1 nu\lt1 n u < 1 。定義 3.1[浮動小数と区間演算] )と、誤差因子の積の補題を使います。
誤差因子の積の補題 (補題 3.2[浮動小数と区間演算] ): ∣ δ i ∣ ≤ u |\delta_i|\le u ∣ δ i ∣ ≤ u , ρ i = ± 1 \rho_i=\pm1 ρ i = ± 1 , n u < 1 nu\lt1 n u < 1 なら ∏ i = 1 n ( 1 + δ i ) ρ i = 1 + θ n \prod_{i=1}^n(1+\delta_i)^{\rho_i}=1+\theta_n ∏ i = 1 n ( 1 + δ i ) ρ i = 1 + θ n , ∣ θ n ∣ ≤ γ n |\theta_n|\le\gamma_n ∣ θ n ∣ ≤ γ n 。
言い換えると、相対誤差 u u u 以下の丸めが n n n 回重なっても、全体の相対誤差は γ n \gamma_n γ n (n u nu n u よりわずかに大きい程度)以下に収まる、ということです。以降の誤差解析は、数えた丸めの回数 n n n を γ n \gamma_n γ n に置き換える作業の繰り返しです。
この補題と組み合わせて使う γ n \gamma_n γ n の計算規則を、補題として証明しておきます。数値線形代数の後退誤差解析で繰り返し使います。
補題 3.2 (γₙ の計算規則 ) ✓
m , n ≥ 1 m,n\ge1 m , n ≥ 1 を整数とする。
m ≤ n m\le n m ≤ n , n u < 1 nu\lt1 n u < 1 なら γ m ≤ γ n \gamma_m\le\gamma_n γ m ≤ γ n 。また整数 k ≥ 1 k\ge1 k ≥ 1 について k n u < 1 knu\lt1 k n u < 1 なら k γ n ≤ γ k n k\gamma_n\le\gamma_{kn} k γ n ≤ γ k n 。
( m + n ) u < 1 (m+n)u\lt1 ( m + n ) u < 1 なら γ m + γ n + γ m γ n ≤ γ m + n \gamma_m+\gamma_n+\gamma_m\gamma_n\le\gamma_{m+n} γ m + γ n + γ m γ n ≤ γ m + n 。とくに γ m + γ n ≤ γ m + n \gamma_m+\gamma_n\le\gamma_{m+n} γ m + γ n ≤ γ m + n 。
( m + n ) u < 1 (m+n)u\lt1 ( m + n ) u < 1 とする。∣ θ m ∣ ≤ γ m |\theta_m|\le\gamma_m ∣ θ m ∣ ≤ γ m , ∣ θ n ∣ ≤ γ n |\theta_n|\le\gamma_n ∣ θ n ∣ ≤ γ n なら ( 1 + θ m ) ( 1 + θ n ) = 1 + θ (1+\theta_m)(1+\theta_n)=1+\theta ( 1 + θ m ) ( 1 + θ n ) = 1 + θ と書いたとき ∣ θ ∣ ≤ γ m + n |\theta|\le\gamma_{m+n} ∣ θ ∣ ≤ γ m + n 。
証明(補題 3.2)
γ k = 1 / ( 1 − k u ) − 1 \gamma_k=1/(1-ku)-1 γ k = 1/ ( 1 − k u ) − 1 は k k k について増加です。また k γ n = k n u / ( 1 − n u ) ≤ k n u / ( 1 − k n u ) = γ k n k\gamma_n=knu/(1-nu)\le knu/(1-knu)=\gamma_{kn} k γ n = k n u / ( 1 − n u ) ≤ k n u / ( 1 − k n u ) = γ k n です(分母 1 − n u ≥ 1 − k n u > 0 1-nu\ge1-knu\gt0 1 − n u ≥ 1 − k n u > 0 )。
1 + γ k = 1 / ( 1 − k u ) 1+\gamma_k=1/(1-ku) 1 + γ k = 1/ ( 1 − k u ) と、( 1 − m u ) ( 1 − n u ) = 1 − ( m + n ) u + m n u 2 ≥ 1 − ( m + n ) u > 0 (1-mu)(1-nu)=1-(m+n)u+mnu^2\ge1-(m+n)u\gt0 ( 1 − m u ) ( 1 − n u ) = 1 − ( m + n ) u + mn u 2 ≥ 1 − ( m + n ) u > 0 から
( 1 + γ m ) ( 1 + γ n ) = 1 ( 1 − m u ) ( 1 − n u ) ≤ 1 1 − ( m + n ) u = 1 + γ m + n (1+\gamma_m)(1+\gamma_n)=\frac{1}{(1-mu)(1-nu)}\le\frac{1}{1-(m+n)u}=1+\gamma_{m+n} ( 1 + γ m ) ( 1 + γ n ) = ( 1 − m u ) ( 1 − n u ) 1 ≤ 1 − ( m + n ) u 1 = 1 + γ m + n
で、両辺から 1 1 1 を引けば主張です。γ m γ n ≥ 0 \gamma_m\gamma_n\ge0 γ m γ n ≥ 0 なので後半も従います。
θ = θ m + θ n + θ m θ n \theta=\theta_m+\theta_n+\theta_m\theta_n θ = θ m + θ n + θ m θ n なので、2 から ∣ θ ∣ ≤ γ m + γ n + γ m γ n ≤ γ m + n |\theta|\le\gamma_m+\gamma_n+\gamma_m\gamma_n\le\gamma_{m+n} ∣ θ ∣ ≤ γ m + γ n + γ m γ n ≤ γ m + n です。
∎
例 3.3 (0.1 + 0.2 が 0.3 にならない理由 )
binary64 で f l ( 0.1 ) = M ⋅ 2 − 55 \mathrm{fl}(0.1)=M\cdot2^{-55} fl ( 0.1 ) = M ⋅ 2 − 55 , f l ( 0.2 ) = M ⋅ 2 − 54 \mathrm{fl}(0.2)=M\cdot2^{-54} fl ( 0.2 ) = M ⋅ 2 − 54 です(M = 3602879701896397 M=3602879701896397 M = 3602879701896397 。十進の 0.1 0.1 0.1 の 2 進展開 0.0 0011 ‾ 0.0\overline{0011} 0.0 0011 を 53 桁で丸めたもの)。厳密な和は 3 M ⋅ 2 − 55 = 10808639105689191 ⋅ 2 − 55 3M\cdot2^{-55}=10808639105689191\cdot2^{-55} 3 M ⋅ 2 − 55 = 10808639105689191 ⋅ 2 − 55 で、[ 1 / 4 , 1 / 2 ) [1/4,1/2) [ 1/4 , 1/2 ) の間隔 2 − 54 2^{-54} 2 − 54 で測ると 5404319552844595.5 5404319552844595.5 5404319552844595.5 目盛り、ちょうど 2 つの浮動小数点数の中点です。最近接偶数丸めは偶数の 5404319552844596 ⋅ 2 − 54 5404319552844596\cdot2^{-54} 5404319552844596 ⋅ 2 − 54 を選びます。一方、十進の 0.3 0.3 0.3 を丸めた f l ( 0.3 ) \mathrm{fl}(0.3) fl ( 0.3 ) は 5404319552844595 ⋅ 2 − 54 5404319552844595\cdot2^{-54} 5404319552844595 ⋅ 2 − 54 なので、両者は 1 目盛りずれます。有理数で計算すると f l ( 0.3 ) − 3 / 10 ≈ − 1.11 × 10 − 17 \mathrm{fl}(0.3)-3/10\approx-1.11\times10^{-17} fl ( 0.3 ) − 3/10 ≈ − 1.11 × 1 0 − 17 で、これは 1 回の丸めの範囲 u ⋅ 0.3 ≈ 3.3 × 10 − 17 u\cdot0.3\approx3.3\times10^{-17} u ⋅ 0.3 ≈ 3.3 × 1 0 − 17 に入ります。一方 f l ( 0.1 + 0.2 ) − 3 / 10 ≈ 4.44 × 10 − 17 \mathrm{fl}(0.1+0.2)-3/10\approx4.44\times10^{-17} fl ( 0.1 + 0.2 ) − 3/10 ≈ 4.44 × 1 0 − 17 はこの範囲を超えています。0.1 0.1 0.1 と 0.2 0.2 0.2 を読み込むときの 2 回の丸めの誤差(和は ≈ 1.67 × 10 − 17 \approx1.67\times10^{-17} ≈ 1.67 × 1 0 − 17 )が加わっているからです。足し算そのものの誤差は、厳密な和 3 M ⋅ 2 − 55 3M\cdot2^{-55} 3 M ⋅ 2 − 55 との差 2 − 55 ≈ 2.8 × 10 − 17 2^{-55}\approx2.8\times10^{-17} 2 − 55 ≈ 2.8 × 1 0 − 17 で、系 3.1 の範囲 u ∣ 3 M ⋅ 2 − 55 ∣ ≈ 3.3 × 10 − 17 u\,|3M\cdot2^{-55}|\approx3.3\times10^{-17} u ∣3 M ⋅ 2 − 55 ∣ ≈ 3.3 × 1 0 − 17 に入っています。
補題 4.1 (Sterbenz の補題 ) ✓
x , y ∈ F x,y\in\mathbb{F} x , y ∈ F が y / 2 ≤ x ≤ 2 y y/2\le x\le2y y /2 ≤ x ≤ 2 y を満たすならば x − y ∈ F x-y\in\mathbb{F} x − y ∈ F であり、したがって f l ( x − y ) = x − y \mathrm{fl}(x-y)=x-y fl ( x − y ) = x − y (引き算は誤差なく計算される)。
証明の方針は、x − y x-y x − y が y y y の最下位桁の位置を単位とする整数倍で、しかも絶対値が y y y 以下だから、p p p 桁に収まる、というものです。非正規化数の場合分けが入るために長く見えますが、中心の考えはこれだけです。
証明(補題 4.1) 仮定から x , y ≥ 0 x,y\ge0 x , y ≥ 0 です。x = 0 x=0 x = 0 なら y ≤ 2 x = 0 y\le2x=0 y ≤ 2 x = 0 で y = 0 y=0 y = 0 、x − y = 0 ∈ F x-y=0\in\mathbb{F} x − y = 0 ∈ F なので、x , y > 0 x,y\gt0 x , y > 0 とします。F \mathbb{F} F は符号について対称なので、x ≥ y x\ge y x ≥ y の場合に示せば十分です(x < y x\lt y x < y なら y − x ∈ F y-x\in\mathbb{F} y − x ∈ F を示して符号を変えます。仮定は x x x と y y y について対称です)。
正の浮動小数点数 z z z に対し、e z = max ( ⌊ log 2 z ⌋ , e min ) e_z=\max(\lfloor\log_2z\rfloor,e_{\min}) e z = max (⌊ log 2 z ⌋ , e m i n ) とおきます。定義 2.1[浮動小数と区間演算] から、z z z は z = M z ⋅ 2 e z − p + 1 z=M_z\cdot2^{e_z-p+1} z = M z ⋅ 2 e z − p + 1 (M z M_z M z は整数で 0 < M z < 2 p 0\lt M_z\lt2^p 0 < M z < 2 p )と書けます(正規化数なら e z e_z e z はその指数、非正規化数なら e z = e min e_z=e_{\min} e z = e m i n )。e z e_z e z は z z z について単調非減少なので、x ≥ y x\ge y x ≥ y から e x ≥ e y e_x\ge e_y e x ≥ e y です。よって x = M x 2 e x − e y ⋅ 2 e y − p + 1 x=M_x2^{e_x-e_y}\cdot2^{e_y-p+1} x = M x 2 e x − e y ⋅ 2 e y − p + 1 は 2 e y − p + 1 2^{e_y-p+1} 2 e y − p + 1 の整数倍で、
x − y = k ⋅ 2 e y − p + 1 ( k は整数 ) x-y=k\cdot2^{e_y-p+1}\qquad(k\ \text{は整数}) x − y = k ⋅ 2 e y − p + 1 ( k は整数 ) です。0 ≤ x − y ≤ 2 y − y = y 0\le x-y\le2y-y=y 0 ≤ x − y ≤ 2 y − y = y から 0 ≤ k ≤ M y < 2 p 0\le k\le M_y\lt2^p 0 ≤ k ≤ M y < 2 p です。
あとは、0 ≤ k < 2 p 0\le k\lt2^p 0 ≤ k < 2 p の整数 k k k と e min ≤ e ≤ e max e_{\min}\le e\le e_{\max} e m i n ≤ e ≤ e m a x について k ⋅ 2 e − p + 1 ∈ F k\cdot2^{e-p+1}\in\mathbb{F} k ⋅ 2 e − p + 1 ∈ F を示せば十分です。k = 0 k=0 k = 0 なら 0 ∈ F 0\in\mathbb{F} 0 ∈ F です。k ≥ 2 p − 1 k\ge2^{p-1} k ≥ 2 p − 1 なら指数 e e e の正規化数です。k < 2 p − 1 k\lt2^{p-1} k < 2 p − 1 のときは、k k k を 2 倍して e e e を 1 減らす操作を、k ≥ 2 p − 1 k\ge2^{p-1} k ≥ 2 p − 1 になるか e = e min e=e_{\min} e = e m i n になるまで繰り返します(値は変わりません)。前者で止まれば正規化数、後者で止まれば 0 < k < 2 p − 1 0\lt k\lt2^{p-1} 0 < k < 2 p − 1 で非正規化数です。
∎
この補題は「近い数どうしの引き算はそれ自体は 正確」と言っています。たとえば x ∈ [ 1 , 2 ] x\in[1,2] x ∈ [ 1 , 2 ] の浮動小数点数について f l ( x − 1 ) = x − 1 \mathrm{fl}(x-1)=x-1 fl ( x − 1 ) = x − 1 です。
それでも近い数の引き算が危険なのは、引く前の値がすでに誤差を含んでいるからです。
命題 4.2 (桁落ちの相対誤差 ) ✓
a , b a,b a , b を a ≠ b a\ne b a = b の実数とし、a ^ = a ( 1 + α ) \hat a=a(1+\alpha) a ^ = a ( 1 + α ) , b ^ = b ( 1 + β ) \hat b=b(1+\beta) b ^ = b ( 1 + β ) , ∣ α ∣ , ∣ β ∣ ≤ ε |\alpha|,|\beta|\le\varepsilon ∣ α ∣ , ∣ β ∣ ≤ ε とする。このとき
∣ ( a ^ − b ^ ) − ( a − b ) ∣ ∣ a − b ∣ ≤ ε ∣ a ∣ + ∣ b ∣ ∣ a − b ∣ \frac{|(\hat a-\hat b)-(a-b)|}{|a-b|}\le\varepsilon\,\frac{|a|+|b|}{|a-b|} ∣ a − b ∣ ∣ ( a ^ − b ^ ) − ( a − b ) ∣ ≤ ε ∣ a − b ∣ ∣ a ∣ + ∣ b ∣ であり、a , b > 0 a,b\gt0 a , b > 0 のとき等号は α = ε \alpha=\varepsilon α = ε , β = − ε \beta=-\varepsilon β = − ε でとられる。
証明(命題 4.2) ( a ^ − b ^ ) − ( a − b ) = a α − b β (\hat a-\hat b)-(a-b)=a\alpha-b\beta ( a ^ − b ^ ) − ( a − b ) = a α − b β なので、三角不等式から ∣ a α − b β ∣ ≤ ε ( ∣ a ∣ + ∣ b ∣ ) |a\alpha-b\beta|\le\varepsilon(|a|+|b|) ∣ a α − b β ∣ ≤ ε ( ∣ a ∣ + ∣ b ∣ ) です。a , b > 0 a,b\gt0 a , b > 0 , α = ε \alpha=\varepsilon α = ε , β = − ε \beta=-\varepsilon β = − ε なら a α − b β = ε ( a + b ) a\alpha-b\beta=\varepsilon(a+b) a α − b β = ε ( a + b ) で等号です。
∎
a ≈ b a\approx b a ≈ b なら倍率 ( ∣ a ∣ + ∣ b ∣ ) / ∣ a − b ∣ (|a|+|b|)/|a-b| ( ∣ a ∣ + ∣ b ∣ ) /∣ a − b ∣ は大きく、入力の小さな相対誤差 ε \varepsilon ε が大きな相対誤差に拡大されます。これを桁落ち (cancellation)といいます。補題 4.1 と合わせると、桁落ちの誤差は引き算の前に 入ったもので、引き算はそれを露わにするだけだとわかります。対策は、引き算の前に誤差の入らない式に書き換えることです。
例 4.3 ((1 + x) − 1 )
x ∈ F x\in\mathbb{F} x ∈ F , 0 < x < 1 0\lt x\lt1 0 < x < 1 とし、y = f l ( f l ( 1 + x ) − 1 ) y=\mathrm{fl}(\mathrm{fl}(1+x)-1) y = fl ( fl ( 1 + x ) − 1 ) を計算します。標準モデルから f l ( 1 + x ) = ( 1 + x ) ( 1 + δ ) \mathrm{fl}(1+x)=(1+x)(1+\delta) fl ( 1 + x ) = ( 1 + x ) ( 1 + δ ) , ∣ δ ∣ ≤ u |\delta|\le u ∣ δ ∣ ≤ u で、f l ( 1 + x ) ∈ [ 1 , 2 ] \mathrm{fl}(1+x)\in[1,2] fl ( 1 + x ) ∈ [ 1 , 2 ] なので 補題 4.1 により引き算は厳密です。したがって y = ( 1 + x ) ( 1 + δ ) − 1 = x + ( 1 + x ) δ y=(1+x)(1+\delta)-1=x+(1+x)\delta y = ( 1 + x ) ( 1 + δ ) − 1 = x + ( 1 + x ) δ で、相対誤差は
∣ y − x ∣ x = ( 1 + x ) ∣ δ ∣ x ≤ ( 1 + x ) u x \frac{|y-x|}{x}=\frac{(1+x)|\delta|}{x}\le\frac{(1+x)u}{x} x ∣ y − x ∣ = x ( 1 + x ) ∣ δ ∣ ≤ x ( 1 + x ) u です。x = 10 − 10 x=10^{-10} x = 1 0 − 10 なら u / x ≈ 10 − 6 u/x\approx10^{-6} u / x ≈ 1 0 − 6 で、16 桁のうち 10 桁が失われます。これは 命題 4.2 の倍率 ( ∣ 1 + x ∣ + 1 ) / x (|1+x|+1)/x ( ∣1 + x ∣ + 1 ) / x と同じ大きさです。
例 4.4 (1 − cos x の書き換え )
x x x が小さいとき 1 − cos x ≈ x 2 / 2 1-\cos x\approx x^2/2 1 − cos x ≈ x 2 /2 は 1 1 1 よりずっと小さく、cos x \cos x cos x の計算値に含まれる u u u 程度の誤差が、相対誤差 u / ( x 2 / 2 ) u/(x^2/2) u / ( x 2 /2 ) に拡大されます。1 − cos x = 2 sin 2 ( x / 2 ) 1-\cos x=2\sin^2(x/2) 1 − cos x = 2 sin 2 ( x /2 ) と書き換えると、引き算がなくなり、どの段も相対誤差 u u u 程度で済みます。( 1 − cos x ) / x 2 (1-\cos x)/x^2 ( 1 − cos x ) / x 2 を両方の式で計算し、mpmath の 50 桁の値と比べます。
# Python 3.12.10 / NumPy 2.5.2 / mpmath 1.3.0(x86-64)
exact = ( 1 - mp. cos ( mp. mpf ( x ))) / mp. mpf ( x ) ** 2 # x は binary64 の値
naive = ( 1 - np. cos ( x )) / x ** 2
stable = 2 * np. sin ( x / 2 ) ** 2 / x ** 2
e1 = abs ( naive - exact ) / exact
e2 = abs ( stable - exact ) / exact
print ( f "1e- {k} { float ( e1 ) :.2e } { float ( e2 ) :.2e } " )
検算. (a) 既知値: ( 1 − cos x ) / x 2 → 1 / 2 (1-\cos x)/x^2\to1/2 ( 1 − cos x ) / x 2 → 1/2 で、参照値は同じ binary64 の x x x に対する 50 桁の値です。(b) 別精度・別の式: 書き換えた式の誤差は全行で u ≈ 1.1 × 10 − 16 u\approx1.1\times10^{-16} u ≈ 1.1 × 1 0 − 16 程度で、参照値と 15〜16 桁一致します。(c) 次数: 素朴な式の誤差は上の見積もり u / ( x 2 / 2 ) = 2 u / x 2 u/(x^2/2)=2u/x^2 u / ( x 2 /2 ) = 2 u / x 2 以下で、x x x を 1 / 10 1/10 1/10 にするとほぼ 100 100 100 倍に増えます(10 − 4 10^{-4} 1 0 − 4 から 10 − 6 10^{-6} 1 0 − 6 で 5.2 × 10 − 9 → 8.9 × 10 − 5 5.2\times10^{-9}\to8.9\times10^{-5} 5.2 × 1 0 − 9 → 8.9 × 1 0 − 5 )。x = 10 − 8 x=10^{-8} x = 1 0 − 8 では x 2 / 2 < u x^2/2\lt u x 2 /2 < u なので f l ( cos x ) = 1 \mathrm{fl}(\cos x)=1 fl ( cos x ) = 1 となり、答えは 0 0 0 、相対誤差は 1 1 1 です。なお NumPy の cos, sin は正しく丸められる保証はありませんが、誤差は数 u u u 程度で、上の見積もりの大きさを変えません。
n n n 個の浮動小数点数 x 1 , … , x n x_1,\ldots,x_n x 1 , … , x n を前から順に足すアルゴリズム
s ^ 1 = x 1 , s ^ k = f l ( s ^ k − 1 + x k ) ( k = 2 , … , n ) \hat s_1=x_1,\qquad\hat s_k=\mathrm{fl}(\hat s_{k-1}+x_k)\quad(k=2,\ldots,n) s ^ 1 = x 1 , s ^ k = fl ( s ^ k − 1 + x k ) ( k = 2 , … , n )
を逐次和 といいます。
定理 5.1 (逐次和の誤差 ) ✓
x 1 , … , x n ∈ F x_1,\ldots,x_n\in\mathbb{F} x 1 , … , x n ∈ F 、( n − 1 ) u < 1 (n-1)u\lt1 ( n − 1 ) u < 1 とし、逐次和の各段でオーバーフローもアンダーフローも起きないとする。このとき
s ^ n = ∑ i = 1 n x i ( 1 + θ ( i ) ) , ∣ θ ( i ) ∣ ≤ γ n − 1 , \hat s_n=\sum_{i=1}^nx_i(1+\theta^{(i)}),\qquad|\theta^{(i)}|\le\gamma_{n-1}, s ^ n = i = 1 ∑ n x i ( 1 + θ ( i ) ) , ∣ θ ( i ) ∣ ≤ γ n − 1 , したがって s = ∑ i x i s=\sum_ix_i s = ∑ i x i について ∣ s ^ n − s ∣ ≤ γ n − 1 ∑ i = 1 n ∣ x i ∣ |\hat s_n-s|\le\gamma_{n-1}\sum_{i=1}^n|x_i| ∣ s ^ n − s ∣ ≤ γ n − 1 ∑ i = 1 n ∣ x i ∣ である。
証明(定理 5.1) 標準モデル(系 3.1 )から s ^ k = ( s ^ k − 1 + x k ) ( 1 + δ k ) \hat s_k=(\hat s_{k-1}+x_k)(1+\delta_k) s ^ k = ( s ^ k − 1 + x k ) ( 1 + δ k ) , ∣ δ k ∣ ≤ u |\delta_k|\le u ∣ δ k ∣ ≤ u (k = 2 , … , n k=2,\ldots,n k = 2 , … , n )です。これを k = n k=n k = n から順に代入して展開すると
s ^ n = x 1 ∏ j = 2 n ( 1 + δ j ) + ∑ i = 2 n x i ∏ j = i n ( 1 + δ j ) \hat s_n=x_1\prod_{j=2}^n(1+\delta_j)+\sum_{i=2}^nx_i\prod_{j=i}^n(1+\delta_j) s ^ n = x 1 j = 2 ∏ n ( 1 + δ j ) + i = 2 ∑ n x i j = i ∏ n ( 1 + δ j ) です。x 1 x_1 x 1 に掛かる因子は n − 1 n-1 n − 1 個、x i x_i x i (i ≥ 2 i\ge2 i ≥ 2 )に掛かる因子は n − i + 1 ≤ n − 1 n-i+1\le n-1 n − i + 1 ≤ n − 1 個です。誤差因子の積の補題(補題 3.2[浮動小数と区間演算] )から k k k 個の積は 1 + θ k 1+\theta_k 1 + θ k , ∣ θ k ∣ ≤ γ k |\theta_k|\le\gamma_k ∣ θ k ∣ ≤ γ k で、補題 3.2 の 1 から γ k ≤ γ n − 1 \gamma_k\le\gamma_{n-1} γ k ≤ γ n − 1 です。最後の不等式は s ^ n − s = ∑ i x i θ ( i ) \hat s_n-s=\sum_ix_i\theta^{(i)} s ^ n − s = ∑ i x i θ ( i ) と三角不等式からです。
∎
この評価は 2 つのことを言っています。第一に、計算した和は入力を相対 γ n − 1 \gamma_{n-1} γ n − 1 だけ動かした数の正確な和 です(後退誤差が小さい)。第二に、正の数の和なら ∑ ∣ x i ∣ = s \sum|x_i|=s ∑ ∣ x i ∣ = s なので相対誤差は γ n − 1 ≈ ( n − 1 ) u \gamma_{n-1}\approx(n-1)u γ n − 1 ≈ ( n − 1 ) u 以下ですが、正負が打ち消し合う和では ∑ ∣ x i ∣ / ∣ s ∣ \sum|x_i|/|s| ∑ ∣ x i ∣/∣ s ∣ 倍に拡大されます(命題 4.2 と同じ構造)。
証明の展開をよく見ると、x i x_i x i に掛かる因子は n − i + 1 n-i+1 n − i + 1 個で、先に足す項ほど多くの丸めを受けます。正の数を足すときは小さい順に足すと評価が小さくなります(演習で確かめます)。
対ごとの和 (pairwise summation)は、隣どうしを足して長さを半分にする操作を繰り返します。長さ m m m の列 ( y 1 , … , y m ) (y_1,\ldots,y_m) ( y 1 , … , y m ) から、m m m が奇数なら末尾に 0 0 0 を足して偶数にし、( f l ( y 1 + y 2 ) , f l ( y 3 + y 4 ) , … ) (\mathrm{fl}(y_1+y_2),\mathrm{fl}(y_3+y_4),\ldots) ( fl ( y 1 + y 2 ) , fl ( y 3 + y 4 ) , … ) を作ります。これを長さが 1 1 1 になるまで繰り返し、残った数を s ^ \hat s s ^ とします。
定理 5.2 (対ごとの和の誤差 ) ✓
x 1 , … , x n ∈ F x_1,\ldots,x_n\in\mathbb{F} x 1 , … , x n ∈ F (n ≥ 2 n\ge2 n ≥ 2 )、L = ⌈ log 2 n ⌉ L=\lceil\log_2n\rceil L = ⌈ log 2 n ⌉ 、L u < 1 Lu\lt1 Lu < 1 とし、途中でオーバーフローもアンダーフローも起きないとする。対ごとの和の結果 s ^ \hat s s ^ は
s ^ = ∑ i = 1 n x i ( 1 + θ ( i ) ) , ∣ θ ( i ) ∣ ≤ γ L \hat s=\sum_{i=1}^nx_i(1+\theta^{(i)}),\qquad|\theta^{(i)}|\le\gamma_L s ^ = i = 1 ∑ n x i ( 1 + θ ( i ) ) , ∣ θ ( i ) ∣ ≤ γ L を満たし、∣ s ^ − s ∣ ≤ γ ⌈ log 2 n ⌉ ∑ i ∣ x i ∣ |\hat s-s|\le\gamma_{\lceil\log_2n\rceil}\sum_i|x_i| ∣ s ^ − s ∣ ≤ γ ⌈ l o g 2 n ⌉ ∑ i ∣ x i ∣ である。
証明(定理 5.2) 段数. ℓ \ell ℓ 段の後の列の長さは ⌈ n / 2 ℓ ⌉ \lceil n/2^\ell\rceil ⌈ n / 2 ℓ ⌉ です。ℓ \ell ℓ についての帰納法で、長さ m = ⌈ a ⌉ m=\lceil a\rceil m = ⌈ a ⌉ (a = n / 2 ℓ a=n/2^\ell a = n / 2 ℓ )の列が次の段で ⌈ m / 2 ⌉ \lceil m/2\rceil ⌈ m /2 ⌉ になるので、⌈ m / 2 ⌉ = ⌈ a / 2 ⌉ \lceil m/2\rceil=\lceil a/2\rceil ⌈ m /2 ⌉ = ⌈ a /2 ⌉ を示せばよいです。a ≤ m a\le m a ≤ m から ⌈ a / 2 ⌉ ≤ ⌈ m / 2 ⌉ \lceil a/2\rceil\le\lceil m/2\rceil ⌈ a /2 ⌉ ≤ ⌈ m /2 ⌉ 。逆に 2 ⌈ a / 2 ⌉ 2\lceil a/2\rceil 2 ⌈ a /2 ⌉ は a a a 以上の整数なので m = ⌈ a ⌉ m=\lceil a\rceil m = ⌈ a ⌉ 以上で、⌈ a / 2 ⌉ ≥ m / 2 \lceil a/2\rceil\ge m/2 ⌈ a /2 ⌉ ≥ m /2 、整数なので ⌈ a / 2 ⌉ ≥ ⌈ m / 2 ⌉ \lceil a/2\rceil\ge\lceil m/2\rceil ⌈ a /2 ⌉ ≥ ⌈ m /2 ⌉ です。長さが 1 1 1 になるのは n ≤ 2 ℓ n\le2^\ell n ≤ 2 ℓ のとき、すなわち ℓ ≥ log 2 n \ell\ge\log_2n ℓ ≥ log 2 n のときなので、段数は L L L です。
誤差. ℓ \ell ℓ 段の後の各成分が、元の連続したいくつかの x i x_i x i について ∑ x i ( 1 + θ ℓ ( i ) ) \sum x_i(1+\theta^{(i)}_\ell) ∑ x i ( 1 + θ ℓ ( i ) ) の形(1 + θ ℓ ( i ) 1+\theta^{(i)}_\ell 1 + θ ℓ ( i ) は ℓ \ell ℓ 個の ( 1 + δ ) (1+\delta) ( 1 + δ ) の積)であることを ℓ \ell ℓ の帰納法で示します。ℓ = 0 \ell=0 ℓ = 0 は x i x_i x i 自身です。次の段で 2 つの成分を足すと、標準モデル(系 3.1 )から和全体に 1 つの因子 ( 1 + δ ) (1+\delta) ( 1 + δ ) が掛かり、各 x i x_i x i の因子は 1 個増えます。末尾に補った 0 0 0 との和は厳密で、δ = 0 \delta=0 δ = 0 とすれば同じ形です。L L L 段の後、各 x i x_i x i には L L L 個の因子が掛かり、誤差因子の積の補題(補題 3.2[浮動小数と区間演算] )から ∣ θ ( i ) ∣ ≤ γ L |\theta^{(i)}|\le\gamma_L ∣ θ ( i ) ∣ ≤ γ L です。最後の不等式は三角不等式です。
∎
n = 10 6 n=10^6 n = 1 0 6 で、逐次和の評価の係数は n − 1 ≈ 10 6 n-1\approx10^6 n − 1 ≈ 1 0 6 、対ごとの和は ⌈ log 2 10 6 ⌉ = 20 \lceil\log_2 10^6\rceil=20 ⌈ log 2 1 0 6 ⌉ = 20 です。演算回数はどちらも n − 1 n-1 n − 1 回の足し算です。NumPy の np.sum(メモリ上で連続な軸に沿った和)は、変形した対ごとの和を使っています。列を(前半の長さを 8 の倍数にそろえて)半分に分けることを長さが 128 以下になるまで再帰的に繰り返し、128 個以下のかたまりの中では 8 本の逐次和を並行に走らせてから 8 本を対ごとに足し、かたまりどうしは分けたときと逆の順に対ごとに足します。かたまりの中に逐次和が残るので、上の定理の評価はそのままは当てはまりません。
例 5.3 (binary32 の 10⁶ 個の和 )
乱数種を固定した [ 0 , 1 ) [0,1) [ 0 , 1 ) の binary32 の一様乱数 10 6 10^6 1 0 6 個について、先頭 n n n 個の和を 3 通りで計算し、正しく丸めた和(math.fsum を binary64 で)と比べます。表の列は、n n n 、逐次和の相対誤差とその評価 γ n − 1 \gamma_{n-1} γ n − 1 、自作の対ごとの和の相対誤差とその評価 γ ⌈ log 2 n ⌉ \gamma_{\lceil\log_2n\rceil} γ ⌈ l o g 2 n ⌉ 、np.sum の相対誤差です(u = 2 − 24 u=2^{-24} u = 2 − 24 )。
# Python 3.12.10 / NumPy 2.5.2(x86-64)/乱数種 20261006
from fractions import Fraction
def pairwise ( x ) : # 隣どうしを足して長さを半分にする
x = np. append ( x , np. float32 ( 0 )) # 0 を足すのは厳密
u = 2.0 ** - 24 # binary32 の単位丸め
g = lambda k : k * u / ( 1 - k * u)
rng = np.random. default_rng ( 20261006 )
xs = rng. random ( 10 ** 6 , dtype = np.float32 )
for n in ( 10 ** 3 , 10 ** 4 , 10 ** 5 , 10 ** 6 ):
s = math. fsum ( x. astype ( np.float64 )) # 正しく丸めた和
rec = np. cumsum ( x , dtype = np.float32 ) [ - 1 ] # 逐次和
e = [ abs ( float ( t ) - s ) / s for t in (rec, pairwise ( x ), np. sum ( x )) ]
k = math. ceil ( math. log2 ( n ))
print ( f " {n :>8 } {e [ 0 ] :.2e } { g ( n - 1 ) :.2e } {e [ 1 ] :.2e } { g ( k ) :.2e } "
ex = sum ( map ( Fraction , xs. tolist ())) # 厳密な和(有理数)
print ( f "fsum と厳密な和の相対差 { abs ( s - ex ) / ex :.2e } " )
1000 6.22e-07 5.95e-05 7.56e-09 5.96e-07 7.56e-09
10000 1.16e-06 5.96e-04 9.95e-09 8.34e-07 1.08e-07
100000 4.52e-06 6.00e-03 1.47e-08 1.01e-06 1.47e-08
1000000 1.54e-05 6.34e-02 1.71e-08 1.19e-06 1.71e-08
検算. (a) 既知値: 各項は 2 − 24 2^{-24} 2 − 24 の整数倍で和は 2 20 2^{20} 2 20 未満なので、厳密な和は 44 ビットに収まり binary64 で正確に表せます。最終行のとおり fsum は有理数で計算した厳密な和と一致し、参照値に丸め誤差はありません。(b) 別手法: 逐次和と自作の対ごとの和の誤差は対応する評価の内側にあり、自作の対ごとの和は逐次和より 2〜3 桁小さい誤差です。np.sum は n = 10 4 n=10^4 n = 1 0 4 を除いて自作の対ごとの和と同じ誤差で、n = 10 4 n=10^4 n = 1 0 4 でも逐次和より 1 桁小さく、γ ⌈ log 2 n ⌉ \gamma_{\lceil\log_2n\rceil} γ ⌈ l o g 2 n ⌉ の内側にあります(np.sum は足す順序が違うので、この表の値は定理の対象外の参考値です)。(c) 次数: 評価 γ n − 1 \gamma_{n-1} γ n − 1 は n n n を 10 倍するごとに 10 倍、γ ⌈ log 2 n ⌉ \gamma_{\lceil\log_2n\rceil} γ ⌈ l o g 2 n ⌉ は log 2 10 ≈ 3.3 \log_2 10\approx3.3 log 2 10 ≈ 3.3 ずつ係数が増えるだけです。実際の逐次和の誤差は 10 倍ごとに 2〜4 倍で、最悪評価の 10 倍よりゆるやかです。丸め誤差の符号がそろわず打ち消し合うためで、定理はこの典型的な大きさまでは主張しません。
例 5.4 (binary32 の調和級数はどこで止まるか )
調和級数 ∑ 1 / k \sum1/k ∑ 1/ k は発散しますが、binary32 で前から足すと和はある所で増えなくなります。和 s ^ \hat s s ^ が [ 8 , 16 ) [8,16) [ 8 , 16 ) にあるとき間隔は 2 u ⋅ 8 = 2 − 20 2u\cdot8=2^{-20} 2 u ⋅ 8 = 2 − 20 なので、足す項 1 / k 1/k 1/ k が間隔の半分 2 − 21 2^{-21} 2 − 21 以下になると、s ^ + 1 / k \hat s+1/k s ^ + 1/ k は s ^ \hat s s ^ に丸められます(ちょうど半分のときは偶数丸めで、仮数が偶数ならそのまま)。和が 16 16 16 に届く前に k = 2 21 k=2^{21} k = 2 21 に達するなら、そこで止まるはずです。ln 2 21 + 0.5772 ≈ 15.13 < 16 \ln 2^{21}+0.5772\approx15.13\lt16 ln 2 21 + 0.5772 ≈ 15.13 < 16 なので、そう見積もれます。
# Python 3.12.10 / NumPy 2.5.2(x86-64)
k = np. arange ( 1 , 2 ** 23 + 1 , dtype = np.float32 )
t = np. float32 ( 1 ) / k # 1/k を binary32 に丸めた項
s = np. cumsum ( t , dtype = np.float32 ) # 前から逐次に足す
m = np. flatnonzero ( s [ 1 : ] == s [ : - 1 ]) [ 0 ] + 2 # 和が初めて増えない項
print ( " 止まる項 " , m , " = 2^21: " , m == 2 ** 21 )
print ( " binary32 の和 " , f " {s [ m - 1 ] :.6f } " , " 最後まで " , f " {s [ - 1 ] :.6f } " )
ref = np. sum ( 1.0 / np. arange ( 1 , m + 1 , dtype = np.float64 ))
print ( " binary64 の和 " , f " {ref :.6f } " )
止まる項 2097152 = 2^21: True
binary32 の和 15.403683 最後まで 15.403683
検算. (a) 既知値: 止まる項は見積もりどおり 2 21 = 2097152 2^{21}=2097152 2 21 = 2097152 で、以後 2 23 2^{23} 2 23 項まで和は変わりません。(b) 別精度: binary64 で同じ 2 21 2^{21} 2 21 項を足すと 15.133307 15.133307 15.133307 で、ln 2 21 + 0.577216 = 15.133306 \ln2^{21}+0.577216=15.133306 ln 2 21 + 0.577216 = 15.133306 (0.577216 0.577216 0.577216 は Euler の定数)とほぼ一致します(差は 1 / ( 2 ⋅ 2 21 ) ≈ 2.4 × 10 − 7 1/(2\cdot2^{21})\approx2.4\times10^{-7} 1/ ( 2 ⋅ 2 21 ) ≈ 2.4 × 1 0 − 7 程度の補正)。binary32 の和 15.4037 15.4037 15.4037 はこれより 0.27 0.27 0.27 大きくなります。主な原因は最後の段階 2 20 < k ≤ 2 21 2^{20}\lt k\le2^{21} 2 20 < k ≤ 2 21 です。ここでは和が [ 8 , 16 ) [8,16) [ 8 , 16 ) にあり、項 1 / k 1/k 1/ k は間隔 2 − 20 2^{-20} 2 − 20 の半分と 1 間隔の間にあるので、どの項も 1 目盛り 2 − 20 2^{-20} 2 − 20 に切り上げられて足されます。過大分は ∑ k = 2 20 + 1 2 21 ( 2 − 20 − 1 / k ) ≈ 1 − ln 2 ≈ 0.307 \sum_{k=2^{20}+1}^{2^{21}}(2^{-20}-1/k)\approx1-\ln2\approx0.307 ∑ k = 2 20 + 1 2 21 ( 2 − 20 − 1/ k ) ≈ 1 − ln 2 ≈ 0.307 です。それより前の段階では切り上げと切り捨てが混じり、差し引きで約 0.037 0.037 0.037 小さくなるので(各段の丸め誤差を足し上げて確かめられます)、合計が 0.27 0.27 0.27 です。(c) 誤差の大きさ: 差 0.27 0.27 0.27 は 定理 5.1 の評価 γ n − 1 ∑ ∣ x i ∣ \gamma_{n-1}\sum|x_i| γ n − 1 ∑ ∣ x i ∣ (n = 2 21 n=2^{21} n = 2 21 では ( n − 1 ) u ≈ 0.125 (n-1)u\approx0.125 ( n − 1 ) u ≈ 0.125 で、γ ≈ 0.14 \gamma\approx0.14 γ ≈ 0.14 、評価は約 2.2 2.2 2.2 )の内側です。
和の誤差をさらに小さくする方法として、各段の丸め誤差を別の変数に拾って次の段で足し戻す補償和 (Kahan の方法)があります。
多項式 p ( x ) = ∑ i = 0 n a i x i p(x)=\sum_{i=0}^na_ix^i p ( x ) = ∑ i = 0 n a i x i の値を計算する標準的な方法は Horner 法
q n = a n , q k = x q k + 1 + a k ( k = n − 1 , … , 0 ) , p ( x ) = q 0 q_n=a_n,\qquad q_k=x\,q_{k+1}+a_k\quad(k=n-1,\ldots,0),\qquad p(x)=q_0 q n = a n , q k = x q k + 1 + a k ( k = n − 1 , … , 0 ) , p ( x ) = q 0
です。乗算 n n n 回・加算 n n n 回で済みます。浮動小数点数では各段が q ^ k = f l ( f l ( x q ^ k + 1 ) + a k ) \hat q_k=\mathrm{fl}(\mathrm{fl}(x\hat q_{k+1})+a_k) q ^ k = fl ( fl ( x q ^ k + 1 ) + a k ) になります。
定理 6.1 (Horner 法の後退誤差 ) ✓
x , a 0 , … , a n ∈ F x,a_0,\ldots,a_n\in\mathbb{F} x , a 0 , … , a n ∈ F 、2 n u < 1 2nu\lt1 2 n u < 1 とし、Horner 法の途中でオーバーフローもアンダーフローも起きないとする。このとき計算値 q ^ 0 \hat q_0 q ^ 0 は
q ^ 0 = ∑ i = 0 n a i ( 1 + θ i ) x i , ∣ θ i ∣ ≤ γ 2 n \hat q_0=\sum_{i=0}^na_i(1+\theta_i)\,x^i,\qquad|\theta_i|\le\gamma_{2n} q ^ 0 = i = 0 ∑ n a i ( 1 + θ i ) x i , ∣ θ i ∣ ≤ γ 2 n を満たす。すなわち q ^ 0 \hat q_0 q ^ 0 は、各係数を相対 γ 2 n \gamma_{2n} γ 2 n 以内で動かした多項式 p ~ ( x ) = ∑ i a ~ i x i \tilde p(x)=\sum_i\tilde a_ix^i p ~ ( x ) = ∑ i a ~ i x i (a ~ i = a i ( 1 + θ i ) \tilde a_i=a_i(1+\theta_i) a ~ i = a i ( 1 + θ i ) )の、x x x における正確な値である。
証明の方針は、各段の乗算と加算の丸めを、それぞれ ( 1 + ε k ) (1+\varepsilon_k) ( 1 + ε k ) , ( 1 + δ k ) (1+\delta_k) ( 1 + δ k ) という因子として書き、最後に係数 a i a_i a i へ掛かる因子の個数を数えることです。添字は多いですが、a i a_i a i に掛かる因子が高々 2 n 2n 2 n 個であることを示すための帳簿にすぎません。
証明(定理 6.1) 標準モデル(系 3.1 )から、k = n − 1 , … , 0 k=n-1,\ldots,0 k = n − 1 , … , 0 について
q ^ k = ( x q ^ k + 1 ( 1 + ε k ) + a k ) ( 1 + δ k ) , ∣ ε k ∣ , ∣ δ k ∣ ≤ u \hat q_k=\bigl(x\hat q_{k+1}(1+\varepsilon_k)+a_k\bigr)(1+\delta_k),\qquad|\varepsilon_k|,|\delta_k|\le u q ^ k = ( x q ^ k + 1 ( 1 + ε k ) + a k ) ( 1 + δ k ) , ∣ ε k ∣ , ∣ δ k ∣ ≤ u です。k k k についての下向きの帰納法で
q ^ k = ∑ i = k n a i x i − k π k , i , π k , i = ( 1 + δ i ) [ i < n ] ∏ j = k i − 1 ( 1 + ε j ) ( 1 + δ j ) \hat q_k=\sum_{i=k}^na_ix^{i-k}\,\pi_{k,i},\qquad\pi_{k,i}=(1+\delta_i)^{[i\lt n]}\prod_{j=k}^{i-1}(1+\varepsilon_j)(1+\delta_j) q ^ k = i = k ∑ n a i x i − k π k , i , π k , i = ( 1 + δ i ) [ i < n ] j = k ∏ i − 1 ( 1 + ε j ) ( 1 + δ j ) を示します([ i < n ] [i\lt n] [ i < n ] は i < n i\lt n i < n なら 1 1 1 、i = n i=n i = n なら 0 0 0 )。k = n k=n k = n では q ^ n = a n \hat q_n=a_n q ^ n = a n で π n , n = 1 \pi_{n,n}=1 π n , n = 1 です。k + 1 k+1 k + 1 で成り立てば、上の式に代入して
q ^ k = ∑ i = k + 1 n a i x i − k π k + 1 , i ( 1 + ε k ) ( 1 + δ k ) + a k ( 1 + δ k ) \hat q_k=\sum_{i=k+1}^na_ix^{i-k}\,\pi_{k+1,i}(1+\varepsilon_k)(1+\delta_k)+a_k(1+\delta_k) q ^ k = i = k + 1 ∑ n a i x i − k π k + 1 , i ( 1 + ε k ) ( 1 + δ k ) + a k ( 1 + δ k ) で、π k + 1 , i ( 1 + ε k ) ( 1 + δ k ) = π k , i \pi_{k+1,i}(1+\varepsilon_k)(1+\delta_k)=\pi_{k,i} π k + 1 , i ( 1 + ε k ) ( 1 + δ k ) = π k , i , 1 + δ k = π k , k 1+\delta_k=\pi_{k,k} 1 + δ k = π k , k なので k k k でも成り立ちます。π 0 , i \pi_{0,i} π 0 , i の因子の個数は、i < n i\lt n i < n なら 1 + 2 i ≤ 2 n − 1 1+2i\le2n-1 1 + 2 i ≤ 2 n − 1 、i = n i=n i = n なら 2 n 2n 2 n です。誤差因子の積の補題(補題 3.2[浮動小数と区間演算] )と 補題 3.2 の 1 から π 0 , i = 1 + θ i \pi_{0,i}=1+\theta_i π 0 , i = 1 + θ i , ∣ θ i ∣ ≤ γ 2 n |\theta_i|\le\gamma_{2n} ∣ θ i ∣ ≤ γ 2 n です。
∎
この定理は、Horner 法の答えが「正しい問題の近似解」ではなく「近い問題の正確な解」であることを言っています。係数そのものが測定値や前の計算の結果で相対 u u u 程度の誤差をもつなら、Horner 法の誤差はそれと同じ程度で、アルゴリズムとしてはこれ以上望めません。答え p ( x ) p(x) p ( x ) そのものの誤差は、ここから三角不等式で
∣ q ^ 0 − p ( x ) ∣ ≤ γ 2 n ∑ i = 0 n ∣ a i ∣ ∣ x ∣ i |\hat q_0-p(x)|\le\gamma_{2n}\sum_{i=0}^n|a_i||x|^i ∣ q ^ 0 − p ( x ) ∣ ≤ γ 2 n i = 0 ∑ n ∣ a i ∣∣ x ∣ i
と評価できます。右辺を ∣ p ( x ) ∣ |p(x)| ∣ p ( x ) ∣ で割った倍率 ∑ ∣ a i ∣ ∣ x ∣ i / ∣ p ( x ) ∣ \sum|a_i||x|^i/|p(x)| ∑ ∣ a i ∣∣ x ∣ i /∣ p ( x ) ∣ は、p ( x ) p(x) p ( x ) が根の近くで小さいときに大きくなります。根の近くで多項式の値を正確に計算できないのは、Horner 法が悪いのではなく、問題そのものが係数の摂動に敏感だからです。この「問題の感度(条件数)」と「アルゴリズムの後退誤差」の区別が、このテーマの条件数と安定性 の章の主題です。
演習 7.1 易
binary64 の [ 1 , 2 ) [1,2) [ 1 , 2 ) に含まれる浮動小数点数の個数を求めよ。また、正規化数の範囲で隣り合う浮動小数点数の相対的な間隔 ( s u c c ( x ) − x ) / x (\mathrm{succ}(x)-x)/x ( succ ( x ) − x ) / x の最大値と最小値を、u u u を使って表せ。
解答 [ 1 , 2 ) [1,2) [ 1 , 2 ) の浮動小数点数は M ⋅ 2 − 52 M\cdot2^{-52} M ⋅ 2 − 52 (2 52 ≤ M < 2 53 2^{52}\le M\lt2^{53} 2 52 ≤ M < 2 53 )なので 2 52 ≈ 4.5 × 10 15 2^{52}\approx4.5\times10^{15} 2 52 ≈ 4.5 × 1 0 15 個です。x ∈ [ 2 e , 2 e + 1 ) x\in[2^e,2^{e+1}) x ∈ [ 2 e , 2 e + 1 ) の正規化数の右の間隔は 2 u ⋅ 2 e 2u\cdot2^e 2 u ⋅ 2 e なので、相対的な間隔は 2 u ⋅ 2 e / x 2u\cdot2^e/x 2 u ⋅ 2 e / x で、x = 2 e x=2^e x = 2 e のとき最大値 2 u 2u 2 u 、x x x が 2 e + 1 2^{e+1} 2 e + 1 の直前(x = ( 2 − 2 u ) 2 e x=(2-2u)2^e x = ( 2 − 2 u ) 2 e )のとき最小値 2 u / ( 2 − 2 u ) = u / ( 1 − u ) 2u/(2-2u)=u/(1-u) 2 u / ( 2 − 2 u ) = u / ( 1 − u ) です。相対的な間隔が 2 倍近く揺れることが、ε M = 2 u \varepsilon_M=2u ε M = 2 u と u u u の 2 つの量が使われる理由の 1 つです。
演習 7.2 標準
Sterbenz の補題の条件 y / 2 ≤ x ≤ 2 y y/2\le x\le2y y /2 ≤ x ≤ 2 y はゆるめられないことを、x x x を 2 2 2 の次の浮動小数点数、y y y を 1 1 1 の前の浮動小数点数として確かめよ(精度 p p p の一般の形式で、e min ≤ − 1 e_{\min}\le-1 e m i n ≤ − 1 , e max ≥ 1 e_{\max}\ge1 e m a x ≥ 1 とする)。
解答 [ 2 , 4 ) [2,4) [ 2 , 4 ) の間隔は 4 u 4u 4 u 、[ 1 / 2 , 1 ) [1/2,1) [ 1/2 , 1 ) の間隔は u u u なので、x = 2 + 4 u x=2+4u x = 2 + 4 u , y = 1 − u y=1-u y = 1 − u です。x / y = ( 2 + 4 u ) / ( 1 − u ) > 2 x/y=(2+4u)/(1-u)\gt2 x / y = ( 2 + 4 u ) / ( 1 − u ) > 2 で条件をわずかに外れます。x − y = 1 + 5 u x-y=1+5u x − y = 1 + 5 u ですが、[ 1 , 2 ) [1,2) [ 1 , 2 ) の浮動小数点数は 2 u 2u 2 u の整数倍なので、奇数倍の 5 u 5u 5 u を含む 1 + 5 u 1+5u 1 + 5 u は F \mathbb{F} F に属しません。したがって f l ( x − y ) ≠ x − y \mathrm{fl}(x-y)\ne x-y fl ( x − y ) = x − y で、引き算に丸め誤差が入ります。
演習 7.3 標準
定理 5.1 の証明の展開を使って、∣ s ^ n − s ∣ ≤ ∑ i = 1 n γ c i ∣ x i ∣ |\hat s_n-s|\le\sum_{i=1}^n\gamma_{c_i}|x_i| ∣ s ^ n − s ∣ ≤ ∑ i = 1 n γ c i ∣ x i ∣ (c 1 = n − 1 c_1=n-1 c 1 = n − 1 、c i = n − i + 1 c_i=n-i+1 c i = n − i + 1 (i ≥ 2 i\ge2 i ≥ 2 ))を示せ。これを使って、正の数 x 1 , … , x n x_1,\ldots,x_n x 1 , … , x n を足すとき、小さい順に並べて足すとこの評価が最小になることを説明せよ。
解答 展開の式で x i x_i x i に掛かる因子は c i c_i c i 個なので、誤差因子の積の補題から ∣ θ ( i ) ∣ ≤ γ c i |\theta^{(i)}|\le\gamma_{c_i} ∣ θ ( i ) ∣ ≤ γ c i で、三角不等式から主張が出ます。係数の列 γ c 1 , γ c 2 , … , γ c n \gamma_{c_1},\gamma_{c_2},\ldots,\gamma_{c_n} γ c 1 , γ c 2 , … , γ c n は γ n − 1 , γ n − 1 , γ n − 2 , … , γ 1 \gamma_{n-1},\gamma_{n-1},\gamma_{n-2},\ldots,\gamma_1 γ n − 1 , γ n − 1 , γ n − 2 , … , γ 1 で、添字が後ろほど小さい非増加列です。∑ γ c i x i \sum\gamma_{c_i}x_i ∑ γ c i x i を最小にする並べ方は、並べ替え不等式(大きい係数に小さい数を対応させる)により x i x_i x i を昇順に並べたものです。ただしこれは評価 を最小にするだけで、実際の誤差が必ず最小になるとは限りません。
演習 7.4 標準
p ( x ) = ( x − 1 ) 10 p(x)=(x-1)^{10} p ( x ) = ( x − 1 ) 10 を展開した係数で Horner 法により x = 1.01 x=1.01 x = 1.01 での値を計算するとき、定理 6.1 から得られる相対誤差の評価 γ 20 ∑ ∣ a i ∣ ∣ x ∣ i / ∣ p ( x ) ∣ \gamma_{20}\sum|a_i||x|^i/|p(x)| γ 20 ∑ ∣ a i ∣∣ x ∣ i /∣ p ( x ) ∣ を見積もれ。binary64 で何桁が信頼できるか。
解答 a i = ( 10 i ) ( − 1 ) 10 − i a_i=\binom{10}{i}(-1)^{10-i} a i = ( i 10 ) ( − 1 ) 10 − i なので ∑ ∣ a i ∣ ∣ x ∣ i = ( 1 + x ) 10 = 2.01 10 ≈ 1.08 × 10 3 \sum|a_i||x|^i=(1+x)^{10}=2.01^{10}\approx1.08\times10^{3} ∑ ∣ a i ∣∣ x ∣ i = ( 1 + x ) 10 = 2.0 1 10 ≈ 1.08 × 1 0 3 、∣ p ( x ) ∣ = 0.01 10 = 10 − 20 |p(x)|=0.01^{10}=10^{-20} ∣ p ( x ) ∣ = 0.0 1 10 = 1 0 − 20 です。倍率は約 1.1 × 10 23 1.1\times10^{23} 1.1 × 1 0 23 で、γ 20 ≈ 20 u ≈ 2.2 × 10 − 15 \gamma_{20}\approx20u\approx2.2\times10^{-15} γ 20 ≈ 20 u ≈ 2.2 × 1 0 − 15 を掛けると評価は 2 × 10 8 2\times10^{8} 2 × 1 0 8 になり、1 桁も保証されません。展開せずに ( x − 1 ) 10 (x-1)^{10} ( x − 1 ) 10 と計算すれば、x − 1 x-1 x − 1 は 補題 4.1 により厳密で、相対誤差は γ 10 \gamma_{10} γ 10 程度です(x x x を浮動小数点数とした場合)。同じ関数でも、計算する式によって答えの精度がまったく違います。
N. J. Higham, Accuracy and Stability of Numerical Algorithms , 2nd ed., SIAM, 2002 — 第 2 章(浮動小数点数と標準モデル)、第 3 章(γ n \gamma_n γ n )、第 4 章(和の誤差と補償和)、第 5 章(多項式と Horner 法)。
IEEE Computer Society, IEEE Standard for Floating-Point Arithmetic (IEEE Std 754-2019), 2019 — 第 3 章(形式)、第 4 章(丸めの属性)、第 5 章(演算)。
D. Goldberg, “What every computer scientist should know about floating-point arithmetic”, ACM Computing Surveys 23 (1991), 5–48. doi:10.1145/103162.103163
J.-M. Muller ほか, Handbook of Floating-Point Arithmetic , 2nd ed., Birkhäuser, 2018 — 浮動小数点数の形式、fma、誤差なし変換。
P. H. Sterbenz, Floating-Point Computation , Prentice-Hall, 1974 — 引き算が厳密になる条件。
L. N. Trefethen, D. Bau III, Numerical Linear Algebra , SIAM, 1997 — Lecture 13(浮動小数点数)、Lecture 14(安定性)。
執筆: Claude Code(Opus 5.5)、Claude Code(Sonnet 5.5)・監査 2 回(Claude Code)・最終 2026-10-12