问题
I am trying to calculate if the input is a prime number but something goes wrong... here's my code:
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).
It gives me false
every time. Anyone got any clues or idea on what I am doing wrong?
回答1:
See http://www.swi-prolog.org/pldoc/man?function=mod/2:
+IntExpr1 mod +IntExpr2
Modulo, defined as Result = IntExpr1 - (IntExpr1 div IntExpr2) × IntExpr2, where div is floored division.
So R
should be 0
. mod
has only one result.
A working solution would be:
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.
By the way, primeNumber/1
(a predicate named primeNumber
, with one argument) is a totally separate predicate from primeNumber/2
(same name, two arguments). A "subfunction" that only gets an extra argument for the start value, is usually given the same name. So instead of prime_prime
you should just use primeNumber
, though in Prolog you normally don't use camelCase.
Using the optimization that Sergei Lodyagin proposed in the comments:
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.
And if you use the predefined predicate between(+Low, +High, ?Value):
primeNumber(A) :-
L is floor(sqrt(A)),
\+ (between(2, L, X),
0 is A mod X).
And to reduce the number of iterations even further, you only need to test for odd modules:
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)).
回答2:
Kay already provided a working modification of the broken program. I'll provide a simple analysis of what's broken.
When solving a problem in Prolog, it's good to be able to write out logically what it is you want first. In this case, it appears that you want to declare that:
A number, A, is prime if, for each number B < A, the value of A mod B is non-zero.
There are probably a couple of ways to render this directly into Prolog, of which Kay shows one.
However, the way your original rules are written, they say:
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.
As you can see, the rules as defined have a few issues:
- The rules don't match the logical definition of prime described in terms of the modulo relationship between the original number and all the numbers less than itself.
- The first rule expects an impossible mathematical condition when A is not equal to 1 (remember, the comma [,] in Prolog is a conjunction)
- The rules are initiated with starting divisor of 1, which is probably bad since 1 divides everything and is likely to become an exception to any rules that work
EDIT
Getting back to the first definition of a prime using the modulo operator, we can translate that into Prolog as follows:
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).
This logic is basically the same as Kay's except he's using a Prolog if-then-else construct.
来源:https://stackoverflow.com/questions/25972392/calculating-whether-number-is-prime-in-prolog