首先,在使用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! –