patternMinor
Project Euler Problem 57 in Haskell
Viewed 0 times
problemprojecteulerhaskell
Problem
I'm very new to Haskell, and I would like some feedback on my coding style. Is there anything here that could be made more elegant or concise?
This is my solution to Project Euler Problem 57.
It is possible to show that the square root of two can be expressed as an infinite continued fraction.
$$\sqrt 2 = 1 + \dfrac{1}{2 + \dfrac{1}{2 + \dfrac{1}{2 + \ldots}}} = 1.414213\ldots$$
By expanding this for the first four iterations, we get:
1 + 1/2 = 3/2 = 1.5
1 + 1/(2 + 1/2) = 7/5 = 1.4
1 + 1/(2 + 1/(2 + 1/2)) = 17/12 = 1.41666...
1 + 1/(2 + 1/(2 + 1/(2 + 1/2))) = 41/29 = 1.41379...
The next three expansions are 99/70, 239/169, and 577/408, but the eighth expansion, 1393/985, is the first example where the number of digits in the numerator exceeds the number of digits in the denominator.
In the first one-thousand expansions, how many fractions contain a numerator with more digits than denominator?
This is my solution to Project Euler Problem 57.
It is possible to show that the square root of two can be expressed as an infinite continued fraction.
$$\sqrt 2 = 1 + \dfrac{1}{2 + \dfrac{1}{2 + \dfrac{1}{2 + \ldots}}} = 1.414213\ldots$$
By expanding this for the first four iterations, we get:
1 + 1/2 = 3/2 = 1.5
1 + 1/(2 + 1/2) = 7/5 = 1.4
1 + 1/(2 + 1/(2 + 1/2)) = 17/12 = 1.41666...
1 + 1/(2 + 1/(2 + 1/(2 + 1/2))) = 41/29 = 1.41379...
The next three expansions are 99/70, 239/169, and 577/408, but the eighth expansion, 1393/985, is the first example where the number of digits in the numerator exceeds the number of digits in the denominator.
In the first one-thousand expansions, how many fractions contain a numerator with more digits than denominator?
numerator =
3 : 7 : zipWith (+) numerator (map ((*) 2) (tail numerator))
denominator =
2 : 5 : zipWith (+) denominator (map ((*) 2) (tail denominator))
numDigits :: Integer -> Int
numDigits = length . show
moreDigits :: Integer -> Integer -> Bool
moreDigits x y = (numDigits x) > (numDigits y)
countTrue :: [Bool] -> Int
countTrue = length . filter ((&&) True)
pe_057 = countTrue $
take 1000 (zipWith moreDigits numerator denominator)
main :: IO ()
main = do
print pe_057Solution
I like the way you defined
I think that using
I don't think that
If you use
I also implemented an alternative solution. The main difference with respect to yours is that I generare a list of (numerator, denominator) pairs instead of having two separate lists.
numerator and denominator.I think that using
length . show to compute the number of digits is a bit overkill. Do you really need to convert the number to a string to do that? I think that using a logarithm is better.log10 = logBase 10
numDigits = ceiling . log10 . (+) 1I don't think that
moreDigits is a good name. What about longerThan?countTrue style doesn't look too functional. What about count :: (a -> bool) -> [a] -> Int? In that way you'll have a function you can use to count the number of items matching a predicate in any list, instead of having to compute first the a list of boolean values.If you use
count you'll need to rearrange change moreDigits :: (Int, Int) -> bool and pe_057.pe_057 = countTrue moreDigits $
take 1000 (zip numerator denominator)I also implemented an alternative solution. The main difference with respect to yours is that I generare a list of (numerator, denominator) pairs instead of having two separate lists.
nextFraction :: (Integer, Integer) -> (Integer, Integer)
nextFraction (n, d) = (2*d + n, d + n)
generator :: [(Integer, Integer)] -> [(Integer,Integer)]
generator (x: xs) = nextFraction x : generator xs
fractions :: [(Integer,Integer)]
fractions = (3,2) : generator fractions
numeratorLonger :: (Integer,Integer) -> Bool
numeratorLonger (n,d) = (numDigits n) > (numDigits d)
numDigits :: Integer -> Int
numDigits n = numDigitsImpl (div n 10) 1
numDigitsImpl :: Integer -> Int -> Int
numDigitsImpl n counter = if next == 0
then counter
else numDigitsImpl next (counter + 1)
where next = div n 10
count :: (a -> Bool) -> [a] -> Int
count f xs = length $ filter id $ map f xs
projectEuler57 n = count numeratorLonger $ take n fractions
main :: IO ()
main = do
print $ projectEuler57 1000Code Snippets
log10 = logBase 10
numDigits = ceiling . log10 . (+) 1pe_057 = countTrue moreDigits $
take 1000 (zip numerator denominator)nextFraction :: (Integer, Integer) -> (Integer, Integer)
nextFraction (n, d) = (2*d + n, d + n)
generator :: [(Integer, Integer)] -> [(Integer,Integer)]
generator (x: xs) = nextFraction x : generator xs
fractions :: [(Integer,Integer)]
fractions = (3,2) : generator fractions
numeratorLonger :: (Integer,Integer) -> Bool
numeratorLonger (n,d) = (numDigits n) > (numDigits d)
numDigits :: Integer -> Int
numDigits n = numDigitsImpl (div n 10) 1
numDigitsImpl :: Integer -> Int -> Int
numDigitsImpl n counter = if next == 0
then counter
else numDigitsImpl next (counter + 1)
where next = div n 10
count :: (a -> Bool) -> [a] -> Int
count f xs = length $ filter id $ map f xs
projectEuler57 n = count numeratorLonger $ take n fractions
main :: IO ()
main = do
print $ projectEuler57 1000Context
StackExchange Code Review Q#64916, answer score: 3
Revisions (0)
No revisions yet.