Прологовая арифметика. Пролог система не считает символы +

advertisement
Прологовая арифметика.
Пролог система не считает символы +, -, * и т. д. чем то особым, и не пытается ничего
вычислять до тех пор, пока мы не укажем ей, что это - запись арифметических действий.
Чтобы лучше понять, что нам непонятно в арифметике Пролога, выполним следующие
запросы к системе:
GNU Prolog 1.2.16
By Daniel Diaz
Copyright (C) 1999-2002 Daniel Diaz
| ?- X = 2, Y is X - 1.
X = 2
Y = 1
yes
| ?-
А вот так система поймет Вас неверно:
GNU Prolog 1.2.16
By Daniel Diaz
Copyright (C) 1999-2002 Daniel Diaz
| ?- X = 2, Y = X - 1.
X = 2
Y = 2-1
yes
| ?-
Пролог рассчитан главным образом на обработку символьной информации, при которой
потребность в арифметических вычислениях относительно мала. Однако, было бы очень
странным, если бы язык программирования компьютера не содержал набора
математических функций и арифметических операторов.
Для осуществления основных арифметических действий, можно воспользоваться
несколькими предопределенными операторами.




+ Сложение
- Вычитание
/ Деление (вещественное)
mod модуль (остаток от целочисленного деления)
Самое время сказать, что одно и то же выражение в Прологе может быть записано в
инфиксной и постфиксной форме:
| ?- X = 15, Y is X mod 2.
X = 15
Y = 1
yes
| ?- X = 15, Y is mod(X,2).
X = 15
Y = 1
yes
| ?-
Встроенные, математические предикаты в GNU Prolog (без простейших)
inc(E)
Инкремент (увеличение на единицу)
dec(E)
Декремент (уменьшение на единицу)
E1 /\ E2
Побитовое "И"
E1 \/ E2
Побитовое "ИЛИ"
E1 ^ E2
Побитовое "XOR" (исключающее "ИЛИ")
\E
Побитовое "НЕ"
E1 << E2
"Целочисленный сдвиг" E1 на E2 разряда влево
E1 >> E2
"Целочисленный сдвиг" E1 на E2 разряда вправо
abs(E)
Абсолютное значение (модуль числа)
sign(E)
Знаковая функция, возвращает -1, 0 или 1
min(E1,E2)
Вернет минимальный аргумент
max(E1,E2)
Вернет максимальный аргумент
E1 ** E2
Возведение в степень: E1E2
sqrt(E)
Извлечение квадратного корня из E
Тригонометрия в радианах: atan(E), cos(E), acos(E), sin(E), asin(E)
exp(X)
ex
log(X)
Натуральный логарифм (по основанию e)
float(X)
"Превращает" целое число X в вещественное
ceiling(X)
"Округляет" вещественное число X до большего целого числа
floor(X)
"Округляет" вещественное число X до меньшего целого числа
round(X)
"Округляет" вещественное число X до ближайшего целого
числа
truncate(X)
"Целая часть" вещественного числа X
Арифметические операции используются также и при сравнении числовых величин. Ниже
перечислены операторы сравнения, их основное отличие - вычисление
конкретезирующих, числовых значений перед сравнением:






Expr1
Expr1
Expr1
Expr1
Expr1
Expr1
X > Y (арифметическое (X больше чем Y))
X < Y (арифметическое (X меньше чем Y))
X >= Y (арифметическое (X больше или равно Y))
X =< Y (арифметическое (X меньше или равно Y))
X=:=Y (арифметическое (X равно Y))
X=\=Y (арифметическое (X не равно Y))
=:= Expr2 succeeds if eval(Expr1) = eval(Expr2).
=\= Expr2 succeeds if eval(Expr1) not eq eval(Expr2).
< Expr2 succeeds if eval(Expr1) < eval(Expr2).
=< Expr2 succeeds if eval(Expr1) <= eval(Expr2).
> Expr2 succeeds if eval(Expr1) > eval(Expr2).
>= Expr2 succeeds if eval(Expr1) => eval(Expr2).
Наибольший общий делитель
Давайте рассмотрим использование арифметических операций на простом примере:
нахождение наибольшего общего делителя двух чисел.
Если заданы два целых числа X и Y, то их наибольший делитель Z можно найти,
руководствуясь следующими тремя правилами:
1. Если X и Y равны, то Z равен X.
2. Если X > Y, то Z равен наибольшему общему делителю разности Y - X.
3. Если Y < X, то формулировка аналогична правилу (2), если X и Y поменять
местами.
Реализуем это рекурсивное определение:
nod(X,X,X).
nod(X,Y,Z) :- X<Y, Y1 is Y-X, nod(X,Y1,Z).
nod(X,Y,Z) :- X>Y, X1 is X-Y, nod(X1,Y,Z).
Протестируем в GNU Prolog:
GNU Prolog 1.2.16
By Daniel Diaz
Copyright (C) 1999-2002 Daniel Diaz
| ?- [user].
compiling user for byte code...
nod(X,X,X).
nod(X,Y,Z) :- X<Y, Y1 is Y-X, nod(X,Y1,Z).
nod(X,Y,Z) :- X>Y, X1 is X-Y, nod(X1,Y,Z).
user compiled, 4 lines read - 1188 bytes written, 4268 ms
(10 ms) yes
| ?- nod(20,25,X).
X = 5 ? ;
no
| ?-
Вычисление факториала
GNU Prolog 1.2.16
By Daniel Diaz
Copyright (C) 1999-2002 Daniel Diaz
| ?- [user].
compiling user for byte code...
fact(0,1).
fact(X,F) :- X>0, X1 is X-1, fact(X1,F1), F is X*F1.
user compiled, 3 lines read - 800 bytes written, 4199 ms
(20 ms) yes
| ?- fact(5,X).
X = 120 ? ;
no
| ?-
Оформление циклов
forall(:Cond, :Action)
For all alternative bindings of Cond, Action can be proven. The example
verifies that all arithmetic statements in the given list are correct. It does not
say which is wrong if one proves wrong.
?- forall(member(Result = Formula, [2 = 1 + 1, 4 = 2 * 2]),
Result =:= Formula).
The predicate forall/2 is implemented as \+ ( Cond, \+ Action), i.e., There is
no instantiation of Cond for which Action is false.. The use of double negation
implies that forall/2 does not change any variable bindings. It proves a relation.
The forall/2 control structure can be used for its side-effects. E.g., the following
asserts relations in a list into the dynamic database:
?- forall(member(Child-Parent, ChildPairs),
assertz(child_of(Child, Parent))).
Using forall/2 as forall(Generator, SideEffect) is preferred over the
classical failure driven loop as shown below because it makes it explicit which
part of the construct is the generator and which part creates the side effects.
Also, unexpected failure of the side effect causes the construct to fail. Failure
makes it evident that there is an issue with the code, while a failure driven loop
would succeed with an erroneous result.
...,
(
Generator,
SideEffect,
fail
;
true
)
If your intent is to create variable bindings, the forall/2 control structure is
inadequate. Possibly you are looking for maplist/2, findall/3 or foreach/2.
Download