Попытка выяснить, как написать рекурсивный предикат Division_by(X, D, I, R), который принимает в качестве входных данных положительное целое число X и делитель D и возвращает ответ как целую часть числа I и оставшуюся часть R, однако , я не могу понять Пролог. Как мне это сделать?
Деление и остаток в Прологе
Ответы (3)
Для этого есть предопределенные оцениваемые функторы.
(div)/2
и (mod)/2
всегда округляются в меньшую сторону. Рекомендован LIA-1, Knuth и др.
(//)/2
и (rem)/2
округляются до нуля (на самом деле это определено реализацией, но все текущие реализации делают это именно так). Вы можете запросить это через current_prolog_flag(integer_rounding_function, F)
, что дает в текущих реализациях toward_zero
.
Разница между этими парами проявляется только тогда, когда задействованы отрицательные числа. Это своего рода религиозная война, какую из них предпочесть. ISO/IEC 10967:2012 Независимая от языка арифметика (vl. LIA-1) обеспечивает только округление в меньшую сторону "из-за склонности к ошибочному использованию" (C.5.1.2.2) в направлении_нуля, тогда как Fortran и его последователи, такие как C перейти к direction_zero, назвав его "алгебраическим" (6.5.5). См. также: Преимущества использования усечения в направлении минус бесконечность против нуля
Я предполагаю, что ваш учитель пытается научить рекурсии.
Деление — это многократное вычитание, так же как умножение — это многократное сложение, n'est-ce-pas?
Обычная идиома пролога, поскольку переменным может быть присвоено значение только один раз, состоит в том, чтобы иметь внешний «общедоступный» предикат, который вызывает частный «рабочий» предикат, который использует аккумулятор (ы) и выполняет фактическую работу. Это приводит нас к такому решению.
%
% divide M (the dividend) by N (the divisor),
%yielding the quotient (Q) and remainder (R).
integer_division( M , N , Q , R ) :-
M > 0 ,
N > 0 ,
div_rem( M , N , 0 , Q , R )
.
%
% internal worker predicate for integer division
% requires dividend and divisor both to be unsigned (positive).
%
div_rem( M , N , Q , Q , M ) :- % dividend M < divisor N? We're done.
M < N , % - unify the accumulator with the quotient
. % - and unify the divisor with the remainder
div_rem( M , N ,T , Q , R ) :- % dividend M >= divisor N?
M >= N , % - increment the accumulator T
T is T+1 , % - decrement the divisor by N
M1 is M-N , % - recurse down
div_rem( M1 , N , T1 , Q , R ) % - That's all.
. % Easy!
Из этого должно быть довольно легко изменить внешний предикат public для учета подписанных операндов, имея в виду, что
+/+
дает+
+/-
дает-
-/+
дает-
-/-
дает+
И что, вычислив M/N
, чтобы получить частное Q
и остаток R
, свойство
M = N * Q + R
Справедливо. Это должно сообщить вам о необходимых знаках для частного и остатка. Не забывайте, что сложение отрицательного числа аналогично вычитанию: M + -N
эквивалентно M - N
. Это приведет к математическому правильному результату (который может отличаться от результатов, полученных с помощью команд целочисленного деления вашего компьютера). Следует отметить, что для выполнения отмеченного выше свойства знак частного и знак остатка могут различаться.
Если бы вам пришлось ограничить свои арифметические операции сложением, вычитанием, то вы могли бы использовать рекурсию следующим образом:
divit(Dividend, Divisor, Q, R) :-
Dividend > 0, % Only allow positive dividend
Divisor \== 0, % Don't allow 0 divisor
% Use an accumulator (starts at 0) for the quotient, counting subtractions
% of the divisor from the dividend
divit(Dividend, Divisor, 0, Q, R).
% If Dividend < Divisor, then
% quotient accumulator is quotient and dividend is remainder, done!
divit(Dividend, Divisor, Qacc, Qacc, Dividend) :-
Dividend < Divisor.
% If Dividend >= Divisor, then
% subtract the divisor from the dividend
% increment the quotient accumulator
% recurs on updated dividend and quotient accumulator until dividend < divisor
divit(Dividend , Divisor, Qacc, Q, R) :-
Dividend >= Divisor,
D1 is Dividend - Divisor,
Qacc1 is Qacc + 1,
divit(D1, Divisor, Qacc1, Q, R).
0, s(0), ...
вместо целых чисел, но он отказывается говорить, поэтому мы можем только догадываться.
- person ; 13.11.2013
I is X div D
даст вам всю часть, аR is X rem D
даст вам остаток (gprolog.univ-paris1.fr/manual/html_node/gprolog030.html). Я не уверен, почему вы хотите написать рекурсивный предикат. - person   schedule 13.11.2013[user].
и ввести его, либо вам нужно поместить его в файл и загрузить. Все популярные прологи поставляются с инструкциями для этого. - person lurker   schedule 13.11.2013