http://www.swi-prolog.org/pldoc/man?function=mod/2を参照してください:
+IntExpr1 mod +IntExpr2
Result = IntExpr1 - (IntExpr1 div IntExpr2) × IntExpr2 として定義されるモジュロ。ここで、div は床除算です。
そうR
あるべきです0
。mod
の結果は 1 つだけです。
実用的な解決策は次のとおりです。
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
(a predicate named , with one argument) は、 (same name, two arguments)primeNumber
とはまったく別の述語です。primeNumber/2
開始値の追加の引数のみを取得する「サブ関数」には、通常、同じ名前が付けられます。そのため、代わりにprime_prime
を使用する必要がありますprimeNumber
が、Prolog では通常キャメルケースを使用しません。
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)).