Oka Laboratory

ContFract!

ユークリッドの互除法 (Euclidean Algorithm) は最大公約数 (GCD) を求めるときに使うアルゴリズムとして有名ですが、連分数 (continued fraction) 展開にも適用できます。

連分数展開

/
n 部分商 an 近似分数 pn/qn

使用方法

利用上の注意

アルゴリズム

2つの自然数a, b(≠0)について、aをbで除したときの商 (quotient) をq、剰余 (remainder) をr としたとき、qが連分数の部分商 (項) となります。

a=b⁢q+r ⇔ ab=q+ 1br

右側の式の br を新たに ab とおいて、r=0 となるまで計算を繰り返すことで、全ての部分商を得ることができます。

var euclidean = function(a, b) {
/* Euclidean Algorithmによる連分数展開 */
	var q = [], r;
	var i = 0;
	const max_term = 100;	// 最大項数
	while (b !== 0 && i <= max_term) {
		q[i++] = Math.floor(a / b);
		r = a % b;
		a = b;
		b = r;
	}
	return q;
};

eucldiean(a,b)関数の第1引数 a は連分数展開する数値の分子、第2引数 b は分母で、戻り値は連分数の部分商配列です。

最大公約数の計算では停止性 (termination) が保証されていますが、実数の連分数展開では、丸め誤差 (rounding error) の蓄積や桁落ち (cancellation) による有功桁数 (significant digits) の減少により、停止性が確実に保証されているとは言い切れません。このため、最大項数 max_term によって停止性を保証しています。

アルゴリズム上では a≥b の必要がありますが、a<b であっても1周目のループで aとbが交換され、条件を満たすようになります。

部分商 a[n] から近似分数 pn/qn を以下の漸化式で求めることができます。

{ p-2=0, p-1=1, pn=an⁢pn-1+pn-2 q-2=1, q-1=0, qn=an⁢qn-1+qn-2 (n≧0)

若しくは上の漸化式を行列化して求めることもできます。当研究室ではこちらを採用しています。

( p0p-1 q0q-1 ) = ( 10 01 ) ⁢ ( a01 10 ) , ( pnpn-1 qnqn-1 ) = ( pn-1pn-2 qn-1qn-2 ) ⁢ ( an1 10 ) (n≧1)
/* 連分数展開による近似分数 */
var multi_matrix = function(a, b) {
/* 2×2行列の積 */
	return [[a[0][0] * b[0][0] + a[0][1] * b[1][0], a[0][0] * b[0][1] + a[0][1] * b[1][1]],
			[a[1][0] * b[0][0] + a[1][1] * b[1][0], a[1][0] * b[0][1] + a[1][1] * b[1][1]]];
};
var a = euclidean(num, denom);		// num/denomの連分数展開
var convergent = [[1, 0], [0, 1]];	// 連分数展開における近似分数(convergent)
var conv_text = [];					// 近似分数の文字列配列
for (var i = 0; i < a.length; i++) {
		convergent = multi_matrix(convergent, [[a[i], 1], [1, 0]]);
		conv_text[i] = convergent[0][0] + '/' + convergent[1][0];
}

表の可変行数に関するアルゴリズムは、小技集 "Tips!" で公開しています。

参考文献


正当なCSSです!