Project Euler

Project Euler: Problem 10

Thank you for your patience as you all (I'm sure) anxiously await my next posting.

Not only has it been a really long time since I posted something technical, it's also been a really long time since I posted a Project Euler solution. On that note, let's go over the challenge:

The sum of the primes below 10 is 2 + 3 + 5 + 7 = 17.
Find the sum of all the primes below two million.

Seems simple enough doesn't it? Let's find out. For Python the code is:

  1. #!/usr/bin/python
  2. """
  3. Python based code solution to problem 10 of project euler.
  4. """
  5. import math
  6.  
  7. def is_prime(divided):
  8. divisor = 3
  9. sqrt_divided = int(math.sqrt(divided))
  10. while divisor <= sqrt_divided:
  11. if divided % divisor == 0:
  12. return False
  13.  
  14. divisor += 2
  15.  
  16. return True
  17.  
  18. if __name__ == "__main__":
  19. print sum([2] + [x for x in xrange(3,2000000+1, +2) if is_prime(x)])

And for Haskell the code looks like:

  1. module Main where
  2.  
  3. prime_wrapper:: Int -> [Int]
  4. prime_wrapper divided = prime 3 divided (round . sqrt. fromIntegral $ divided)
  5.  
  6. prime:: Int -> Int -> Int -> [Int]
  7. prime divisor divided sqrt_divided
  8. | divisor > sqrt_divided = [divided]
  9. | mod divided divisor == 0 = []
  10. | otherwise = next_prime
  11. where next_prime = prime (divisor + 2) divided sqrt_divided
  12.  
  13. main :: IO ()
  14. main = print $ sum primes
  15. where primes = 2 : [ x | x <- [3,5..2000000], prime_wrapper x /= [] ]

I will be the first to admit that this problem is a little on the easy side. Mostly because you can reuse the code you created for problems 3 and 7, or at least I did. :)

Even though you and I know that Haskell will execute this code faster than Python, I feel I still need to uphold the tradition of posting my highly inaccurate execution times:

Python: 34.054s
Haskell: 20.690s

Project Euler: Problem 9

Happy New Year Ladies(?) and Geeks

Trying to get the year off to a good start, I'm posting up my solution for the ninth Project Euler problem. I'm not going to spend a lot of time talking about it, because the solution is a pretty easy one. Here is the code in Python:

  1. #!/usr/bin/python3
  2. """
  3. python solution for project euler problem #9.
  4. """
  5.  
  6. print( [a*b*(1000 - b -a) for a in range(1,500+1) for b in range(1,500+1) \
  7. if a * a + b * b == ((1000 -b -a) * (1000 - b - a))][0])

And here is the code in Haskell:

  1. module Main where
  2.  
  3. main :: IO()
  4. main = print . head $ [a*b*(1000-b-a) | a <- [1..500] , b <- [1..500], a ^ 2 + b ^ 2 == (1000 - b - a) ^ 2]

See, it really is that simple. There really isn't anything interesting between to the solutions, but I would like to make a quick note on the luxury of being able to use “head” in Haskell to simplify the whole process. In the Python solution, the answer is generated twice, that's just the nature of the algorithm, and to just get one number, I just ask for the first item in the list. Thanks to Haskell's lazy evaluation, I only have to calculate the answer once, and I think this may be reflected in the run times.

So now the part that I know everyone loves to read the most, Times:

python-2.6.6 : .165s
python-3.1.2 : .110s
haskell(runghc) : 1.921s
haskell(compiled) : .086s

Project Euler: Problem 8

The website has problem eight stated as such,“Find the greatest product of five consecutive digits in the 1000-digit number.
73167176531330624919225119674426574742355349194934
96983520312774506326239578318016984801869478851843
85861560789112949495459501737958331952853208805511
12540698747158523863050715693290963295227443043557
66896648950445244523161731856403098711121722383113
62229893423380308135336276614282806444486645238749
30358907296290491560440772390713810515859307960866
70172427121883998797908792274921901699720888093776
65727333001053367881220235421809751254540594752243
52584907711670556013604839586446706324415722155397
53697817977846174064955149290862569321978468622482
83972241375657056057490261407972968652414535100474
82166370484403199890008895243450658541227588666881
16427171479924442928230863465674813919123162824586
17866458359124566529476545682848912883142607690042
24219022671055626321111109370544217506941658960408
07198403850962455444362981230987879927244284909188
84580156166097919133875499200524063689912560717606
05886116467109405077541002256983155200055935729725
71636269561882670428252483600823257530420752963450”

