Problem50 - Project Euler

30分プログラム、その325。Problem50 - Project Euler。昨日のやつ(id:mzp:20080620:euler)の改良版。ログメッセージを出すようにしたのと、ちゃんと答えを表示するようにした。

使い方

1> problem50:solve(1000000).
sive prime:2
sive prime:3
...
sive prime:999983
checking N=546
checking N=545
checking N=544
checking N=543
{543,
 997651}

ソースコード

-module(problem50).
-compile(export_all).

%% Prime generator
sieve([X|Xs])->
    io:format("sive prime:~p~n",[X]),
    Ys = lists:filter(fun (N)->N rem X =/= 0 end,Xs),
    [X|sieve(Ys)];
sieve([]) ->
    [].

make_primes(N)->
    sieve(lists:seq(2,N)).

is_prime(N,[X|Xs])->
    N rem X =/= 0 andalso is_prime(N,Xs);
is_prime(_,[]) ->
    true.
is_prime(N)->
    To = round(math:sqrt(N))+1,
    is_prime(N,lists:seq(2,To)).
    
%% estimate upper bound for N
up_bound(To,[X|Xs])->
    if 
	To-X < 0 -> 0;
	true     -> 1 + up_bound(To-X,Xs)
    end;
up_bound(To,[]) ->
    To.
    
%% check N is satified
take(0,_Xs,Ys) ->
    Ys;
take(N,[X|Xs],Ys) ->
    take(N-1,Xs,[X|Ys]);
take(_N,[],_Ys) ->
    [].

take(N,Xs)->
    take(N,Xs,[]).

satisfy(To,N,[_|Xs]=Ys)->
    Y = lists:sum(take(N,Ys)),
    if
	Y =:= 0;Y > To ->
	    false;
	true -> 
	    case is_prime(Y) of
		true -> 
		    Y;
		_ ->
		    satisfy(To,N,Xs)
	    end
    end;
satisfy(_To,_,[]) ->
    false.

%% find satisfy N
loop(To,N,Primes) when N > 0->
    io:format("checking N=~p~n",[N]),
    case satisfy(To,N,Primes) of
	false ->
	    loop(To,N-1,Primes);
	P ->
	    {N,P}
    end;
loop(_,_,_) ->
    unexpected.

%% run
solve(To)->
    Primes = make_primes(To),
    N = up_bound(To,Primes),
    loop(To,N,Primes).