4

Trying to figure out how to write a recursive predicate divide_by(X, D, I, R) that takes as input a positive integer X and a divisor D, and returns the answer as the whole number part I and the remainder part R, however, I can't seem to get my head around Prolog. How would I go about doing this?

Sumurai8
  • 20,333
  • 11
  • 66
  • 100
user2326995
  • 163
  • 1
  • 11
  • Have you tried reading a tutorial? And why do you need a recursive predicate instead of integer arithmetic? –  Nov 13 '13 at 12:53
  • As I said mate, brand new to prolog and can't find any tutorials that will show me what I need to do. I'm not sure I understand what you mean – user2326995 Nov 13 '13 at 12:58
  • Well, mate, there are enough tutorials that will show you what you need to do, if you take time to read them. And what I mean is, `I is X div D` will give you the whole part, and `R is X rem D` will give you the remainder (http://gprolog.univ-paris1.fr/manual/html_node/gprolog030.html). I'm not sure why you want to write a _recursive_ predicate. –  Nov 13 '13 at 13:02
  • So you'd enter the code like this?: divide_by(X, D, I, R):- I is X div D, R is X rem D and ask it like -?-divide_by(12, 5, I, R). for example? – user2326995 Nov 13 '13 at 14:01
  • you can but there is no recursion there:) – ssbarbee Nov 13 '13 at 14:10
  • I put it in and it won't work at all haha. Don't understand this! – user2326995 Nov 13 '13 at 14:12
  • @user2326995 can you please explain "won't work at all"? What's the error? I entered the code you showed in your prior comment and it worked fine. Did you end the last clause with a period? – lurker Nov 13 '13 at 14:23
  • JIP:-?-divide_by(12, 5, I, R). - Warning, the predicate divide_by/4 is undefined. No is what I get mate! haha! – user2326995 Nov 13 '13 at 14:58
  • Sounds like you didn't define your predicate properly. To enter the code, you have to go into user mode first `[user].` and enter it, or you need to put it into a file and load it. All of the popular prologs come with instructions for this. – lurker Nov 13 '13 at 14:59

3 Answers3

3

There are predefined evaluable functors for this.

(div)/2 and (mod)/2 always rounding down. Recommended by LIA-1, Knuth etc.

(//)/2 and (rem)/2 rounding toward zero (actually, it's implementation defined, but all current implementations do it like that). You can ask this via current_prolog_flag(integer_rounding_function, F) which gives in current implementations toward_zero.

The difference between those pairs shows only when negative numbers are involved. It is kind of a religious war which one to prefer. ISO/IEC 10967:2012 Language independent arithmetic (vl. LIA-1) only provides rounding down "due to proneness for erroneous use" (C.5.1.2.2) of toward_zero, whereas Fortran and followers like C go for toward_zero calling it "algebraic" (6.5.5). See also: Advantages of using truncation towards minus infinity vs towards zero

Community
  • 1
  • 1
false
  • 10,264
  • 13
  • 101
  • 209
0

If you had to limit your arithmetic operations to addition, subtraction, then you could use recursion as follows:

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).
lurker
  • 56,987
  • 9
  • 69
  • 103
  • I am assuming he actually has something like `0, s(0), ...` instead of integers but he refuses to say so we can just guess. –  Nov 13 '13 at 14:43
  • @Boris - I haven't been given anything to enter into it, it will just be integers – user2326995 Nov 13 '13 at 14:59
0

I'm assuming your teacher is trying to teach recursion.

Division is repeated subtraction, just as multiplication is repeated addition, n'est-ce-pas?

A common prolog idiom, since variables can only be assigned a value once, is to have an outer "public" predicate, that invokes a private "worker" predicate that uses the accumulator(s) and does the actual work. This leads us to a solution like this.

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

From this it should be pretty easy to modify the outer public predicate to account for signed operands, bearing in mind that

  • +/+ yields +
  • +/- yields -
  • -/+ yields -
  • -/- yields +

And that having evaluated M/N to obtain quotient Q and remainder R, the property

M = N * Q + R

holds true. That should inform you as to the required signs for the quotient and remainder. Don't forget that addition of a negative number is the same as subtraction: M + -N is equivalent to M - N. That will get you to results that are mathematically correct (which may differ from the results obtained via your computer's integer division instructions). One should note that for the property noted above to be true, the sign of the quotient and the sign of the remainder may differ.

Nicholas Carey
  • 71,308
  • 16
  • 93
  • 135