-- Programming With Prime Numbers
-- https://programmingpraxis.files.wordpress.com/
-- 2012/09/programmingwithprimenumbers.pdf
import Control.Monad (forM_, when)
import Control.Monad.ST
import Data.Array.ST
import Data.Array.Unboxed
import Data.List (sort)
ancientSieve :: Int -> UArray Int Bool
ancientSieve n = runSTUArray $ do
bits <- newArray (2, n) True
forM_ [2 .. n] $ \p -> do
isPrime <- readArray bits p
when isPrime $ do
forM_ [2*p, 3*p .. n] $ \i -> do
writeArray bits i False
return bits
ancientPrimes :: Int -> [Int]
ancientPrimes n = [p | (p, True) <-
assocs $ ancientSieve n]
sieve :: Int -> UArray Int Bool
sieve n = runSTUArray $ do
let m = (n-1) `div` 2
r = floor . sqrt $ fromIntegral n
bits <- newArray (0, m-1) True
forM_ [0 .. r `div` 2 - 1] $ \i -> do
isPrime <- readArray bits i
when isPrime $ do
let a = 2*i*i + 6*i + 3
b = 2*i*i + 8*i + 6
forM_ [a, b .. (m-1)] $ \j -> do
writeArray bits j False
return bits
primes :: Int -> [Int]
primes n = 2 : [2*i+3 | (i, True) <- assocs $ sieve n]
tdPrime :: Int -> Bool
tdPrime n = prime (2:[3,5..])
where prime (d:ds)
| n < d * d = True
| n `mod` d == 0 = False
| otherwise = prime ds
tdFactors :: Int -> [Int]
tdFactors n = facts n (2:[3,5..])
where facts n (f:fs)
| n < f * f = [n]
| n `mod` f == 0 =
f : facts (n `div` f) (f:fs)
| otherwise = facts n fs
powmod :: Integer -> Integer -> Integer -> Integer
powmod b e m =
let times p q = (p*q) `mod` m
pow b e x
| e == 0 = x
| even e = pow (times b b)
(e `div` 2) x
| otherwise = pow (times b b)
(e `div` 2) (times b x)
in pow b e 1
isSpsp :: Integer -> Integer -> Bool
isSpsp n a =
let getDandS d s =
if even d then getDandS (d `div` 2) (s+1)
else (d, s)
spsp (d, s) =
let t = powmod a d n
in if t == 1 then True else doSpsp t s
doSpsp t s
| s == 0 = False
| t == (n-1) = True
| otherwise = doSpsp ((t*t) `mod` n) (s-1)
in spsp $ getDandS (n-1) 0
isPrime :: Integer -> Bool
isPrime n =
let ps = [2,3,5,7,11,13,17,19,23,29,31,37,41,
43,47,53,59,61,67,71,73,79,83,89,97]
in n `elem` ps || all (isSpsp n) ps
rhoFactor :: Integer -> Integer -> Integer
rhoFactor n c =
let f x = (x*x+c) `mod` n
fact t h
| d == 1 = fact t' h'
| d == n = rhoFactor n (c+1)
| isPrime d = d
| otherwise = rhoFactor d (c+1)
where
t' = f t
h' = f (f h)
d = gcd (t' - h') n
in fact 2 2
rhoFactors :: Integer -> [Integer]
rhoFactors n =
let facts n
| n == 2 = [2]
| even n = 2 : facts (n `div` 2)
| isPrime n = [n]
| otherwise = let f = rhoFactor n 1
in f : facts (n `div` f)
in sort $ facts n
main = do
print $ ancientPrimes 100
print $ primes 100
print $ length $ primes 1000000
print $ tdPrime 716151937
print $ tdFactors 8051
print $ powmod 437 13 1741
print $ isSpsp 2047 2
print $ isPrime 600851475143
print $ isPrime 2305843009213693951
print $ rhoFactors 600851475143