Reputation: 2674
Problem 3 of Project Euler says: The prime factors of 13195 are 5, 7, 13 and 29. What is the largest prime factor of the number 600851475143?
I made a lazy list of primes, then I do a takeWhile they are less than the square root of 600851475143, and test each prime to see if it is a factor.
primes :: [Integer]
primes = sieve [2..]
where
sieve (p:xs) = p : sieve [x|x <- xs, x `mod` p > 0]
primeFactors :: Integer -> Integer
primeFactors x = last $ filter (\y -> x `mod` y == 0) $ takeWhile (< floor (sqrt x)) $ primes
However, I get an error with (< floor (sqrt x))
:
projecteuler.hs:34:70:
No instance for (RealFrac Integer) arising from a use of `floor'
Possible fix: add an instance declaration for (RealFrac Integer)
In the second argument of `(<)', namely `floor (sqrt x)'
In the first argument of `takeWhile', namely `(< floor (sqrt x))'
In the expression: takeWhile (< floor (sqrt x))
projecteuler.hs:34:77:
No instance for (Floating Integer) arising from a use of `sqrt'
Possible fix: add an instance declaration for (Floating Integer)
In the first argument of `floor', namely `(sqrt x)'
In the second argument of `(<)', namely `floor (sqrt x)'
In the first argument of `takeWhile', namely `(< floor (sqrt x))'
This is weird: :t floor
gives me (Integral b, RealFrac a) => a -> b
, which means that this floor should be returning a integer. How can I add an instance declaration (or do whatever is necessary to fix this?)
Also, any suggestions on code optimization are greatly appreciated :)
Edit: this has been solved, and now I am cleaning it up. I've encapsulated everything inside of the main function, so it looks like this:
p003primeFactors :: Integer -> [Integer]
p003primeFactors x = filter (\y -> x `mod` y == 0) $ takeWhile (\p -> p^2 <= x) $ primes
where
primes :: [Integer]
primes = sieve [2..]
where
sieve (p:xs) = p : sieve [x|x <- xs, x `mod` p > 0]
Is this the best way to create namespaces for functions like this?
Upvotes: 1
Views: 725
Reputation: 19637
The actual problem is the second error. (The first is just a consequence.) The x
is an Integer
, so you cannot call sqrt
on it, because that requires a Floating
instance.
Try:
takeWhile (< floor (sqrt (fromIntegral x)))
This will convert x
from an integer to a floating point number so that sqrt
can operate on it.
Upvotes: 3