Prolog程序检查数字是否为Prime

时间:2014-04-25 00:18:27

标签: prolog primes

我根据以下逻辑编写了以下程序:素数只能​​被1和它自身整除。所以我只是经历了将它划分为大于1且小于其自身的所有数字的过程,但我似乎遇到了问题,因为我将所有输入的数字都设为真。这是我的代码......

divisible(X,Y) :-
    Y < X,
    X mod Y is 0,
    Y1 is Y+1,
    divisible(X,Y1).

isprime(X) :-
    integer(X),
    X > 1,
    \+ divisible(X,2).

提前致谢:)

6 个答案:

答案 0 :(得分:9)

我是Prolog的初学者,但设法解决了你的问题。

divisible(X,Y) :- 0 is X mod Y, !.

divisible(X,Y) :- X > Y+1, divisible(X, Y+1).

isPrime(2) :- true,!.
isPrime(X) :- X < 2,!,false.
isPrime(X) :- not(divisible(X, 2)).

主要问题是声明X mod Y is 0。谓词is有两个(左和右)参数,但左参数必须是一个常量或变量,它在谓词执行时已经统一。我只是交换了这些值。其余的代码用于检查数字2(这是素数)和数字少于2(不是素数)

我忘了提到比较Y < X是错误的,因为您要测试2和X-1之间的所有数字,该比较包括X.

答案 1 :(得分:5)

这个答案是@lefunction's previous answer的后续行动。

isPrime2/1isPrime1/1尽可能接近,并进行了一些重要更改(如下所示):

isPrime2(2) :-
    !.
isPrime2(3) :-
    !.
isPrime2(X) :-
    X > 3,
    X mod 2 =\= 0,
    N_max is ceiling(sqrt(X)),
    isPrime2_(X,3,N_max).

isPrime2_(X,N,N_max) :-
    (  N > N_max 
    -> true
    ;  0 =\= X mod N,
       M is N + 2,
       isPrime2_(X,M,N_max)
    ).

让我们查询!

?- time(isPrime1(99999989)).
% 99,999,990 inferences, 5.082 CPU in 5.078 seconds (100% CPU, 19678881 Lips)
true.

?- time(isPrime2(99999989)).
% 20,002 inferences, 0.001 CPU in 0.001 seconds (100% CPU, 13615185 Lips)
true.

答案 2 :(得分:4)

X mod Y is 0总是失败,因为is左侧不允许使用任何表达式。

更改为0 is X mod Y,或者更好地更改为X mod Y =:= 0

答案 3 :(得分:3)

agarwaen's accepted answer在大数字上表现不佳。这是因为它不是尾递归(我认为)。此外,您可以通过一些关于素数的事实来加速一切。

1)2是唯一偶数素数

2)任何大于原件一半的数字均不均匀

isPrime1(2) :-
    !.
isPrime1(3) :-
    !.
isPrime1(X) :-
    X > 3,
    (  0 is X mod 2 
    -> false
    ;  Half is X/2,
       isPrime1_(X,3,Half)
    ).

isPrime1_(X,N,Half) :-
    (  N > Half 
    -> true
    ;  0 is X mod N
    -> false
    ;  M is N + 2,
       isPrime1_(X,M,Half)
    ).

1 ?- time(isPrime1(999983)). % 1,249,983 inferences, 0.031 CPU in 0.039 seconds (80% CPU, 39999456 Lips) true.

<强> EDIT1

是否可以更进一步? isPrime_/3isPrime2/1更有效,因为它只与之前已知的素数进行比较。但问题是生成此列​​表。

allPrimes(Max,Y) :- 
    allPrimes(3,Max,[2],Y).

allPrimes(X,Max,L,Y) :-
    Z is X+2,
    N_max is ceiling(sqrt(X)),
    (  X >= Max 
    -> Y = L;
    (  isPrime_(X,L,N_max)
    -> append(L,[X],K),       %major bottleneck
       allPrimes(Z,Max,K,Y)
    ;  allPrimes(Z,Max,L,Y)
    )).

isPrime_(_,[],_).

isPrime_(X,[P|Ps],N_max) :-
    (  P > N_max  
    -> true     %could append here but still slow
    ;  0 =\= X mod P,
       isPrime_(X,Ps,N_max)
    ).

答案 4 :(得分:2)

正在尝试其他方法。基于Fermats little theorem的伪素数测试:

test(P) :- 2^P mod P =:= 2.

test2(P) :- modpow(2,P,P,2).

modpow(B, 1, _, R) :- !, R = B.
modpow(B, E, M, R) :- E mod 2 =:= 1, !,
   F is E//2,
   modpow(B, F, M, H),
   R is (H^2*B) mod M.
modpow(B, E, M, R) :- F is E//2,
   modpow(B, F, M, H),
   R is (H^2) mod M.

没有谓词{{​​1}},事情会变得太慢或整数溢出:

modpow/4

尚不确定如何将其扩展到完整的素数测试。

答案 5 :(得分:0)

我的方式是优雅的方式:

isPrime(A):-not((A1 is A-1,between(2,A1,N), 0 is mod(A,N))),not(A is 1).

1不是PRIME NUMBER,但如果您不这么认为,只需删除 not(A is 1)