refactored 3 and 12 for speed and readability

1 parent 29a929a commit 08b6f9aa07b9e647382a72863bf0f3fef65ef506 Eric Wilson committed Jan 12, 2011
Showing with 46 additions and 51 deletions.
1. +12 −20 003.hs
2. +10 −6 012.hs
3. +14 −15 EulerMath/Divisors.hs
4. +1 −1 EulerMath/Fib.hs
5. +9 −9 EulerMath/Primes.hs
32 003.hs
 @@ -1,27 +1,19 @@ -{-- - There must be a better way. - Sorry this is unreadable, and resorts to using Integer. ---} +import EulerMath.Primes +import EulerMath.Divisors -isPrime :: Integer -> Bool -isPrime = null . smallFactors +firstPrimeFactor :: Integer -> Integer +firstPrimeFactor n = head [ d | d <- primesUpTo n, mod n d == 0] -smallFactors :: Integer -> [Integer] -smallFactors n = takeWhile (\d -> d*d <= n) \$ factors n - where factors n = [ d | d <- [2..n-1], mod n d == 0] - -smallPrimeFactors :: Integer -> [Integer] -smallPrimeFactors = filter isPrime . smallFactors - -reduceByList :: Integer -> [Integer] -> Integer -reduceByList big [] = big -reduceByList big (div:divs) = reduceByList (reduce big div) divs +reduceByNextPrime :: Integer -> Integer +reduceByNextPrime n = reduce n (firstPrimeFactor n) where reduce num div = if mod num div /= 0 then num else reduce (quot num div) div - + euler3 :: Integer -> Integer -euler3 n = if reduceByList n (smallPrimeFactors n) == 1 - then last (smallPrimeFactors n) - else reduceByList n (smallPrimeFactors n) +euler3 n = + if reduced == 1 + then n + else euler3' reduced + where reduced = reduceByNextPrime n
16 012.hs
 @@ -9,14 +9,18 @@ triDivs n = if (even n) then numDivs (quot n 2) * numDivs (n+1) else numDivs n * numDivs (quot (n+1) 2) -euler12 :: Int -> (Int, Int, Int) -euler12 n = head \$ filter (tripleAbove n) \$ map triDivTriple [1..] +numDivs :: Int -> Int +numDivs n = product \$ map (+1) \$ primeFactorMultiplicity n + +primeFactorMultiplicity :: Int -> [Int] +primeFactorMultiplicity = map snd . primeFactorizationFS primes1000 + where primes1000 = primesUpTo 1000 + +euler12 :: Int -> Int +euler12 n = (\ (_, t, _) -> t) . head \$ filter (tripleAbove n) \$ map triDivTriple [1..] where triDivTriple m = (m, tri m, triDivs m) tripleAbove n (_, _, m) = (m > n) -primeFactorsWithMult :: Int -> [Int] -primeFactorsWithMult = map snd . primeFactorization -numDivs :: Int -> Int -numDivs n = product \$ map (+1) \$ primeFactorsWithMult n +
 @@ -1,33 +1,32 @@ module EulerMath.Divisors ( divisors , primeFactorization +, primeFactorizationFS +, primeFactors ) where import EulerMath.Primes -{-- -This is good for primes under 1000 currently. -A more general primeFactorization, both fast and -sufficient for larger numbers would be nice. ---} - -divisors :: Integer -> [Integer] +divisors :: (Integral a) => a -> [a] divisors n = [ d | d <- [1..n], mod n d == 0 ] -primes1000 :: [Int] -primes1000 = primesUpTo 1000 +primeFactors :: (Integral a) => a -> [a] +primeFactors n = [ d | d <- primesUpTo n, mod n d == 0 ] + +primeFactorsFS :: (Integral a) => [a] -> a -> [a] +primeFactorsFS smallPrimes n = [ d | d <- smallPrimes, mod n d == 0 ] --- replacing primes1000 with primesUpTo n kills performance. -primeFactors :: Int -> [Int] -primeFactors n = [ d | d <- primes1000, mod n d == 0 ] -timesDivides :: Int -> Int -> Int +timesDivides :: (Integral a) => a -> a -> a timesDivides d n = timesDividesIt d n 0 where timesDividesIt d n i = if (mod n d /= 0) then i else timesDividesIt d (quot n d) (i+1) -primeFactorization :: Int -> [(Int, Int)] -primeFactorization n = map (\p -> (p, timesDivides p n)) \$ primeFactors n +primeFactorization :: (Integral a) => a -> [(a, a)] +primeFactorization n = map (\p -> (p, timesDivides p n)) \$ primeFactors n + +primeFactorizationFS :: (Integral a) => [a] -> a -> [(a, a)] +primeFactorizationFS smallPrimes n = map (\p -> (p, timesDivides p n)) \$ primeFactorsFS smallPrimes n
 @@ -2,7 +2,7 @@ module EulerMath.Fib ( fib ) where -fib :: Int -> Int +fib :: (Integral a) => a -> a fib n = fst \$ fibPair n where fibPair 1 = (1,1)
 @@ -1,32 +1,32 @@ module EulerMath.Primes ( nPrimes , primesUpTo -, primesBelowRoot +, primesUpToRoot , isPrime ) where -divides :: Int -> Int -> Bool +divides :: (Integral a) => a -> a -> Bool divides d n = mod n d == 0 -sieve :: [Int] -> [Int] -> [Int] +sieve :: (Integral a) => [a] -> [a] -> [a] sieve [] ys = ys sieve (x:xs) ys = x : sieve xs (filter (not . divides x) ys) -genPrimes :: Int -> [Int] +genPrimes :: (Integral a) => a -> [a] genPrimes n = iterSieve [2,3] n where iterSieve xs 0 = xs iterSieve xs n = iterSieve (sieveRange xs (last xs) ((last xs)^2)) (n-1) sieveRange xs n m = sieve xs [n..m] -nPrimes :: Int -> [Int] +nPrimes :: (Integral a) => Int -> [a] nPrimes n = take n \$ genPrimes 4 -primesUpTo :: Int -> [Int] +primesUpTo :: (Integral a) => a -> [a] primesUpTo n = takeWhile (<=n) \$ genPrimes 4 -primesBelowRoot :: Int -> [Int] -primesBelowRoot n = takeWhile (\d -> d^2 <= n) \$ genPrimes 4 +primesUpToRoot :: (Integral a) => a -> [a] +primesUpToRoot n = takeWhile (\d -> d^2 <= n) \$ genPrimes 4 -isPrime :: Int -> Bool +isPrime :: (Integral a) => a -> Bool isPrime n = any (==n) \$ primesUpTo (n+1)