4

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

4

3 回答 3

3

为此,有预定义的可评估函子。

(div)/2并且(mod)/2总是四舍五入。LIA-1、Knuth 等推荐。

(//)/2并向(rem)/2零舍入(实际上,它是定义的实现,但所有当前的实现都是这样做的)。current_prolog_flag(integer_rounding_function, F)你可以通过which give in current implementations来询问这个问题toward_zero

这些对之间的差异仅在涉及负数时显示。这是一场人们更喜欢的宗教战争。ISO/IEC 10967:2012 与语言无关的算术 (vl. LIA-1) 仅提供向下舍入“由于易于错误使用” (C.5.1.2.2) 的向零,而 Fortran 和像 C 之类的追随者去向零调用它“代数”(6.5.5)。另请参阅: 使用截断朝向负无穷与朝向零的优点

于 2013-11-13T15:10:35.773 回答
0

我假设您的老师正在尝试教授递归。

除法是重复减法,就像乘法是重复加法一样,n'est-ce-pas ?

由于变量只能被赋值一次,一个常见的 prolog 习惯用法是有一个外部“公共”谓词,它调用一个使用累加器并执行实际工作的私有“工人”谓词。这导致我们得到这样的解决方案。

%
% 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求得商Q和余数R,性质

M = N * Q + R

成立。这应该会通知您商和余数所需的符号。别忘了负数的加法和减法一样:M + -N等价于M - N. 这将使您获得数学上正确的结果(可能与通过计算机的整数除法指令获得的结果不同)。应该注意,要使上述属性为真,商的符号和余数的符号可能不同。

于 2013-11-13T19:16:26.060 回答
0

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

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).
于 2013-11-13T14:39:44.940 回答