実装したので,メモ.
実装といっても,単純なアルゴリズムなので,コードは至極シンプル.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
import System.Random (randomRIO)
solovayStrassen :: Integer -> IO Bool
solovayStrassen n = return.isProbablyPrime n =<< randomRIO (1,n-1)
isProbablyPrime :: (Integral a) => a -> a -> Bool
isProbablyPrime n a
| gcd a n /= 1 = False
| otherwise = powMod a (div (n-1) 2) n == mod (jacobi a n) n
jacobi :: Integral a => a -> a -> a
jacobi a n | a < 0 && mod n 4 == 1 = jacobi (-a) n
| a < 0 && mod n 4 == 3 = - jacobi (-a) n
| a < 2 = a
| even a && (mod n 8 == 1 || mod n 8 == 7) = jacobi (div a 2) n
| even a && (mod n 8 == 3 || mod n 8 == 5) = - jacobi (div a 2) n
| mod a 4 == 3 && mod n 4 == 3 = - jacobi (mod n a) a
| otherwise = jacobi (mod n a) a
-- a^n (mod p)
powMod :: (Integral a, Integral b) => a -> b -> a -> a
powMod a n p | n == 0 = 1
| even n = powMod (mod (a*a) p) (div n 2) p
| otherwise = (a * powMod a (n-1) p)`mod` p
main :: IO ()
main = print =<< solovayStrassen (2 ^ m26 - 1)
where m26 = 23209 -- 26th Mersenne prime
m27 = 44497 -- 27th Mersenne prime
|
Haskellが整数乗算にFFTを使用していれば,計算量はO( (log n)^2 log log n)のはず.
ちなみに,素数の入力に対しては常にTrue,合成数に対してはFalseとなる確率が1/2より大きい.
作成者
Toru Mano
最終更新時刻
2023-01-01
(c70d5a1)