What is the bottleneck in this primes related predicate?

后端 未结 4 1004
旧时难觅i
旧时难觅i 2021-01-19 21:05

So here it is : I\'m trying to calculate the sum of all primes below two millions (for this problem), but my program is very slow. I do know that the algorithm in itself is

4条回答
  •  终归单人心
    2021-01-19 21:41

    OK, before the edit the problem was just the algorithm (imho). As you noticed, it's more efficient to check if the number is divided by the smaller primes first; in a finite set, there are more numbers divisible by 3 than by 32147.

    Another algorithm improvement is to stop checking when the primes are greater than the square root of the number.

    Now, after your change there are indeed some prolog issues: you use append/3. append/3 is quite slow since you have to traverse the whole list to place the element at the end. Instead, you should use difference lists, which makes placing the element at the tail really fast.

    Now, what is a difference list? Instead of creating a normal list [1,2,3] you create this one [1,2,3|T]. Notice that we leave the tail uninstantiated. Then, if we want to add one element (or more) at the end of the list we can simply say T=[4|NT]. awesome?

    The following solution (accumulate primes in reverse order, stop when prime>sqrt(N), difference lists to append) takes 0.063 for 20k primes and 17sec for 2m primes while your original code took 3.7sec for 20k and the append/3 version 1.3sec.

    problem_010(R) :-
        p010(3, Primes, Primes),
        sumlist([2|Primes], R).
    p010(2000001, _Primes,[]) :- !.                                %checking for primes till 2mil
    p010(Current, Primes,PrimesTail) :-
        R is sqrt(Current),
        (
            prime(R,Current, Primes)
        ->  PrimesTail = [Current|NewPrimesTail]
        ;   NewPrimesTail = PrimesTail
        ),
        NewCurrent is Current + 2,
        p010(NewCurrent, Primes,NewPrimesTail).
    prime(_,_, Tail) :- var(Tail),!.
    prime(R,_N, [Prime|_Primes]):-
        Prime>R.
    prime(_R,N, [Prime|_Primes]) :-0 is N mod Prime, !, fail.
    prime(R,ToTest, [_|Primes]) :- prime(R,ToTest, Primes).
    

    also, considering adding the numbers while you generate them to avoid the extra o(n) because of sumlist/2
    in the end, you can always implement the AKS algorithm that runs in polynomial time (XD)

提交回复
热议问题