Rational 連分数と最良有理近似

概要

有理数 $p/q$ の連分数展開

$$\frac{p}{q} = a_0 + \cfrac{1}{a_1 + \cfrac{1}{a_2 + \cfrac{1}{a_3 + \cdots}}} = [a_0; a_1, a_2, a_3, \ldots]$$

と書ける表示で、$a_0 \in \mathbb{Z}$, $a_k \in \mathbb{Z}_{>0}$ ($k \geq 1$) を満たす。 有理数の場合は有限長 (連分数係数の列が有限) で終わり、無理数の場合は無限に続く。

sangi の Rational は連分数展開 toContinuedFraction() と 復元 fromContinuedFraction() を提供する。 これにより分母制約下での最良有理近似や、Float ↔ Rational 変換の応用が可能となる。

API の使い方については Rational API リファレンス — 連分数 を参照。

連分数展開 — Euclidean 過程

アルゴリズム

連分数係数 $a_k$ はユークリッドの互除法と同型の手続きで得られる。

$$\begin{aligned} (r_0, r_1) &\leftarrow (p, q), \\ a_k &= \lfloor r_k / r_{k+1} \rfloor, \\ r_{k+2} &= r_k - a_k \, r_{k+1} = r_k \bmod r_{k+1}, \\ &\text{stop when } r_{k+2} = 0. \end{aligned}$$

$\gcd(p, q)$ を求めるユークリッドの互除法と完全に同じ反復であり、 商 $a_k$ をすべて記録すれば連分数係数列が得られる。

計算量: $O(\log \min(|p|, q))$ 回の除算。 Lamé の定理により、係数列の長さは Fibonacci 数列により上から $O(\log_\phi q)$ で抑えられる ($\phi = (1+\sqrt{5})/2$)。

$355/113$ の連分数展開:

$$\begin{aligned} 355 &= 3 \cdot 113 + 16, & a_0 &= 3, \\ 113 &= 7 \cdot 16 + 1, & a_1 &= 7, \\ 16 &= 16 \cdot 1 + 0, & a_2 &= 16. \end{aligned}$$

よって $355/113 = [3; 7, 16]$ である。

復元

係数列 $[a_0; a_1, \ldots, a_n]$ から有理数を復元するには末尾から畳み込む。

$$x = a_n, \quad x \leftarrow a_k + 1/x \quad (k = n-1, n-2, \ldots, 0)$$

逆向きに収束分数を漸化式で生成する (次節) より高速で、整数演算のみで完結する。

関連記事: 連分数とペル方程式 — 連分数の定義、収束分数、周期的連分数、Lagrange の定理、Pell 方程式への応用 / 多倍長 GCD アルゴリズム

収束分数の漸化式

連分数 $[a_0; a_1, \ldots, a_n]$ を $k$ 番目で打ち切った値を $k$ 番目の収束分数 (convergent) と呼ぶ:

$$\frac{p_k}{q_k} = [a_0; a_1, \ldots, a_k]$$

収束分数は次の漸化式で生成される。

$$\begin{aligned} p_{-1} &= 1, & p_0 &= a_0, & p_k &= a_k p_{k-1} + p_{k-2}, \\ q_{-1} &= 0, & q_0 &= 1, & q_k &= a_k q_{k-1} + q_{k-2}. \end{aligned}$$

$2 \times 2$ 行列の積として書くと:

$$\begin{pmatrix} p_k & p_{k-1} \\ q_k & q_{k-1} \end{pmatrix} = \begin{pmatrix} a_0 & 1 \\ 1 & 0 \end{pmatrix} \begin{pmatrix} a_1 & 1 \\ 1 & 0 \end{pmatrix} \cdots \begin{pmatrix} a_k & 1 \\ 1 & 0 \end{pmatrix}$$

各行列の行列式は $-1$ なので、積の行列式は $(-1)^{k+1}$ となり、次の恒等式が得られる:

$$p_k q_{k-1} - p_{k-1} q_k = (-1)^{k+1}$$

これにより $p_k$ と $q_k$ は常に互いに素であり、収束分数は最初から約分済みである。

例: π の収束分数

$\pi = 3.14159265\ldots$ の連分数展開は $[3; 7, 15, 1, 292, 1, 1, 1, 2, 1, 3, \ldots]$ で、最初の数項の収束分数は:

$k$$a_k$$p_k / q_k$誤差
033$0.142$
1722/7$1.3 \times 10^{-3}$
215333/106$8.3 \times 10^{-5}$
31355/113$2.7 \times 10^{-7}$
4292103993/33102$5.8 \times 10^{-10}$

$a_4 = 292$ という大きな係数のおかげで、$355/113$ は分母を 100 倍に増やしただけで誤差が $3$ 桁向上し、 分母 $113$ までの中では極めて良い近似となる。

Stern-Brocot 木との関係

Stern-Brocot 木は、$0/1$ と $1/0$ から始まり、左右の中間分数 (mediant) を順に挟むことで、 すべての正既約分数を一度ずつ生成する 2 分木である:

$$\operatorname{mediant}\!\left(\frac{a}{b}, \frac{c}{d}\right) = \frac{a + c}{b + d}$$

連分数係数 $[a_0; a_1, a_2, \ldots]$ は Stern-Brocot 木上の経路と次のように対応する:

  • 根 $1/1$ から出発
  • $a_0$ 回 R (右)
  • $a_1$ 回 L (左)
  • $a_2$ 回 R (右)
  • $\ldots$ と交互

