みけCATのにっき(仮)
つれづれなるまゝに、日くらし、PCにむかひて、心に移りゆくよしなし事を、そこはかとなく書きつくれば、あやしうこそものぐるほしけれ。
(本当か!?)
出典

ミラー・ラビンテスト

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

ミラー・ラビンテスト

投稿記事 by みけCAT » 12年前

Perlでミラー・ラビンテストを実装してみました。
参考:Pythonを使って高速素数判定をしてみる
[search=google]ミラー・ラビンテスト[/search]

CODE:

#!/usr/bin/perl

use strict;
use Math::BigInt;
use Math::BigInt::Random qw/ random_bigint /;

my($result);
if(@ARGV==0 || @ARGV>2) {
	die("Usage: miraarabinntesuto.pl  [loop count]\n");
} elsif(@ARGV>=2) {
	$result=&miraarabinntesuto($ARGV[0],$ARGV[1]);
} else {
	$result=&miraarabinntesuto($ARGV[0]);
}
print $result?"Prime!\n":"Not prime...\n";
exit(0);

# http://d.hatena.ne.jp/pashango_p/20090704/1246692091

# if the number is prime, return 1. otherwise, return 0.
sub miraarabinntesuto {
	my($q,$loopnum)=@_;
	my($s,$d,$a,$r,$i,$j,$ok);
	my($powresult,$pownow,$powcurrent);
	if(!$loopnum){$loopnum=50;}
	$q=Math::BigInt->new($q);
	if($qnew("2");
		$a=random_bigint( min => "1", max => $q-1);

		# 「pow(a,d,q) != 1」がTrueだった場合
		$powresult=Math::BigInt->new("1");
		$pownow=$a;
		$powcurrent=$d;
		while($powcurrent>0) {
			if($powcurrent & 1){$powresult=($powresult*$pownow)%$q;}
			$pownow=($pownow*$pownow)%$q;
			$powcurrent>>=1;
		}
		if($powresult==1) {next;}

		# 0~s-1までのカウンタをrとし、すべての「pow(a, 2**(r*d), d)!=-1」がTrue
		# もしかして:pow(a, d*(2**r), q)!=-1
		$ok=1;
		# powresultは前の結果を利用
		for($r=0;$r [ループ回数]
の形で使います。
実際に実行してみると、素数10000000000000000000009の判定を約3秒で終わらせることができました。(デフォルトのとき)

しかし、参考ページの下の300桁の素数の判定では、1回ループに設定しても約20秒かかりました。
50回ループすると約17分かかる計算です。
これは、常識的には一瞬とは捉えられない気がします。
オフトピック
miraarabinntesutoはネタです。

コメントはまだありません。