Деление и остаток в Прологе

Попытка выяснить, как написать рекурсивный предикат Division_by(X, D, I, R), который принимает в качестве входных данных положительное целое число X и делитель D и возвращает ответ как целую часть числа I и оставшуюся часть R, однако , я не могу понять Пролог. Как мне это сделать?


person user2326995    schedule 13.11.2013    source источник
comment
Учебник читать не пробовали? И зачем вам рекурсивный предикат вместо целочисленной арифметики?   -  person    schedule 13.11.2013
comment
Как я уже сказал, приятель, я новичок в прологе и не могу найти никаких руководств, которые покажут мне, что мне нужно делать. Я не уверен, что понимаю, что вы имеете в виду   -  person user2326995    schedule 13.11.2013
comment
Что ж, приятель, есть достаточно учебных пособий, которые покажут вам, что вам нужно делать, если вы потратите время на их прочтение. Я имею в виду, что I is X div D даст вам всю часть, а R is X rem D даст вам остаток (gprolog.univ-paris1.fr/manual/html_node/gprolog030.html). Я не уверен, почему вы хотите написать рекурсивный предикат.   -  person    schedule 13.11.2013
comment
Таким образом, вы вводите код следующим образом?: Division_by(X, D, I, R):- I is X div D, R is X rem D и спрашивайте, как -?-divide_by(12, 5, I, R ). Например?   -  person user2326995    schedule 13.11.2013
comment
можно, но там нет рекурсии :)   -  person ssBarBee    schedule 13.11.2013
comment
Я вставил его, и он вообще не работает, ха-ха. Не понимаю этого!   -  person user2326995    schedule 13.11.2013
comment
@user2326995 user2326995 не могли бы вы объяснить, что это вообще не сработает? В чем ошибка? Я ввел код, который вы показали в предыдущем комментарии, и он сработал нормально. Вы поставили точку в последнем предложении?   -  person lurker    schedule 13.11.2013
comment
JIP:-?-разделить_на(12, 5, I, R). - Предупреждение, предикат Division_by/4 не определен. Нет, это то, что я получаю, приятель! ха-ха!   -  person user2326995    schedule 13.11.2013
comment
Похоже, вы неправильно определили свой предикат. Чтобы ввести код, вам нужно сначала войти в пользовательский режим [user]. и ввести его, либо вам нужно поместить его в файл и загрузить. Все популярные прологи поставляются с инструкциями для этого.   -  person lurker    schedule 13.11.2013


Ответы (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). См. также: Преимущества использования усечения в направлении минус бесконечность против нуля

person false    schedule 13.11.2013

Я предполагаю, что ваш учитель пытается научить рекурсии.

Деление — это многократное вычитание, так же как умножение — это многократное сложение, 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. Это приведет к математическому правильному результату (который может отличаться от результатов, полученных с помощью команд целочисленного деления вашего компьютера). Следует отметить, что для выполнения отмеченного выше свойства знак частного и знак остатка могут различаться.

person Nicholas Carey    schedule 13.11.2013

Если бы вам пришлось ограничить свои арифметические операции сложением, вычитанием, то вы могли бы использовать рекурсию следующим образом:

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).
person lurker    schedule 13.11.2013
comment
Я предполагаю, что у него на самом деле есть что-то вроде 0, s(0), ... вместо целых чисел, но он отказывается говорить, поэтому мы можем только догадываться. - person ; 13.11.2013
comment
@Boris - мне ничего не дали для ввода, это будут просто целые числа - person user2326995; 13.11.2013