Add `isPrime` and `divides` to Euler.hs.

This commit is contained in:
Jesse D. McDonald 2015-09-02 20:06:03 -05:00
parent 39772d8b2b
commit 7d015132e9
7 changed files with 21 additions and 30 deletions

View File

@ -9,9 +9,11 @@ module Euler
, whenM , whenM
, unlessM , unlessM
, primesTo , primesTo
, isPrimeArray , isPrimeArrayTo
, primes , primes
, isPrime
, primeFactors , primeFactors
, divides
, zipArraysWith , zipArraysWith
, RangeIx(..) , RangeIx(..)
, divisors , divisors
@ -60,26 +62,30 @@ whenM mc m = mc >>= (\c -> when c m)
unlessM mc m = mc >>= (\c -> unless c m) unlessM mc m = mc >>= (\c -> unless c m)
primesTo n = LST.runST $ do primesTo n = LST.runST $ do
isPrime <- LST.strictToLazyST (newArray (2, n) 1 :: ST s (STUArray s Integer Word8)) isPrimeArr <- LST.strictToLazyST (newArray (2, n) 1 :: ST s (STUArray s Integer Word8))
let primesFrom m = if m > n then return [] else do let primesFrom m = if m > n then return [] else do
p <- LST.strictToLazyST (readArray isPrime m) p <- LST.strictToLazyST (readArray isPrimeArr m)
if p == 0 then primesFrom (m+1) else do if p == 0 then primesFrom (m+1) else fmap (m:) $ do
LST.strictToLazyST $ forM_ [2*m,3*m..n] $ \i -> writeArray isPrime i 0 LST.strictToLazyST $ forM_ [2*m,3*m..n] $ \i -> do
(m:) <$> primesFrom (m+1) writeArray isPrimeArr i 0
primesFrom (m+1)
primesFrom 2 primesFrom 2
isPrimeArray n = runSTUArray $ do isPrimeArrayTo n = runSTUArray $ do
isPrime <- newArray (2, n) 1 :: ST s (STUArray s Integer Word8) isPrimeArr <- newArray (2, n) 1 :: ST s (STUArray s Integer Word8)
forM_ [2..n] $ \m -> whenM ((/= 0) <$> readArray isPrime m) $ do forM_ [2..n] $ \m -> whenM ((/= 0) <$> readArray isPrimeArr m) $ do
forM_ [2*m,3*m..n] $ \i -> writeArray isPrime i 0 forM_ [2*m,3*m..n] $ \i -> writeArray isPrimeArr i 0
return isPrime return isPrimeArr
primes :: [Integer] primes :: [Integer]
--primes = let go (!p:xs) = p : go [ x | x <- xs, x `mod` p /= 0 ] in go [2..] --primes = let go (!p:xs) = p : go [ x | x <- xs, not (p `divides` x) ] in go [2..]
primes = go 1000000 primes = go 1000000
where where
go n = primesTo n ++ dropWhile (<= n) (go (2*n)) go n = primesTo n ++ dropWhile (<= n) (go (2*n))
isPrime :: Integer -> Bool
isPrime n = n >= 2 && not (any (`divides` n) $ takeWhile ((<=n).(^2)) primes)
primeFactors :: Integer -> [Integer] primeFactors :: Integer -> [Integer]
primeFactors n = go n primes primeFactors n = go n primes
where where
@ -90,6 +96,9 @@ primeFactors n = go n primes
| (q, 0) <- n `divMod` p = p : go q (p:ps) | (q, 0) <- n `divMod` p = p : go q (p:ps)
| otherwise = go n ps | otherwise = go n ps
divides :: Integral a => a -> a -> Bool
a `divides` b = b `mod` a == 0
class Ix a => RangeIx a where class Ix a => RangeIx a where
intersectBounds :: (a, a) -> (a, a) -> (a, a) intersectBounds :: (a, a) -> (a, a) -> (a, a)

View File

@ -8,9 +8,6 @@
import Euler import Euler
isPrime :: Integer -> Bool
isPrime n = n >= 2 && not (any (\p -> n `mod` p == 0) $ takeWhile (< n) primes)
nPrimes a b = length $ takeWhile isPrime $ map (\n -> n^2 + a*n + b) [0..] nPrimes a b = length $ takeWhile isPrime $ map (\n -> n^2 + a*n + b) [0..]
main = print $ uncurry (*) $ snd $ maximumBy (compare `on` fst) $ main = print $ uncurry (*) $ snd $ maximumBy (compare `on` fst) $

View File

@ -17,7 +17,5 @@ rotations n = map (fromDigits . take (length digits))
main = do main = do
let limit = 1000000 - 1 let limit = 1000000 - 1
let isPrimeArr = isPrimeArray limit
let isPrime n = (isPrimeArr!n) /= 0
let circular n = all isPrime $ rotations n let circular n = all isPrime $ rotations n
print $ length $ filter circular [2..limit] print $ length $ filter circular [2..limit]

View File

@ -5,8 +5,4 @@ import Euler
import Data.Array.Unboxed import Data.Array.Unboxed
truncations n = map fromDigits $ filter (not . null) $ inits (toDigits n) ++ tails (toDigits n) truncations n = map fromDigits $ filter (not . null) $ inits (toDigits n) ++ tails (toDigits n)
isPrimeArr = isPrimeArray 1000000
isPrime n = n >= 2 && isPrimeArr!n /= 0
main = print $ sum $ take 11 $ filter (all isPrime . truncations) [11..] main = print $ sum $ take 11 $ filter (all isPrime . truncations) [11..]

View File

@ -9,7 +9,4 @@ import Euler
pandigitals = map fromDigits $ go 9 pandigitals = map fromDigits $ go 9
where go 0 = []; go n = reverse (sort (permutations [1..n])) ++ go (n-1) where go 0 = []; go n = reverse (sort (permutations [1..n])) ++ go (n-1)
isPrime n = not $ any (\p -> n `mod` p == 0) $
takeWhile (<= floor (sqrt (fromIntegral n))) primes
main = print $ head $ filter isPrime pandigitals main = print $ head $ filter isPrime pandigitals

View File

@ -14,10 +14,6 @@
import Euler import Euler
import Debug.Trace import Debug.Trace
isPrime :: Integer -> Bool
isPrime n = n >= 2 && all (\p -> n `mod` p /= 0) smallPrimes
where smallPrimes = takeWhile (<= floor (sqrt (fromIntegral n))) primes
main = print $ head $ do main = print $ head $ do
base <- primes base <- primes
let digits = toDigits base let digits = toDigits base

View File

@ -18,8 +18,6 @@ module Main where
import Euler import Euler
isPrime n = n >= 2 && not (any (\p -> n `mod` p == 0) $ takeWhile ((<= n) . (^2)) primes)
-- diagonals of an m by m spiral; m = 2*n + 1. -- diagonals of an m by m spiral; m = 2*n + 1.
allDiags = 1 : zipWith (+) allDiags (concat $ map (replicate 4) [2,4..]) allDiags = 1 : zipWith (+) allDiags (concat $ map (replicate 4) [2,4..])
allDiags' = map isPrime allDiags allDiags' = map isPrime allDiags