Last active
April 18, 2020 16:22
-
-
Save WillNess/4747441 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
So you've got the two bugs: your | |
> isprimerec _ 1 = False | |
> isprimerec n t = if (n `rem` t) == 0 then False else isprimerec n (n-1) | |
should have been | |
> isprimerec _ 1 = True | |
> isprimerec n t = if (n `rem` t) == 0 then False else isprimerec n (t-1) | |
or, with list comprehension, | |
> isprime n = n>1 && and [ rem n t /= 0 | t <- [n-1,n-2..2] ] | |
*Internalize* that extra parameter, it was a technicality anyway! | |
( Ahha, but what's that `and`, you ask? It's just like this recursive function, `every`: | |
> every (x:xs) = x && every xs -- 'x' is a Boolean, 'xs' is a list | |
> every [] = True -- of Booleans | |
... ok? ) But now a major *algorithmic* drawback becomes apparent: we test in the *wrong* order. | |
It will be much faster to test in ascending order: | |
> isprime n = n>1 && and [ rem n t /= 0 | t <- [2..n-1] ] | |
or even faster to stop at the `sqrt`, | |
> isprime n = n>1 && and [ rem n t /= 0 | t <- [2..q] ] | |
> where q = floor (sqrt (fromIntegral n)) | |
or to test only by odds, and 2 (why test by 6, if we tested by 2 already? etc.): | |
> isprime n = n>1 && and [ rem n t /= 0 | t <- 2:[3,5..q] ] | |
> where q = floor (sqrt (fromIntegral n)) | |
or just by *primes* (why test by 6, if we tested by 3 already? etc.): | |
> isprime n = n>1 && and [ rem n t /= 0 | t <- takeWhile ((<= n).(^2)) primes ] | |
> primes = 2 : filter isprime [3..] | |
and why test the *evens* when filtering the primes through - isn't it better | |
to not generate them in the first place? | |
> primes = 2 : filter isprime [3,5..] | |
but `isprime` always tests by 2 - yet we feed it only the odd numbers: | |
> primes = 2 : 3 : filter (noDivs $ drop 1 primes) [5,7..] | |
> noDivs factors n = and [ rem n t /= 0 | t <- takeWhile ((<= n).(^2)) factors ] | |
and why generate the multiples of 3 (`[9,15 ..]`) only to test and remove them later? | |
> -- Prelude> take 20 [5,7..] | |
> -- Prelude> take 20 [j+i | i<-[0,2..], j<-[5]] | |
> -- Prelude> take 20 [j+i | i<-[0,6..], j<-[5,7,9]] | |
> -- [5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43] | |
> primes = 2:3:5: filter (noDivs $ drop 2 primes) [j+i | i<-[0,6..], j<-[7,11]] | |
or without the multiples of 5, | |
> -- Prelude> take 20 [j+i | i<-[0,6..], j<-[7,11]] | |
> -- Prelude> take 20 [j+i | i<-[0,30..], j<-[7,11,13,17,19,23,25,29,31,35]] | |
> -- [7,11,13,17,19,23,25,29,31,35,37,41,43,47,49,53,55,59,61,65] | |
> primes = 2:3:5:7: filter (noDivs $ drop 3 primes) | |
[j+i | i<-[0,30..], j<-[11,13,17,19,23,29,31,37]] | |
... but that's already going too far. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment