OK, next installment of this. :)
The problem is stated as such:
The prime factors of 13195 are 5, 7, 13 and 29.
What is the largest prime factor of the number 600851475143 ?
Haskell:
module Main where factors count top_number | count >= top_number = [] | zero_mod count = count : new_top: factors (count + 2) new_top zero_mod divisor | divide == 0 = True --prime :: Integer -> Integral -> Bool prime divisor divided | divided == 1 = True | divisor >= sqrt_divided = True where next_prime = prime (divisor + 2) divided is_prime input = prime 3 input main = do let x = factors 3 600851475143
Getting that sqrt function to work took me longer to figure out than I want to admit. I was having the hardest time getting the numeric types to play nice. I finally broke down and asked the haskell-beginners email list to get the answer.
Python:
#!/usr/bin/python import math top_number = 600851475143 def zero_mod(divisor): if top_number % divisor == 0: return True else: return False def is_prime(divided): divisor = 3 sqrt_divided = math.sqrt(divided) if divided == 1: return True else: while divisor <= sqrt_divided: if divided == divisor: return True elif divided % divisor == 0: return False else: divisor += 2 return True def main(): count = 3 go_to = top_number first_list =[] while count <= go_to: if zero_mod(count): first_list.append(count) go_to = top_number / count first_list.append(go_to) count += 2 second_list = map(is_prime, first_list) print "%s" % max(zip(second_list, first_list))[-1] if __name__ == "__main__": main()
And finally Perl:
#!/usr/bin/perl use strict; use warnings; my $top_number = 600851475143; sub is_prime { my ($divided) = @_; my $divisor = 3; while($divisor <= $sqrt_divided) { $divisor += 2; } 1; } my @f; my $new_top = $top_number; for(my $i = 3; $i <= $new_top; $i += 2) { unless ($top_number % $i) { if (is_prime($i)) { } } $new_top = $top_number / $i; }
Props goes out to zloyrusski who helped me figure out a major hang up with Perl on this one. The for loop idea was his,though I really diverted from his answer. Goes to show you how much two people really can think differently. Hey Zloyrusski, is this Perl code looking better? ;) As always, I'm open to constructive criticism.
--UPDATES--
1) Code has been redone to fix the error talked about by agf. I find it a little amusing that I still get the same answer though.
2) I gotta start using less languages to do this in. If I make a mistake I've gotta change & test three different versions.
3) Times ( as requested by Caleb):
Haskell: 0.004s
Python: 0.205s
Perl : 0.136s
4) More props for zloyrusski for the division algorithm.