Yeah, looks pretty intimadating to me too. ;) Lucky enough for both of us this really isn't all that hard to figure out.

Python

  1. #!/usr/bin/python3
  2. """
  3. code solution for Euler Project #8
  4. """
  5. import operator
  6. from functools import reduce
  7.  
  8. if __name__ == "__main__":
  9. index = 0
  10. high_score = 0
  11. investigate_this = 7316717653133062491922511967442657474235534919493496983520312774506326239578318016984801869478851843858615607891129494954595017379583319528532088055111254069874715852386305071569329096329522744304355766896648950445244523161731856403098711121722383113622298934233803081353362766142828064444866452387493035890729629049156044077239071381051585930796086670172427121883998797908792274921901699720888093776657273330010533678812202354218097512545405947522435258490771167055601360483958644670632441572215539753697817977846174064955149290862569321978468622482839722413756570560574902614079729686524145351004748216637048440319989000889524345065854122758866688116427171479924442928230863465674813919123162824586178664583591245665294765456828489128831426076900422421902267105562632111110937054421750694165896040807198403850962455444362981230987879927244284909188845801561660979191338754992005240636899125607176060588611646710940507754100225698315520005593572972571636269561882670428252483600823257530420752963450
  12.  
  13.  
  14. digit_list = [int(x) for x in str(investigate_this)]
  15. digit_list_length = len(digit_list)
  16.  
  17. while index < digit_list_length:
  18. if index == 0:
  19. temp_product = reduce(operator.mul, digit_list[index: index +5])
  20. elif index == 1:
  21. temp_product = reduce(operator.mul, digit_list[index - 1: index + 4])
  22. elif index == digit_list_length - 1:
  23. temp_product = reduce(operator.mul, digit_list[index - 4: index + 1])
  24. elif index == digit_list_length - 2:
  25. temp_product = reduce(operator.mul, digit_list[index - 3: index + 2])
  26. else:
  27. temp_product = reduce(operator.mul, digit_list[index -2 : index + 3])
  28.  
  29. if temp_product > high_score:
  30. high_score = temp_product
  31.  
  32. index += 1
  33.  
  34. print(high_score)

For my first attempt I took an approach of having a travelling index and checking both two digits before and two digits after the index. This worked out pretty well except that I needed to add four special use cases (the first two index points and the last two). Some people may say that it's not “pythonic” to use reduce, and in some ways I can agree with it. However, in this case my reduce fuctions really aren't very complicated and I think they look cleaner than using for loops in this instance. Does anyone out there have any opinions?

Haskell

  1. module Main where
  2.  
  3. import Data.Char
  4.  
  5. investigate_this = map digitToInt $ show 7316717653133062491922511967442657474235534919493496983520312774506326239578318016984801869478851843858615607891129494954595017379583319528532088055111254069874715852386305071569329096329522744304355766896648950445244523161731856403098711121722383113622298934233803081353362766142828064444866452387493035890729629049156044077239071381051585930796086670172427121883998797908792274921901699720888093776657273330010533678812202354218097512545405947522435258490771167055601360483958644670632441572215539753697817977846174064955149290862569321978468622482839722413756570560574902614079729686524145351004748216637048440319989000889524345065854122758866688116427171479924442928230863465674813919123162824586178664583591245665294765456828489128831426076900422421902267105562632111110937054421750694165896040807198403850962455444362981230987879927244284909188845801561660979191338754992005240636899125607176060588611646710940507754100225698315520005593572972571636269561882670428252483600823257530420752963450
  6.  
  7. investigate_length = length investigate_this
  8.  
  9. productof5 index
  10. | index >= investigate_length - 4 = []
  11. | otherwise = prod5 : productof5 (index + 1)
  12. where prod5 = product [ investigate_this !! y | y <- [index..(index + 4)]]
  13.  
  14. main :: IO()
  15. main = print . maximum $ productof5 0

In my next solution, I followed the same idea of using a traveling index, but this time I only paid attention to the index and the next four digits. The advantage to this was that I only needed to worry about one special case, and that was if the number of multipliers were less than five total. This did seem to simplify things.

Sorry to all my Perl & Java readers. Life is kind of chaotic at the moment and I only really had the energy to do these two languages. One day I hope to revisit this problem in those languages, and when I do I'll update this post with the new code additions.

I realize in the last few times I've posted project euler solution I haven't said anything so just to nail this thought home amongst the people reading this. I look forward to hearing any and all constructive comments regarding algorythms and code. Oh, and one more thing, I apologize in advance for the formatting of the rather large number.

Project Euler: Problem 7

Here is the seventh installment of this series. And just to keep things interesting I'm going to do something different this time around. I still performed the solutions for Haskell, Java, and Perl (if you want to view them check out my github repo), but instead of posting the code for all four languages, I'm going to be talking about the evolution of my Python solution, showing you all three revisions, and talking briefly about how or why things changed.

Python code:
Solution 1:

  1. #!/usr/bin/python3
  2.  
  3. import math
  4.  
  5. def is_prime(divided):
  6. divisor = 3
  7. sqrt_divided = math.sqrt(divided)
  8. while divisor <= sqrt_divided:
  9. if divided % divisor == 0:
  10. return False
  11.  
  12. divisor += 2
  13. return True
  14.  
  15. if __name__ == "__main__":
  16. prime_list = [2]
  17. count = 3
  18.  
  19. while len(prime_list) < 10001:
  20. if is_prime(count) == True:
  21. prime_list.append(count)
  22.  
  23. count += 2
  24.  
  25. print(prime_list[-1])

Looking at this first solution, we see that it follows the Haskell solution quite closely. This is of course not an accident; I'm lazy. ;) And since I'm still learning Haskell, I find it easier to learn the basics of a language through translation. So this Python solution was my first solution, which I then translated to Haskell.

Solution 2:

  1. #!/usr/bin/python3
  2.  
  3. import math
  4.  
  5. def is_prime(divided):
  6. divisor = 3
  7. sqrt_divided = math.sqrt(divided)
  8. while divisor <= sqrt_divided:
  9. if divided % divisor == 0:
  10. return False
  11.  
  12. divisor += 2
  13. return True
  14.  
  15.  
  16. if __name__ == "__main__":
  17. count = 1 #to substitute the prime number 2 in the example
  18. last = 0
  19. iterator = 3
  20.  
  21. while count < 10001:
  22. if is_prime(iterator):
  23. count += 1
  24. last = iterator
  25.  
  26. iterator += 2
  27.  
  28. print(last)

So in coming up with my Java solution, I didn't want to deal with trying to come up with a linked list-based solution for number storage. At which point I had the great thought: why not just hold the last number to be prime, and not all primes. Spending all this time with lists and arrays instead of just straight Ints has really played with my thought patterns. So after I wrote up the Java solution, I translated it to Python, to see if there would be a reduction in the execution time based on only using Ints instead of a list of Ints. Paint me a little surprised when I saw that the difference was minimal if non-existent most of the time.

Solution 3:

  1. #!/usr/bin/python3
  2.  
  3. import math
  4.  
  5. def is_prime(divided):
  6. divisor = 3
  7. sqrt_divided = int(math.sqrt(divided))
  8. while divisor <= sqrt_divided:
  9. if divided % divisor == 0:
  10. return False
  11.  
  12. divisor += 2
  13. return True
  14.  
  15.  
  16. if __name__ == "__main__":
  17. # using a list to store each int value
  18. data = [1,0,3]
  19.  
  20. while data[0] < 10001:
  21. if is_prime(data[2]):
  22. data[0] += 1
  23. data[1] = data[2]
  24.  
  25. data[2] += 2
  26.  
  27. print(data[1])

After digging into how Python does its memory management, like Lists being mutable while Ints are not, I modified the second solution so that the Ints are now in a list. This way the Python memory manager does not have to create a new variable to store each value. After these changes I got the speed difference I was expecting to see between the first and second revision.

Also, you might have noticed that in the is_prime function, I cast math.sqrt to an Int. As math.sqrt returns a float, every time that comparison happens for the while loop there has to be a conversion of divisor from its current state of int to a float. Math.sqrt returns a float, thus sqrt_divided is a float, and divisor is an int. So every time that while loop cycles again, there has to be a conversion of an int to a float. By casting that float to an int during the variable declaration, I save myself a few thousand cast operations and shave off a couple hundredths of a second from the total run time.

Language Run Times:
Python:
solution 1: .452s
solution 2: .433s
solution 3: .376
Haskell: .187s
Perl : .333s
Java: .128s

I don't think there are enough words in the English language to express my surprise that Java actually had the lowest overall run time on this one. I reran the Java solution a couple of times to see if it was an error, but it's correct. This is something that I will have to dig into more deeply to find out why.

If you made it this far down into the article, hopefully you liked it enough to share it with your friends. Thanks if you do, I appreciate it.

Bookmark and Share

Syndicate content