【问题标题】:Calculating whether number is prime in Prolog在Prolog中计算数字是否为素数
【发布时间】:2014-11-16 07:40:07
【问题描述】:

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

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。有人对我做错了什么有任何线索或想法吗?

【问题讨论】:

  • 第一:XA:看看加载文本时的警告。
  • 除非A1,否则R =:= 1R =:= A 不可能同时为真。
  • 我认为 primeNumber/1 有更好的算法(和 prolog 实现)。如果这不仅仅是简短的示例,并且您计划在任何实际应用程序中使用此谓词,我可以与您分享我上次是如何做到的。

标签: prolog primes primality-test


【解决方案1】:

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

+IntExpr1 mod +IntExpr2
取模,定义为 Result = IntExpr1 - (IntExpr1 div IntExpr2) × IntExpr2,其中 div 为取整除法。

所以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(同名,两个参数)完全不同的谓词。仅获得起始值的额外参数的“子函数”通常具有相同的名称。所以你应该使用primeNumber而不是prime_prime,尽管在Prolog中你通常不使用camelCase。

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

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)).

【讨论】:

  • 迭代 B 直到 sqrt(A) 就足够了,而不是直到 A。我的意思是您的条件 B>=A(大量迭代只会产生热量)。
  • @SergeiLodyagin,你是对的。我更新了我的答案。
  • 将“succ(B, C)”更改为等价于“C is B+2”(从 prime_prime(A, 3, L) 开始将减少两次迭代次数...
  • @SergeiLodyagin,谢谢!实际上,我并不打算提供一个展示解决方案如何在 Prolog 中实现素数测试。 ;-)
【解决方案2】:

Kay 已经提供了对损坏程序的工作修改。我将提供一个简单的分析是什么坏了。

在 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 会除所有内容,并且很可能成为任何有效规则的例外

编辑

回到使用模运算符素数的第一个定义,我们可以将其转换为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).

除了他使用 Prolog if-then-else 构造之外,此逻辑与 Kay 的基本相同。

【讨论】:

    猜你喜欢
    • 2014-06-05
    • 1970-01-01
    • 2012-01-04
    • 2014-06-10
    • 2015-01-18
    • 1970-01-01
    • 1970-01-01
    • 2020-09-20
    • 1970-01-01
    相关资源
    最近更新 更多