ミラーラビン素数判定法についてメモ
素数判定
前提知識
フェルマーの小定理
証明略
もう一つ
証明
式を変形すると
pは素数のため2つの数の積で表されるとしたら
a = 0の場合に
よって
フェルマーテスト
適当に
成り立っていなければ確実に素数でないといえる
なぜならフェルマーの小定理の対偶をとると、
となるため
ただし、成り立っていても確実に素数かどうかはわからない
たくさん
うまくいかないaを取ってきてしまう確率は基本的に
フェルマーテストの問題点
いくらaをたくさんとってきても
全部
561, 1105など
ミラーラビンテスト
pを奇数の素数とする
するとp-1は偶数なので
と置くことができる
このときに以下が成り立つ
証明
フェルマーの小定理より
この平方根つまり
-1の場合は、(7)の後者の式が成り立つ
1の場合はさらに平方根を考えていく。
そうして考えていったときにr=0になるまでひとつも-1になるものが存在しなかったとする。(全部1)
このとき
これは(5)の前者の式を満たす
ミラーラビンテストは(5)の対偶を使う
これもこの条件を満たしていれば確実に合成数だと言えるが、
満たしていなければ確実に素数だといえるわけではない
これもたくさんaを取ってきてすべて満たしていないか調べる
うまくいかないaを選んでしまう確率は最大で
決定的アルゴリズム
求めたい数nが
aは
参考
実装
fn modpow(base: i64, mut exp: i64, m: i64) -> i64 {
let mut ret = 1;
let mut pow = base;
while exp != 0 {
if exp & 1 != 0 {
ret = ((ret as i128 * pow as i128) % m as i128) as i64;
}
pow = ((pow as i128 * pow as i128) % m as i128) as i64;
exp >>= 1;
}
ret
}
fn rabin_miller(n: i64) -> bool {
if n <= 2 {
return n == 2
}
if n % 2 == 0 {
return false;
}
let mut s = 0;
let mut t = n-1;
while t % 2 == 0 {
s += 1;
t /= 2;
}
let is_prime = |a| {
let mut x = modpow(a, t, n);
if x == 1 || x == n-1 {
return true;
}
for _ in 0..s-1 {
x = ((x as i128 * x as i128) % n as i128) as i64;
if x == n-1 {
return true;
}
}
false
};
for &a in &[2, 325, 9375, 28178, 450775, 9780504, 1795265022] {
if a >= n {
break;
}
if !is_prime(a) {
return false;
}
}
true
}
Discussion
分かりやすい解説ありがとうございます。
このページのおかげでミラーラビンを理解することができました。
実装で、
a >= n
の時にbreakしていますが、 のRemarksに、breakしてはいけないと書いてありました。
a ← a mod n
としてテストするそうで、
その際a=0になったらis_primeをtrueとして扱うのが正しいそうです。
こちらで確認したところ、breakする実装では、
n=4033の時に素数ではないという誤判定になりました(実際は素数)。
もう一点、
のところ、n=4,759,123,141の時はだめなようです。
nは合成数(48781×97561)ですが、素数に判定されてしまいました。
n<4,759,123,141とするのが正しそうです。