Project Euler Problem 50

Consecutive prime sum

The prime 41, can be written as the sum of six consecutive primes:
41 = 2 + 3 + 5 + 7 + 11 + 13
This is the longest sum of consecutive primes that adds to a prime below one-hundred.
The longest sum of consecutive primes below one-thousand that adds to a prime, contains 21 terms, and is equal to 953.
Which prime, below one-million, can be written as the sum of the most consecutive primes?
Link to original description
Source code examples on Github

Erlang version 1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#!/usr/bin/env escript
%% -*- erlang -*-
%%! -smp enable -sname p50
% vim:syn=erlang

-mode(compile).

main(_) ->
    PL = prime(5000),
    Answer = calc(0,PL,PL,0,[]),
    io:format("Answer ~p ~n",[ Answer ]).

calc(_,[],_,_,A) -> fetch_results(lists:reverse(lists:usort(A)));
calc(N,[H|T], O, R, A) when R+H < 1000000 -> calc(N+1,T,O,R+H, A);
calc(N,_,O, R, A) -> L = lists:sublist(O,2,length(O)-1),calc(0,L,L,0,A ++ [{N, R}]).


fetch_results([]) -> [];
fetch_results([{N,R}|T]) ->
    case is_prime(R) of
        true -> {N,R}
        ;_   -> fetch_results(T)
    end.

prime(2)                    -> [2] ;
prime(N) when N > 2, N =< 6 -> prime(lists:seq(3,N,2),[2]);
prime(N) when N > 6         ->
    prime(lists:merge( [6*K-1 || K <- lists:seq(1,(N+1) div 6)], [6*K+1 || K <- lists:seq(1,(N-1) div 6)] ), [2,3]);
prime(_)                    -> [].

prime(X,P)                  -> prime(X,lists:reverse(P),P).

prime([],_,P)                                          -> lists:reverse(P) ;
prime([H|T],[HP|TP],P) when HP * HP =< H,H rem HP > 0  -> prime([H|T],TP,P);
prime([H|T],[HP|_],P)  when HP * HP > H                -> prime(T,[H|P]);
prime([_|T],_,P)                                       -> prime(T,P).

is_prime(N)   -> is_prime(N, 2).
is_prime(N,N) -> true;
is_prime(N,M) when N rem M =:= 0 -> false;
is_prime(N,M) -> is_prime(N,M+1). 

Python version

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
prime_list = [2, 3, 5, 7, 11, 13, 17, 19, 23]   # Ensure that this is initialised with at least 1 prime
prime_dict = dict.fromkeys(prime_list, 1)
lastn      = prime_list[-1]

def _isprime(n):
    ''' Raw check to see if n is prime. Assumes that prime_list is already populated '''
    isprime = n >= 2 and 1 or 0
    for prime in prime_list:                    # Check for factors with all primes
        if prime * prime > n: break             # ... up to sqrt(n)
        if not n % prime:
            isprime = 0
            break
    if isprime: prime_dict[n] = 1               # Maintain a dictionary for fast lookup
    return isprime

def _refresh(x):
    ''' Refreshes primes upto x '''
    global lastn
    while lastn <= x:                           # Keep working until we've got up to x
        lastn = lastn + 1                       # Check the next number
        if _isprime(lastn):
            prime_list.append(lastn)            # Maintain a list for sequential access

def prime(x):
    ''' Returns the xth prime '''
    global lastn
    while len(prime_list) <= x:                 # Keep working until we've got the xth prime
        lastn = lastn + 1                       # Check the next number
        if _isprime(lastn):
            prime_list.append(lastn)            # Maintain a list for sequential access
    return prime_list[x]

def isprime(x):
    ''' Returns 1 if x is prime, 0 if not. Uses a pre-computed dictionary '''
    _refresh(x)                                 # Compute primes up to x (which is a bit wasteful)
    return prime_dict.get(x, 0)                 # Check if x is in the list

def factors(n):
    ''' Returns a prime factors of n as a list '''
    _refresh(n)
    x, xp, f = 0, prime_list[0], []
    while xp <= n:
        if not n % xp:
            f.append(xp)
            n = n / xp
        else:
            x = x + 1
            xp = prime_list[x]
    return f

def all_factors(n):
   ''' Returns all factors of n, including 1 and n '''
   f = factors(n)
   elts = sorted(set(f))
   numelts = len(elts)
   def gen_inner(i):
       if i >= numelts:
           yield 1
           return
       thiselt = elts[i]
       thismax = f.count(thiselt)
       powers = [1]
       for j in xrange(thismax):
           powers.append(powers[-1] * thiselt)
       for d in gen_inner(i+1):
           for prime_power in powers:
               yield prime_power * d
   for d in gen_inner(0):
       yield d

def num_factors(n):
    ''' Returns the number of factors of n, including 1 and n '''
    div = 1
    x = 0
    while n > 1:
        c = 1
        while not n % prime(x):
            c = c + 1
            n = n / prime(x)
        x = x + 1
        div = div * c
    return div

Perl version

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#!/usr/bin/perl -w

use strict;

sub primes {
    my @n = (2..shift);
    my @p;
    while (@n && (push @p, shift @n)) {
        @n = grep { $_ % $p[-1] } @n;
    }
    return @p
}


sub is_prime {
    for (2..int(sqrt($_[0]))){ return 0 unless $_[0] % $_}
    1
}

my @p = primes(5000);

my($len, $sum, $mlen, $msum) = (0, 0, 0, 0);
for my $n (0..$#p){
    for my $m ($n..$#p){
        $sum += $p[$m];
        if(is_prime($sum) && $sum < 1000000 && $mlen < $len){
            ($mlen, $msum) = ($len, $sum)
        }elsif($sum < 1000000){ $len++}
        else{ last; }
    }
    ($len, $sum) = (0,0);
}

print $mlen."--".$msum."\n";



Performance

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
mkh@mkh-xps:~/work/mblog/pr_euler/p50$ time ./p50.erl
Answer {543,997651}

real    0m0.340s
user    0m0.305s
sys     0m0.078s
mkh@mkh-xps:~/work/mblog/pr_euler/p50$ time ./p50.pl
541--997651

real    0m0.897s
user    0m0.893s
sys     0m0.004s
mkh@mkh-xps:~/work/mblog/pr_euler/p50$ time ./p50.py
997651

real    0m1.377s
user    0m1.371s
sys     0m0.008s
mkh@mkh-xps:~/work/mblog/pr_euler/p50