R Version
takes about 15 seconds to execute
> isPrime <- function(x)
+ {
+ y = sqrt(x)
+ for(i in 2:y)
+ {
+ if(x%%i==0) return(F)
+ }
+ return(T)
+ }
> for(i in 1:y){if(600851475143%%i==0 && isPrime(i)) {x<-c(x, i); print(i)}; if(i%%1000000==0) print(“…”)}
[1] 71
[1] 839
[1] 1471
[1] 6857
[1] “…”
[1] “…”
[1] “…”
[1] “…”
[1] “…”
Thanks kindageeky for the
Thanks kindageeky for the submissions (spread out of two pages).
I'm not familiar with R but I'm happy to see it up here.
I will also refrain from making any Pirate jokes in it's presence. ;)
glasgow youth hostel hotel burnham in chicago
19 Oct 2008 map costa del veneto venetian riviera hotel coast venice and book hotels rooms B&Bs Compare prices and book an hotel online. Even though there are no certain facts it is estimated that the Maldives have been populated by 1500 BC the explorers from USA and Sri Lanka may had come to the archipelago. Monaco hotels & Monte Carlo hotel accommodation. Book online for special offers & great discounts on hotels.
Same problem solved in
Same problem solved in C#.
https://sites.google.com/site/eulerproblemsincsharp/home/problem-3
Suggestions
Before i start to rant on small style issues I must say that I like your choice of languages and i think solving project Euler problems (and especially with Haskell) is a great way to grow as a programmer.
Also note that my comments are not about your choice of algorithms or general approach to the problem, this is probably a more interesting area of improvement but my feedback focus only on the code itself.
this is written much better as:
and that goes for Haskell as well:
Does the expression
round . fromIntegralin your factor-function in Haskell do anything? To my knowledge it can just be deleted.What you did right with that line however was that you used functional
composition
(.)to construct a pipe-line of functions. It isconsidered good practise in the Haskell community since it makes
refactoring easier. You should use that technique in your function main
as well. so instead of:
write:
This could be considered a matter of taste if it was done consistently,
it's the inconsistency that causes the code-smell (and that goes for
the whitespace inconsistency as well, notice the extra space before
maximum and the space before zip in your version).
Don't have commented out code within your code. It's fine for
experimentation, but before posting (or commiting to your VCS) either
uncomment it or delete it. When it comes to top-level types in Haskell
i suggest that you keep them, i find that the code becomes easier to
reason about if the right functions and values have their types in the
code (tip: if you want help finding the right type you can use the :t command in ghci).
This could be rewritten to:
This reduces nesting and makes the code easier to read.
I'm not to fond of your
sqrt_dividedin any of the languages. It's only used once and the expression you assign to it expresses its meaning better than the name, you should remove this variable and use its expression directly in Python and Perl. In Haskell it's a similar story but your expression is much larger because of the type conversion, i would suggest writing a version of sqrt that works with integers instead and removing the sqrt_divided symbol there as well.Here is a quick and dirty attempt to clean up your prime function from the Haskell code:
You don't need a
doin your main when you are really only performing a single IO action, i would rewrite that to use awhereblock which is the style you have used in other places. (Note thatprint = putStrLn . show)It became a fairly large comment, I hope you find it at least somewhat constructive and best of luck with the next Euler problem.
WOW Daniel, That has to be
WOW Daniel,
That has to be longest comment that has ever been posted on this blog (yet) or in any that I can recall reading as of late. And thank you for the compliment on which programming languages to use for these little projects.Also, a really big thank you for the helpful tips on some ways to clean up my coding style. I do appreciate them, and have already modified my old code to use your changes. (To help them stick ;). )
Concerning Haskell, I'm still confused between when/how to use $ instead of '.'. Can you suggest any good reading material to help me understand which one to use when? Haskell is still very foreign to me, and I'm still not quite sure what I'm doing. I just know that I'm producing code that is getting the results I'm looking for. So the examples and explanations above have been extremely helpful.
Thanks again and look forward to constructive comments from you.
Function composition style
http://stackoverflow.com/questions/940382/haskell-difference-between-dot-and-dollar-sign
(Note that
.and$aren't special, they are just library functions and not part of the core language.)The link above contains some information about the operators themselves, but sadly no motivation for a particular style and i didn't find it anywhere else so i'll try to give you the gist of it.
First note that
... $ ...can be rewritten as(...) (...)because of its low precedence. When used as an infix-operator like this it's just a tool to avoid parenteses and this is how it is used in your examples. You could replace $ by enclosing its left and right-side arguments with parenteses.This means that
f $ g $ h $ xgets translated tof (g (h x))whilef . g . h $ xtranslates to(f . g . h) x.They may seem similar at first glance but the first version contains a lot more nested scopes making the code harder to reason about and to refactor.
I can refactor the expression to
(fg . h) x where fg = f . gbut i can't writefg $ h $ x where fg = f $ gsince that would mean something different. I could solve that by writingfg = f . gin the last example as well but it is a larger and less obvious step.Secondly it's more obvious that i can rewrite
to
Because the
xargument is "close to the surface" (it isn't nested within a lot of parentheses).Python version comments
1. You can use a list comprehension without otherwise restructuring your program, this is the "pythonic" way to do it:
or
with
print second_list[-1]instead of what you have now.2. Your algorithm is not correct. What is the largest prime factors of 14? 15?
3. Your algorithm is not efficient. You're dividing by numbers that can't possibly yield any number's largest prime factor.
There are some other small things but those are the main points.
I just want to say that I
I just want to say that I know the python is a little ugly. Using a while loop wasn't my first choice but range(1,600851475143) produced errors because of too many items in the list.
If your aware of a more python friendly way to deal with the problem above I'm all eyes.
Hey agf, Thanks for posting.
Hey agf,
Thanks for posting. And I see what you mean by the algorithm being incorrect. I got mixed up between how to find factors and how to find primality. I will fix this and update the post.
Thanks!
Style
You should clean up the code before posting, for starters the zero_mod functions in both Haskell and Python are quite smelly.
Hey Daniel, Thanks for the
Hey Daniel,
Thanks for the post. I appreciate your input, but would also appreciate you sharing with me your versions of my code so that I can learn how to make it less "smelly". Feel free to email me directly if your uncomfortable posting code in a public forum.
Benchmark
you really want comments? provide timings for your scripts to show which language is faster... (plus it'd just be interesting)
Hey Caleb, Yes I do believe I
Hey Caleb,
Yes I do believe I want comments. ;)
I like the suggestion and thank you for it. I'll update the post this evening with some benchmarks.
And so it begins..
.. the first of many of the Project Euler problems that suck purely because you have to generate prime numbers. It's not an interesting problem to solve (imho) and there are so many problems that rely on it.
For this problem I wrote my own. For every prime-related problem afterward, I just reused one that I found on the web that's really fast.