首先,在使用append/3
一个列表的末尾附加是相当缓慢。如果您必须,请使用差异列表。 (就个人而言,我会尽量避免append/3
尽可能)
其次,你prime/2
在整个列表总是循环检查的首要时。这是不必要的缓慢。你可以改为检查id,你可以找到一个整数因子,直到你想检查的数字的平方根。
problem_010(R) :-
p010(3, 2, R).
p010(2000001, Primes, Primes) :- !.
p010(Current, In, Result) :-
(prime(Current) -> Out is In+Current ; Out=In),
NewCurrent is Current + 2,
p010(NewCurrent, Out, Result).
prime(2).
prime(3).
prime(X) :-
integer(X),
X > 3,
X mod 2 =\= 0,
\+is_composite(X, 3). % was: has_factor(X, 3)
is_composite(X, F) :- % was: has_factor(X, F)
X mod F =:= 0, !.
is_composite(X, F) :-
F * F < X,
F2 is F + 2,
is_composite(X, F2).
免责声明:我发现这个实现的prime/1
和has_factor/2
通过谷歌搜索。
该代码给出:
?- problem_010(R).
R = 142913828922
Yes (12.87s cpu)
这是更快代码:
problem_010(R) :-
Max = 2000001,
functor(Bools, [], Max),
Sqrt is integer(floor(sqrt(Max))),
remove_multiples(2, Sqrt, Max, Bools),
compute_sum(2, Max, 0, R, Bools).
% up to square root of Max, remove multiples by setting bool to 0
remove_multiples(I, Sqrt, _, _) :- I > Sqrt, !.
remove_multiples(I, Sqrt, Max, Bools) :-
arg(I, Bools, B),
(
B == 0
->
true % already removed: do nothing
;
J is 2*I, % start at next multiple of I
remove(J, I, Max, Bools)
),
I1 is I+1,
remove_multiples(I1, Sqrt, Max, Bools).
remove(I, _, Max, _) :- I > Max, !.
remove(I, Add, Max, Bools) :-
arg(I, Bools, 0), % remove multiple by setting bool to 0
J is I+Add,
remove(J, Add, Max, Bools).
% sum up places that are not zero
compute_sum(Max, Max, R, R, _) :- !.
compute_sum(I, Max, RI, R, Bools) :-
arg(I, Bools, B),
(B == 0 -> RO = RI ; RO is RI + I),
I1 is I+1,
compute_sum(I1, Max, RO, R, Bools).
这将运行一个数量级,比我上面给的代码快:
?- problem_010(R).
R = 142913828922
Yes (0.82s cpu)
@false这是...有趣。事实上,它返回142913828922,虽然我会发誓它第一次返回21171191:检查它atm –
对不起,我收回了我的评论:您正在使用更大的数字!不是20001,而是2000001 – false
@false是的,我刚刚意识到它也是xp! –