Integer Prolog中的除法与余数

Integer Prolog中的除法与余数,integer,prolog,division,modulus,Integer,Prolog,Division,Modulus,试图弄清楚如何编写一个递归谓词除以(X,D,I,R),它以一个正整数X和一个除数D作为输入,并以整数I部分和余数R部分返回答案,然而,我似乎无法理解Prolog。我该怎么做呢?如果必须将算术运算限制为加法、减法,那么可以使用递归,如下所示: divit(Dividend, Divisor, Q, R) :- Dividend > 0, % Only allow positive dividend Divisor \== 0, % Don't allow 0 div

试图弄清楚如何编写一个递归谓词除以(X,D,I,R),它以一个正整数X和一个除数D作为输入,并以整数I部分和余数R部分返回答案,然而,我似乎无法理解Prolog。我该怎么做呢?

如果必须将算术运算限制为加法、减法,那么可以使用递归,如下所示:

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).
divit(被除数、除数、Q、R):-
股息>0%,仅允许正股息
除数\==0,%n不允许0除数
%使用累加器(从0开始)计算商,计算减法
%除数的除数
除数(被除数,除数,0,Q,R)。
%如果除数<除数,则
%商累加器是商,红利是余数,完成!
除数(股息、除数、Qacc、Qacc、股息):-
除数。
%如果股息>=除数,则
%从股息中减去除数
%增加商累加器
%在更新的除数和商累加器上递归,直到除数<除数
除数(被除数、除数、Qacc、Q、R):-
股息>=除数,
D1是除数因子,
Qacc1是Qacc+1,
除数(D1,除数,Qacc1,Q,R)。

此函数有预定义的可计算函子

(div)/2和
(mod)/2始终向下舍入。由LIA-1、Knuth等推荐

(//)/2
(rem)/2
向零舍入(实际上,它是实现定义的,但所有当前的实现都是这样做的)。您可以通过
current\u prolog\u标志(integer\u rounding\u function,F)
来询问这一点,该标志在当前实现
中给出了向零的方向

只有当涉及负数时,这些对之间的差异才会显示出来。这是一场人们更喜欢的宗教战争。ISO/IEC 10967:2012语言无关算术(vl.LIA-1)只提供了“由于错误使用的倾向”(C.5.1.2.2)向零舍入,而Fortran和类似C的追随者则向零舍入,称之为“代数”(6.5.5)。另见:

我想你的老师是在教递归

除法是重复的减法,就像乘法是重复的加法,不是吗

由于变量只能被赋值一次,一个常见的prolog习惯用法是有一个外部的“public”谓词,它调用一个私有的“worker”谓词,该谓词使用累加器并执行实际工作。这就引出了这样的解决方案

%
% 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!

这是真的。这应该告诉你商数和余数所需的符号。不要忘记负数的加法和减法是一样的:
M+-N
相当于
M-N
。这将使您得到数学上正确的结果(可能与通过计算机的整数除法指令获得的结果不同)。需要注意的是,如果上述属性为真,商的符号和余数的符号可能不同。

您是否阅读过教程?为什么需要递归谓词而不是整数算术呢?正如我说的,mate是prolog的新手,找不到任何教程来说明我需要做什么。我不确定我是否理解你的意思。好吧,伙计,如果你花时间阅读,有足够多的教程可以告诉你需要做什么。我的意思是,
I is X div D
会给你整个部分,
R is X rem D
会给你剩下的部分()。我不知道你为什么要写递归谓词。所以你应该像这样输入代码:除以(X,d,I,R):-I是X div d,R是X rem d,然后像这样问-?-除以(12,5,I,R)。例如?你可以,但那里没有递归:)我假设他实际上有类似于
0,s(0),…
的东西,而不是整数,但他拒绝说,所以我们只能猜测。@Boris-我没有得到任何东西来输入它,它只会是整数
M = N * Q + R