ruby 、perl 、python の多倍長整数演算の速度を適当に比較してみました。フィボナッチ数の計算速度比較以上にどーでもいい比較です。

実験 1: 5 の累乗の計算 5 の 30,000 乗、100,000 乗、300,000 乗、1,000,000 乗の計算にかかる時間を調べました。単位は秒。 30000 100000 300000 1000000 ruby 0.09 0.13 0.78 8.21 python 0.14 0.12 0.31 1.37 perl(bigint) 3.67 37.05 N/A N/A perl(GMP) 0.06 0.06 0.09 0.21 GMP は当然として python も結構速いです。python は乗算に Karatsuba 法を実装しているようです。perl の bigint は圧倒的に遅いです。100 秒超えたら N/A です。

以下ソース。n を数字に置き換えてください。 5 **n 5 **n use bigint ; 5 **n; use Math::BigInt lib => "GMP" ; Math::BigInt->new( 5 )->bpow(n);

実験 2: 5 の累乗の表示 実験 1 の数字を 10 進表示するのにかかる時間を調べました。多倍長整数を文字列化するということは基数変換するということであり、これが結構時間のかかる処理なのです。 30000 100000 300000 1000000 ruby 0.01 0.05 4.05 42.88 python 0.24 3.16 28.92 N/A perl(bigint) 0.01 1.74 N/A N/A perl(GMP) 0.02 0.06 0.21 1.20 やはり GMP が圧倒的ですが、Ruby もかろうじて動きます。Ruby は基数変換に Karatsuba 法を用いているためです (ruby-dev:31323) 。ちょっと手前味噌。

以下ソース。上の表の数値は下のソースの実行時間から実験 1 の数値を引いてあります (つまり累乗の計算時間は含みません) 。 p( 5 **n) print ( 5 **n) use bigint ; print ( 5 **n); print "

" ; use Math::BigInt lib => "GMP" ; print Math ::BigInt->new( 5 )->bpow(n); print "

" ;

実験 3: 円周率の計算 最後に、多倍長整数を使って円周率を 100 桁、1,000 桁、10,000 桁計算する時間を調べました。 100 1000 10000 ruby 0.03 0.25 5.77 python 0.09 0.13 6.11 perl(bigint) 0.25 3.44 N/A perl(GMP) 0.11 0.59 6.56 あれほど圧倒的だった GMP がなぜか普通です。もっと大きな桁で威力を発揮するのかな。ruby と python はほぼ同じ。bigint はやっぱり全然ダメです。

以下ソース。python わからないのでなんだかかっこわるい。GMP の演算は破壊的なので copy() とか必要でうっとうしすぎます。 a = b = 10 ** n (n * 8 + 1 ).step( 3 , -2 ) do | i | a = (i / 2 ) * (a + b * 2 ) / i end puts " 3. #{ a - b }" a = b = 10 ** n for i in range (n * 8 + 1 , 1 , - 2 ): a = divmod ( divmod (i, 2 )[ 0 ] * (a + b * 2 ), i)[ 0 ] print ( "3." + str (a - b)) use strict ; use bigint ; my $a ; my $b ; my $i ; $a = $b = 10 ** n; for ( $i = n * 8 + 1 ; $i >= 3 ; $i -= 2 ) { $a = int ( int ( $i / 2 ) * ( $a + $b * 2 ) / $i ); } $a -= $b ; print ( "3. $a

" ); use strict ; use Math::BigInt lib => "GMP" ; my $a = Math::BigInt->new( 10 )->bpow(n); my $b = $a->copy (); my $i ; my $t ; for ( $i = n * 8 + 1 ; $i >= 3 ; $i -= 2 ) { $t = $b->copy (); $a->badd ( $t ); $a->badd ( $t ); $t = Math::BigInt->new( int ( $i / 2 )); $t->bmul ( $a ); $t->bdiv ( $i ); $a = $t ; } $a->bsub ( $b ); print ( "3. $a

" );

いい加減なまとめ 現状では、気軽に多倍長演算を享受したい時は ruby か python がおすすめです。perl の bigint は 速度がどうでもいいときだけ使いましょう 速度が重要なら GMP とあわせて使いましょう 。ソースを書くのが面倒でもそれなりに速く多倍長演算したいときは GMP がよさそうです。

以下追記: H.I. 2008/01/17 10:09

「use bigint lib => 'GMP'」と書くことができて、GMPで

operator/constant overload をしてくれるみたいです。 との情報をいただきました。Perl では記述性と速度を両取りする選択肢もあるようです。Perl はさすがですね。円周率 10000 桁で試したところ、10 秒でした。GMP を直接たたくより若干遅い *1 ようですが、記述性があがる方がいいですね。

あと、すべて実時間で計測してます。プロセスの初期化時間やコンパイル時間が含まれますので、0.0x のような小さい数値はあてにしないでください。