计算Prolog中的数字是否为素数

时间:2014-09-22 10:55:17

标签: prolog primes primality-test

我正在尝试计算输入是否为素数但出现问题...这是我的代码:

primeNumber(X):-
    prime_prime(A, 1).

prime_prime(A, B):-
    R is A mod B,
    R =:= 1,
    R =:= A.
prime_prime(X, B):-
    B < A,
    Next is B + 1,
    prime_prime(A, Next).

每次都给我false。任何人都对我做错了什么有任何线索或想法?

2 个答案:

答案 0 :(得分:3)

请参阅http://www.swi-prolog.org/pldoc/man?function=mod/2

  

+IntExpr1 mod +IntExpr2
      模数,定义为Result = IntExpr1 - (IntExpr1 div IntExpr2)×IntExpr2,其中div是floored division。

因此R应为0mod只有一个结果。

一个有效的解决方案是:

primeNumber(A) :-
    A > 1,                 % Negative numbers, 0 and 1 are not prime.
    prime_prime(A, 2).     % Begin iteration:

prime_prime(A, B) :-       % Test if A divides by B without remainder
    B >= A                 % The limit was reached?
    ->  true               %     Then it's prime.
    ;   0 is A mod B       % B divides A without a remainder?
    ->  false              %     Then it's not prime.
    ;   succ(B, C),        % Otherwise: C is B + 1
        prime_prime(A, C). % Test if C divides A.

顺便说一下,primeNumber/1(一个名为primeNumber的谓词,带有一个参数)是一个完全独立的谓词primeNumber/2(同名,两个参数)。仅为起始值获取额外参数的“子函数”通常具有相同的名称。因此,除了prime_prime之外,您应该只使用primeNumber,但在Prolog中,您通常不使用camelCase。

使用Sergei Lodyagin在评论中提出的优化:

primeNumber(A) :-
    A > 1,                    % Negative numbers, 0 and 1 are not prime.
    sqrt(A, L),               % A prime factor of A is =< the square root of A.
    prime_prime(A, 2, L).     % Begin iteration:

prime_prime(A, B, L) :-       % Test if A divides by B without remainder
    B >= L                    % The limit was reached?
    ->  true                  %     Then it's prime.
    ;   0 is A mod B          % B divides A without a remainder?
    ->  false                 %     Then it's not prime.
    ;   succ(B, C),           % Otherwise: C is B + 1
        prime_prime(A, C, L). % Test if C divides A.

如果您使用预定义谓词between(+Low, +High, ?Value)

primeNumber(A) :-
    L is floor(sqrt(A)),
    \+ (between(2, L, X),
        0 is A mod X).

为了进一步减少迭代次数,您只需要测试奇数模块:

primeNumber(2).
primeNumber(A) :-
    A > 2,
    \+ 0 is A mod 2,
    L is floor(sqrt(A) / 2),
    \+ (between(1, L, X),
        0 is A mod (1 + 2*X)).

答案 1 :(得分:2)

凯已经提供了破损程序的工作修改。我将提供一个简单的分析。

当解决Prolog中的问题时,最好能够逻辑地写出你想要的东西。在这种情况下,您似乎要声明:

A number, A, is prime if, for each number B < A, the value of A mod B is non-zero.

可能有几种方法可以直接将其呈现给Prolog,其中Kay显示了一个。

但是,原始规则的编写方式,他们说:

A number, A, is prime if:
    (Rule 1) The value of A mod B, for a given value of B, is 1 and is also A.
 OR (Rule 2) B < A and Rule 1 is satisfied with A and B+1.

如您所见,定义的规则存在一些问题:

  • 这些规则与原始数字与所有数字之间的模数关系所描述的素数的逻辑定义不匹配。
  • 当A不等于1时,第一条规则要求一个不可能的数学条件(记住,Prolog中的逗号 [,]是连接
  • 规则是以1的起始除数开始的,这可能很糟糕,因为1除了一切,很可能成为任何有效规则的例外

修改

使用模运算符返回 prime 的第一个定义,我们可以将其转换为Prolog,如下所示:

is_prime(N) :-                 % N is prime if...
  N > 1,                       % N > 1, and
  non_divisible_from(N, 2).    % N is non-divisible by everything from 2 to N-1

non_divisible_from(N, D) :-    % N is non-divisible by D through N-1 if...
  N =< D.                      % D >= N
                               % --OR--
non_divisible_from(N, D) :-    % N is non-divisible from D to N-1 if...
  N > D,                       % N > D, and
  N mod D =\= 0,               % N is non-divisible by D, and
  D1 is D + 1,                 % N is non-divisible by D+1 to N-1
  non_divisible_from(N, D1).

这个逻辑与Kay的基本相同,只是他使用的是Prolog if-then-else结构。