各収束分数 $p_k/q_k$ は、$k$ 番目の左折・右折の切り替わり地点 (列車の方向転換) に対応する。 連分数展開は本質的に Stern-Brocot 木の探索経路をランレングス圧縮した表示と見なせる。

sangi の nextMinimal() (Stern-Brocot 順で次の正有理数) や nextCalkinWilf() (Calkin-Wilf 列で次の正有理数) はこの木構造を直接たどる関数である。

最良有理近似

最良近似の定義

実数 $x$ と分母制約 $D$ に対し、 分母 $q \leq D$ の有理数 $p/q$ のなかで $|x - p/q|$ を最小化するものを最良有理近似と呼ぶ。

Lagrange の定理

$x$ の連分数展開 $[a_0; a_1, a_2, \ldots]$ の収束分数 $p_k/q_k$ は最良近似であり、 次の不等式を満たす:

$$\left| x - \frac{p_k}{q_k} \right| < \frac{1}{q_k q_{k+1}} < \frac{1}{q_k^2}$$

かつ、$q \leq q_k$ なる任意の分数 $p/q \neq p_k/q_k$ に対し

$$\left| x - \frac{p_k}{q_k} \right| < \left| x - \frac{p}{q} \right|$$

これが連分数の本質的な性質であり、$\pi$ の良い有理近似 $22/7$ や $355/113$ がなぜ「良い」のかを説明する。

アルゴリズム: 分母 D 以下の最良近似

実数 $x$ の連分数係数を逐次計算し、収束分数の分母が $D$ を超える直前で打ち切る。 途中の $a_k$ を超える小さな係数 $a'_k$ を取って中間収束分数 (semiconvergent) を試す経路もあり、 この場合は分母 $D$ ぎりぎりの semiconvergent が最良近似となることがある。

Float ↔ Rational 変換

Float → Rational (精確変換)

Rational(double value) および Rational(const Float&) は IEEE 754 ビット列 (仮数 $m$ と指数 $e$) からそのまま $m \cdot 2^e$ を構成する精確変換である。 $0.1$ のような十進表記で簡単な数も IEEE 754 では 3602879701896397 / 2^55 のような近似値であり、 精確変換するとこの値がそのまま Rational になる。

Float → Rational (連分数による有理近似)

精確変換は「double 値の正確な再現」を目指すが、 「人間が意図したであろう簡潔な分数」を得たい場合は連分数による近似が有効である。 分母制約 $D$ の下での最良近似を取ることで、$0.1 \to 1/10$ や $0.3333\ldots \to 1/3$ のような自然な復元ができる。

典型的なユースケースは:

  • テスト用の期待値を double で書いたあと、ハッシュ用の安定 ID として Rational 化
  • UI から受け取った小数値を有理数として保管 (CAS で正確な記号計算を続けるため)
  • 機械学習モデルの重みを既約分数で表現して再現性を確保

Rational → Float

逆変換 toDouble(), toFloat(), toMpFloat(prec) は 分子・分母をそれぞれ Float に変換して除算する。 $p$ と $q$ の桁数が double の有効桁数 (16 桁) を大きく超える場合、 変換結果は IEEE 754 の最近接丸めに従う。

Hurwitz の定理

連分数の最良近似性をさらに精密化した定理として Hurwitz の定理がある:

Hurwitz の定理 (1891): 任意の無理数 $\alpha$ に対し、 無限個の有理数 $p/q$ が次を満たす:

$$\left| \alpha - \frac{p}{q} \right| < \frac{1}{\sqrt{5} \, q^2}$$

定数 $\sqrt{5}$ はベストポシブルであり、これより小さい定数では成り立たない無理数が存在する。 等号を達成する無理数は黄金比 $\phi = (1+\sqrt{5})/2$ の連分数展開 $[1; 1, 1, 1, \ldots]$ に関連する数族である。

$\phi$ の連分数係数がすべて $1$ であることが、$\phi$ を「最も近似しにくい無理数」にしている。 この性質はDiophantine 近似の出発点である。

関連記事: 連分数とペル方程式 — Lagrange 最良近似定理、周期的連分数、ペル方程式 $x^2 - D y^2 = 1$ の構成的解法

設計判断

係数列の型

toContinuedFraction()std::vector<Int> を返す。 係数は理論上 int に収まらない場合があり (特に Float 近似経由の係数)、 Int を採用することで型変換とオーバーフローの両方を回避する。

有限長と無限長

有理数の連分数は必ず有限長で終わる。 無理数の場合は無限長になるため、sangi の toContinuedFraction()Rational 専用 (有限長保証) であり、無理数の連分数は別 API (将来予定の Float 用 lazy continued fraction) で扱う。

末尾係数の正規化

連分数 $[a_0; a_1, \ldots, a_n]$ は $a_n = 1, n \geq 1$ のとき $[a_0; a_1, \ldots, a_{n-1} + 1]$ と同一の有理数を表す。 sangi は末尾 $a_n \neq 1$ または長さ 1 のいずれかになるよう正規化する。 これにより連分数表現が一意になり、ハッシュ・比較が単純化される。

参考文献

  • Hardy, G. H. and Wright, E. M. An Introduction to the Theory of Numbers. 6th ed. Oxford University Press, 2008. Chapter X (連分数).
  • Khinchin, A. Ya. Continued Fractions. Dover, 1997.
  • Graham, R. L., Knuth, D. E., and Patashnik, O. Concrete Mathematics. 2nd ed. Addison-Wesley, 1994. §4.5 (Stern-Brocot 木).