mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-18 10:53:40 +00:00
Estimated hours taken: _____ <overview or general description of changes> <directory>/<file>: <detailed description of changes>
746 lines
17 KiB
Mathematica
746 lines
17 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 1997-1998 The University of Melbourne.
|
|
% This file may only be copied under the terms of the GNU General
|
|
% Public License - see the file COPYING in the Mercury distribution.
|
|
%-----------------------------------------------------------------------------%
|
|
%
|
|
% file: integer.m
|
|
% authors: aet Mar 1998.
|
|
%
|
|
% Implements an arbitrary precision integer type and basic
|
|
% operations on it. (An arbitrary precision integer may have
|
|
% any number of digits, unlike an int, which is limited to the
|
|
% precision of the machine's int type, which is typically 32 bits.)
|
|
%
|
|
% Note that all operators behave as the equivalent operators on ints do.
|
|
% This includes the division operators: / // rem div mod.
|
|
%
|
|
% Possible improvements:
|
|
%
|
|
% 1) allow negative digits (-base+1 .. base-1) in lists of
|
|
% digits and normalise only when printing. This would
|
|
% probably simplify the division algorithm, also.
|
|
%
|
|
% 2) alternatively, instead of using base=10000, use *all* the
|
|
% bits in an int and make use of the properties of machine
|
|
% arithmetic. Base 10000 doesn't use even half the bits
|
|
% in an int, which is inefficient. (Base 2^14 would be
|
|
% a little better but would require a slightly more
|
|
% complex case conversion on reading and printing.)
|
|
%
|
|
% 3) Use an O(n^(3/2)) algorithm for multiplying large
|
|
% integers, rather than the current O(n^2) method.
|
|
% There's an obvious divide-and-conquer technique,
|
|
% Karatsuba multiplication.
|
|
%
|
|
% 4) We could overload operators so that we can have mixed operations
|
|
% on ints and integers. For example, "integer(1)+3". This
|
|
% would obviate most calls of integer().
|
|
%
|
|
% 5) Use double-ended lists rather than simple lists. This
|
|
% would improve the efficiency of the division algorithm,
|
|
% which reverse lists.
|
|
%
|
|
% 6) Add bit operations (XOR, AND, OR, etc). We would treat
|
|
% the integers as having a 2's complement bit representation.
|
|
% This is easier to do if we use base 2^14 as mentioned above.
|
|
%
|
|
% 7) The implementation of `div' is slower than it need be.
|
|
%
|
|
% 8) Fourier methods such as Schoenhage-Strassen and
|
|
% multiplication via modular arithmetic are left as
|
|
% exercises to the reader. 8^)
|
|
%
|
|
%
|
|
% Of the above, 1) would have the best bang-for-buck, 5) would
|
|
% benefit division and remainder operations quite a lot, and 3)
|
|
% would benefit large multiplications (thousands of digits)
|
|
% and is straightforward to implement.
|
|
|
|
:- module integer.
|
|
|
|
:- interface.
|
|
|
|
:- import_module string.
|
|
|
|
:- type integer.
|
|
|
|
:- pred integer:'<'(integer, integer).
|
|
:- mode integer:'<'(in, in) is semidet.
|
|
|
|
:- pred integer:'>'(integer, integer).
|
|
:- mode integer:'>'(in, in) is semidet.
|
|
|
|
:- pred integer:'=<'(integer, integer).
|
|
:- mode integer:'=<'(in, in) is semidet.
|
|
|
|
:- pred integer:'>='(integer, integer).
|
|
:- mode integer:'>='(in, in) is semidet.
|
|
|
|
:- pred integer:'='(integer, integer).
|
|
:- mode integer:'='(in, in) is semidet.
|
|
|
|
:- func integer(int) = integer.
|
|
|
|
:- func integer__to_string(integer) = string.
|
|
|
|
:- func integer__from_string(string) = integer.
|
|
:- mode integer__from_string(in) = out is semidet.
|
|
|
|
:- func integer:'+'(integer) = integer.
|
|
|
|
:- func integer:'-'(integer) = integer.
|
|
|
|
:- func integer:'+'(integer, integer) = integer.
|
|
|
|
:- func integer:'-'(integer, integer) = integer.
|
|
|
|
:- func integer:'*'(integer, integer) = integer.
|
|
|
|
:- func integer:'//'(integer, integer) = integer.
|
|
|
|
:- func integer:'div'(integer, integer) = integer.
|
|
|
|
:- func integer:'rem'(integer, integer) = integer.
|
|
|
|
:- func integer:'mod'(integer, integer) = integer.
|
|
|
|
:- func integer__abs(integer) = integer.
|
|
|
|
:- pred integer__pow(integer, integer, integer).
|
|
:- mode integer__pow(in, in, out) is det.
|
|
|
|
% :- func integer__float(integer) = float.
|
|
|
|
:- implementation.
|
|
|
|
:- import_module require, list, char, std_util, int.
|
|
|
|
:- type sign == int. % -1, 0, +1
|
|
:- type digit == int. % base 10000 digit
|
|
|
|
:- type comparison
|
|
---> lessthan
|
|
; equal
|
|
; greaterthan.
|
|
|
|
% Note: the list of digits is stored in reverse order.
|
|
% That is, little end first.
|
|
:- type integer
|
|
---> i(sign, list(digit)).
|
|
|
|
% We choose base=10000 since 10000^2+10000 < maxint.
|
|
% XXX: We should check this.
|
|
:- func base = int.
|
|
base = 10000.
|
|
|
|
:- func log10base = int.
|
|
log10base = 4.
|
|
|
|
integer:'<'(X1, X2) :-
|
|
big_cmp(X1, X2) = C,
|
|
C = lessthan.
|
|
|
|
integer:'>'(X1, X2) :-
|
|
big_cmp(X1, X2) = C,
|
|
C = greaterthan.
|
|
|
|
integer:'=<'(X1, X2) :-
|
|
big_cmp(X1, X2) = C,
|
|
( C = lessthan ; C = equal).
|
|
|
|
integer:'>='(X1, X2) :-
|
|
big_cmp(X1, X2) = C,
|
|
( C = greaterthan ; C = equal).
|
|
|
|
integer:'='(X1, X2) :-
|
|
big_cmp(X1, X2) = C,
|
|
C = equal.
|
|
|
|
:- func one = integer.
|
|
one = integer(1).
|
|
|
|
:- func zero = integer.
|
|
zero = integer(0).
|
|
|
|
integer:'+'(X1) =
|
|
X1.
|
|
|
|
integer:'-'(N) =
|
|
big_neg(N).
|
|
|
|
integer:'+'(X1, X2) =
|
|
big_plus(X1, X2).
|
|
|
|
integer:'-'(X1, X2) =
|
|
big_plus(X1, big_neg(X2)).
|
|
|
|
integer:'*'(X1, X2) =
|
|
big_mul(X1, X2).
|
|
|
|
integer:'div'(X1, X2) =
|
|
big_div(X1, X2).
|
|
|
|
integer:'//'(X1, X2) =
|
|
big_quot(X1, X2).
|
|
|
|
integer:'rem'(X1, X2) =
|
|
big_rem(X1, X2).
|
|
|
|
integer:'mod'(X1, X2) =
|
|
big_mod(X1, X2).
|
|
|
|
integer__abs(N) = Abs :-
|
|
( N < integer(0) ->
|
|
Abs = -N
|
|
;
|
|
Abs = N
|
|
).
|
|
|
|
:- func big_neg(integer) = integer.
|
|
big_neg(i(S, Ds)) =
|
|
i(-S, Ds).
|
|
|
|
:- func big_mul(integer, integer) = integer.
|
|
big_mul(i(S1, Ds1), i(S2, Ds2)) = i(S, Ds) :-
|
|
S = S1 * S2,
|
|
Ds = pos_mul(Ds1, Ds2).
|
|
|
|
|
|
:- func big_quot(integer, integer) = integer.
|
|
big_quot(X1, X2) = Q :-
|
|
big_quot_rem(X1, X2, Q, _R).
|
|
|
|
:- func big_rem(integer, integer) = integer.
|
|
big_rem(X1, X2) = R :-
|
|
big_quot_rem(X1, X2, _Q, R).
|
|
|
|
:- func big_div(integer, integer) = integer.
|
|
big_div(X, Y) = Div :-
|
|
big_quot_rem(X, Y, Trunc, Rem),
|
|
(
|
|
( X >= zero, Y >= zero
|
|
; X < zero, Y < zero
|
|
; Rem = zero
|
|
)
|
|
->
|
|
Div = Trunc
|
|
;
|
|
Div = Trunc - one
|
|
).
|
|
|
|
|
|
% XXX: This is dog-slow.
|
|
:- func big_mod(integer, integer) = integer.
|
|
big_mod(X, Y) = X - (X div Y) * Y.
|
|
|
|
% Compare two integers.
|
|
:- func big_cmp(integer, integer) = comparison.
|
|
big_cmp(i(S1, D1), i(S2, D2)) =
|
|
( S1 < S2 ->
|
|
lessthan
|
|
; S1 > S2 ->
|
|
greaterthan
|
|
; (S1=0, S2=0) ->
|
|
equal
|
|
; S1=1 ->
|
|
pos_cmp(D1, D2)
|
|
;
|
|
pos_cmp(D2, D1)
|
|
).
|
|
|
|
:- func pos_cmp(list(digit), list(digit)) = comparison.
|
|
pos_cmp(Xs, Ys) = pos_cmp_2(Xs1, Ys1) :-
|
|
Xs1 = norm(Xs),
|
|
Ys1 = norm(Ys).
|
|
|
|
:- func pos_cmp_2(list(digit), list(digit)) = comparison.
|
|
pos_cmp_2([], []) = equal.
|
|
pos_cmp_2([_X|_Xs], []) = greaterthan.
|
|
pos_cmp_2([], [_Y|_Ys]) = lessthan.
|
|
pos_cmp_2([X|Xs], [Y|Ys]) = Cmp :-
|
|
Res = pos_cmp_2(Xs, Ys),
|
|
( (Res = lessthan ; Res = greaterthan) ->
|
|
Cmp = Res
|
|
; X = Y ->
|
|
Cmp = equal
|
|
; X < Y ->
|
|
Cmp = lessthan
|
|
;
|
|
Cmp = greaterthan
|
|
).
|
|
|
|
:- func big_plus(integer, integer) = integer.
|
|
big_plus(i(S1, Ds1), i(S2, Ds2)) = Sum :-
|
|
( S1 = S2 ->
|
|
Sum = i(S1, pos_plus(Ds1, Ds2))
|
|
; S1 = 1 ->
|
|
C = pos_cmp(Ds1, Ds2),
|
|
( C = lessthan ->
|
|
Sum = i(-1, pos_sub(Ds2, Ds1))
|
|
; C = greaterthan ->
|
|
Sum = i(1, pos_sub(Ds1, Ds2))
|
|
;
|
|
Sum = zero
|
|
)
|
|
;
|
|
C = pos_cmp(Ds1, Ds2),
|
|
(
|
|
C = lessthan ->
|
|
Sum = i(1, pos_sub(Ds2, Ds1))
|
|
; C = greaterthan ->
|
|
Sum = i(-1, pos_sub(Ds1, Ds2))
|
|
;
|
|
Sum = zero
|
|
)
|
|
).
|
|
|
|
integer__from_string(S) = Big :-
|
|
string__to_char_list(S, Cs),
|
|
string_to_integer(Cs) = Big.
|
|
|
|
:- func string_to_integer(list(char)) = integer.
|
|
:- mode string_to_integer(in) = out is semidet.
|
|
string_to_integer(CCs) = Result :-
|
|
( CCs = [],
|
|
fail
|
|
; CCs = [C|Cs],
|
|
% Note:
|
|
% - '-' must be in parentheses.
|
|
% - There can be only one minus sign in a valid string.
|
|
( C = ('-') ->
|
|
Result = i(Sign, Digs),
|
|
Digs = string_to_integer_acc(Cs, []),
|
|
pos_cmp(Digs, []) = Cmp,
|
|
(Cmp = equal ->
|
|
Sign = 0
|
|
;
|
|
Sign = -1
|
|
)
|
|
; char__is_digit(C) ->
|
|
Result = i(Sign, Digs),
|
|
Digs = string_to_integer_acc(CCs, []),
|
|
pos_cmp(Digs, []) = Cmp,
|
|
(Cmp = equal ->
|
|
Sign = 0
|
|
;
|
|
Sign = 1
|
|
)
|
|
;
|
|
fail
|
|
)
|
|
).
|
|
|
|
|
|
:- func string_to_integer_acc(list(char), list(digit)) = list(digit).
|
|
:- mode string_to_integer_acc(in, in) = out is semidet.
|
|
string_to_integer_acc([], Acc) = Acc.
|
|
string_to_integer_acc([C|Cs], Acc) = Result :-
|
|
( char__is_digit(C) ->
|
|
char__to_int(C, D1),
|
|
char__to_int('0', Z),
|
|
Dig = pos_int_to_digits(D1 - Z),
|
|
NewAcc = pos_plus(Dig, mul_by_digit(10, Acc)),
|
|
Result = string_to_integer_acc(Cs, NewAcc)
|
|
;
|
|
fail
|
|
).
|
|
|
|
integer(N) =
|
|
int_to_integer(N).
|
|
|
|
% Note: Since most machines use 2's complement arithmetic,
|
|
% INT_MIN is usually -INT_MAX-1, hence -INT_MIN will
|
|
% cause int overflow. We handle overflow below.
|
|
% We don't check for a negative result from abs(), which
|
|
% would indicate overflow, since we may trap int overflow
|
|
% instead.
|
|
%
|
|
% XXX: What about machines that aren't 2's complement?
|
|
:- func int_to_integer(int) = integer.
|
|
int_to_integer(D) = Int :-
|
|
( int__min_int(D) ->
|
|
% were we to call int__abs, int overflow might occur.
|
|
Int = integer(D + 1) - one
|
|
;
|
|
int__abs(D, AD),
|
|
Int = i(signum(D), pos_int_to_digits(AD))
|
|
).
|
|
|
|
:- func int_max = int.
|
|
int_max = Maxint :-
|
|
int__max_int(Maxint).
|
|
|
|
:- func signum(int) = int.
|
|
signum(N) = SN :-
|
|
( N < 0 ->
|
|
SN = -1
|
|
; N = 0 ->
|
|
SN = 0
|
|
;
|
|
SN = 1
|
|
).
|
|
|
|
:- func pos_int_to_digits(int) = list(digit).
|
|
pos_int_to_digits(D) = Result :-
|
|
( D = 0 ->
|
|
Result = []
|
|
;
|
|
Result = [ S1 | pos_int_to_digits(C1) ],
|
|
chop(D, S1, C1)
|
|
).
|
|
|
|
% Multiply a list of digits by the base.
|
|
:- func mul_base(list(digit)) = list(digit).
|
|
mul_base(Xs) =
|
|
[0|Xs].
|
|
|
|
:- func mul_by_digit(digit, list(digit)) = list(digit).
|
|
mul_by_digit(D, Xs) = Norm :-
|
|
Norm = norm(DXs),
|
|
DXs = mul_by_digit_2(D, Xs).
|
|
|
|
:- func mul_by_digit_2(digit, list(digit)) = list(digit).
|
|
mul_by_digit_2(_D, []) = [].
|
|
mul_by_digit_2(D, [X|Xs]) = [ D*X | mul_by_digit_2(D, Xs) ].
|
|
|
|
% Normalise a list of ints so that each element of the list
|
|
% is a base 10000 digit and there are no extraneous zeros
|
|
% at the big end. (Note: the big end (most significant
|
|
% digit) is at the end of the list.)
|
|
:- func norm(list(int)) = list(digit).
|
|
norm(Xs) =
|
|
nuke_zeros(norm_2(Xs, 0)).
|
|
|
|
:- func nuke_zeros(list(digit)) = list(digit).
|
|
nuke_zeros(Xs) = Zs :-
|
|
list__reverse(Xs, RXs),
|
|
RZs = drop_while(equals_zero, RXs),
|
|
list__reverse(RZs, Zs).
|
|
|
|
:- func norm_2(list(int), digit) = list(digit).
|
|
norm_2([], C) = Xs :-
|
|
( C = 0 ->
|
|
Xs = []
|
|
;
|
|
Xs = [C]
|
|
).
|
|
norm_2([X|Xs], C) = [S1 | norm_2(Xs, C1)] :-
|
|
XC = X + C,
|
|
chop(XC, S1, C1).
|
|
|
|
% Chop an integer into the first two digits of its
|
|
% base 10000 representation.
|
|
:- pred chop(int, digit, digit).
|
|
:- mode chop(in, out, out) is det.
|
|
chop(N, Dig, Carry) :-
|
|
Dig = N mod base,
|
|
Carry = N div base.
|
|
|
|
|
|
:- pred equals_zero(int).
|
|
:- mode equals_zero(in) is semidet.
|
|
equals_zero(X) :-
|
|
X = 0.
|
|
|
|
:- func drop_while(pred(T), list(T)) = list(T).
|
|
:- mode drop_while(pred(in) is semidet, in) = out is det.
|
|
drop_while(_F, []) = [].
|
|
drop_while(F, [X|Xs]) =
|
|
( call(F,X) ->
|
|
drop_while(F, Xs)
|
|
;
|
|
[X|Xs]
|
|
).
|
|
|
|
:- func pos_plus(list(digit), list(digit)) = list(digit).
|
|
pos_plus(Xs, Ys) = Norm :-
|
|
Norm = norm(Sums),
|
|
Sums = add_pairs(Xs, Ys).
|
|
|
|
:- func pos_sub(list(digit), list(digit)) = list(digit).
|
|
pos_sub(Xs, Ys) = Norm :-
|
|
Norm = norm(Diffs),
|
|
Diffs = diff_pairs(Xs, Ys).
|
|
|
|
:- func add_pairs(list(int), list(int)) = list(int).
|
|
add_pairs(XXs, YYs) = XYs :-
|
|
( XXs = [],
|
|
XYs = YYs
|
|
; YYs = [], XXs = [_|_],
|
|
XYs = XXs
|
|
; XXs = [X|Xs], YYs = [Y|Ys],
|
|
XYs = [ X+Y | add_pairs(Xs, Ys) ]
|
|
).
|
|
|
|
:- func diff_pairs(list(int), list(int)) = list(int).
|
|
diff_pairs(XXs, YYs) = XYs :-
|
|
( XXs = [],
|
|
list__map(int_negate, YYs, XYs)
|
|
; YYs = [], XXs = [_|_],
|
|
XYs = XXs
|
|
; XXs = [X|Xs], YYs = [Y|Ys],
|
|
XYs = [ X-Y | diff_pairs(Xs, Ys) ]
|
|
).
|
|
|
|
:- pred int_negate(int, int).
|
|
:- mode int_negate(in, out) is det.
|
|
int_negate(M, NegM) :-
|
|
NegM = -M.
|
|
|
|
:- func pos_mul(list(digit), list(digit)) = list(digit).
|
|
pos_mul([], _Ys) = [].
|
|
pos_mul([X|Xs], Ys) = Sum :-
|
|
mul_by_digit(X, Ys) = XYs,
|
|
pos_mul(Xs, Ys) = XsYs,
|
|
mul_base(XsYs) = TenXsYs,
|
|
Sum = pos_plus(XYs, TenXsYs).
|
|
|
|
integer__to_string(N) = S :-
|
|
integer_to_string_2(N) = S.
|
|
|
|
:- func integer_to_string_2(integer) = string.
|
|
integer_to_string_2(i(S, Ds)) = Str :-
|
|
string__append(Sgn, digits_to_string(Ds), Str),
|
|
( S = (-1) ->
|
|
Sgn = "-"
|
|
;
|
|
Sgn = ""
|
|
).
|
|
|
|
:- func digits_to_string(list(digit)) = string.
|
|
digits_to_string(DDs) = Str :-
|
|
list__reverse(DDs, Rev),
|
|
( Rev = [],
|
|
Str = "0"
|
|
; Rev = [R|Rs],
|
|
string__int_to_string(R, S),
|
|
list__map(digit_to_string, Rs, Ss),
|
|
string__append_list([S|Ss], Str)
|
|
).
|
|
|
|
:- pred digit_to_string(digit, string).
|
|
:- mode digit_to_string(in, out) is det.
|
|
digit_to_string(D, S) :-
|
|
string__int_to_string(D, S1),
|
|
Width = log10base,
|
|
string__pad_left(S1, '0', Width, S).
|
|
|
|
|
|
:- pred big_quot_rem(integer, integer, integer, integer).
|
|
:- mode big_quot_rem(in, in, out, out) is det.
|
|
big_quot_rem(N1, N2, Qt, Rm) :-
|
|
( N2 = zero ->
|
|
error("integer__big_quot_rem: division by zero")
|
|
; N1 = zero ->
|
|
Qt = zero,
|
|
Rm = N2
|
|
;
|
|
N1 = i(S1, D1),
|
|
N2 = i(S2, D2),
|
|
Qt = i(SQ, Q),
|
|
Rm = i(SR, R),
|
|
( pos_is_zero(R) ->
|
|
SR = 0
|
|
;
|
|
SR = S1
|
|
),
|
|
( pos_is_zero(Q) ->
|
|
SQ = 0
|
|
;
|
|
SQ = S1 * S2
|
|
),
|
|
Q = norm(QRR),
|
|
R = norm(RRR),
|
|
list__reverse(RR, RRR),
|
|
list__reverse(QR, QRR),
|
|
list__reverse(D1, D1R),
|
|
list__reverse(D2, D2R),
|
|
quot_rem_rev([], D1R, D2R, QR, RR)
|
|
).
|
|
|
|
% Algorithm: We take digits from the start of U (call them Ur)
|
|
% and divide by V to get a digit Q of the ratio.
|
|
% Essentially the usual long division algorithm.
|
|
% Qhat is an approximation to Q. It may be at most 2 too big.
|
|
%
|
|
% If the first digit of V is less than base/2, then
|
|
% we scale both the numerator and denominator. This
|
|
% way, we can use Knuth's[*] nifty trick for finding
|
|
% an accurate approximation to Q. That's all we use from
|
|
% Knuth; his MIX algorithm is fugly.
|
|
%
|
|
% [*] Knuth, Semi-numerical algorithms.
|
|
%
|
|
:- pred quot_rem_rev(list(digit), list(digit), list(digit), list(digit),
|
|
list(digit)).
|
|
:- mode quot_rem_rev(in, in, in, out, out) is det.
|
|
quot_rem_rev(Ur, U, V, Qt, Rm) :-
|
|
( V = [V0|_] ->
|
|
BaseDiv2 = base div 2,
|
|
( V0 < BaseDiv2 ->
|
|
quot_rem_rev_2(mul_by_digit_rev(M, Ur),
|
|
mul_by_digit_rev(M, U),
|
|
mul_by_digit_rev(M, V), Q, R),
|
|
Qt = Q,
|
|
Rm = div_by_digit_rev(M, R),
|
|
M = base div (V0 + 1)
|
|
;
|
|
quot_rem_rev_2(Ur, U, V, Qt, Rm)
|
|
)
|
|
;
|
|
error("integer__quot_rem_rev: software error")
|
|
).
|
|
|
|
:- pred quot_rem_rev_2(list(digit), list(digit), list(digit), list(digit),
|
|
list(digit)).
|
|
:- mode quot_rem_rev_2(in, in, in, out, out) is det.
|
|
quot_rem_rev_2(Ur, U, V, Qt, Rm) :-
|
|
( pos_lt_rev(Ur, V) ->
|
|
( U = [],
|
|
Qt = [0],
|
|
Rm = Ur
|
|
; U = [Ua|Uas],
|
|
quot_rem_rev_2(UrUa, Uas, V, Quot, Rem),
|
|
Qt = [0|Quot],
|
|
Rm = Rem,
|
|
list__append(Ur, [Ua], UrUa)
|
|
)
|
|
;
|
|
( U = [],
|
|
Qt = [Q],
|
|
Rm = NewUr
|
|
; U = [Ua|Uas],
|
|
quot_rem_rev_2(NewUrUa, Uas, V, Quot, Rem),
|
|
Qt = [Q|Quot],
|
|
Rm = Rem,
|
|
list__append(NewUr, [Ua], NewUrUa)
|
|
),
|
|
NewUr = pos_sub_rev(Ur, mul_by_digit_rev(Q, V)),
|
|
( pos_geq_rev(Ur, mul_by_digit_rev(Qhat, V)) ->
|
|
Q = Qhat
|
|
; pos_geq_rev(Ur, mul_by_digit_rev(Qhat - 1, V)) ->
|
|
Q = Qhat - 1
|
|
;
|
|
Q = Qhat - 2
|
|
),
|
|
V0 = head(V),
|
|
U0 = head(Ur),
|
|
LengthUr = length(Ur),
|
|
LengthV = length(V),
|
|
( LengthUr > LengthV ->
|
|
Qhat = (U0*B+U1) div V0,
|
|
U1 = head(tail(Ur))
|
|
;
|
|
Qhat = U0 div V0
|
|
),
|
|
B = base
|
|
).
|
|
|
|
:- func length(list(T)) = int.
|
|
length([]) = 0.
|
|
length([_|Xs]) = 1 + length(Xs).
|
|
|
|
:- func head(list(T)) = T.
|
|
head(HT) = H :-
|
|
( HT = [Hd|_T] ->
|
|
H = Hd
|
|
;
|
|
error("integer__head: []")
|
|
).
|
|
|
|
:- func tail(list(T)) = list(T).
|
|
tail(HT) = T :-
|
|
( HT = [_H|Tl] ->
|
|
T = Tl
|
|
;
|
|
error("integer__tail: []")
|
|
).
|
|
|
|
|
|
% Multiply a *reverse* list of digits (big end first)
|
|
% by a digit.
|
|
%
|
|
% Note: All functions whose name has the suffix "_rev"
|
|
% operate on such reverse lists of digits.
|
|
:- func mul_by_digit_rev(digit, list(digit)) = list(digit).
|
|
mul_by_digit_rev(D, Xs) = Rev :-
|
|
list__reverse(Xs, RXs),
|
|
Mul = mul_by_digit(D, RXs),
|
|
list__reverse(Mul, Rev).
|
|
|
|
:- func div_by_digit_rev(digit, list(digit)) = list(digit).
|
|
div_by_digit_rev(_D, []) = [].
|
|
div_by_digit_rev(D, [X|Xs]) = div_by_digit_rev_2(X, Xs, D).
|
|
|
|
:- func div_by_digit_rev_2(digit, list(digit), digit) = list(digit).
|
|
div_by_digit_rev_2(X, Xs, D) = [Q|Rest] :-
|
|
Q = X div D,
|
|
( Xs = [],
|
|
Rest = []
|
|
; Xs = [H|T],
|
|
Rest = div_by_digit_rev_2(R*base + H, T, D),
|
|
R = X rem D
|
|
).
|
|
|
|
:- func pos_sub_rev(list(digit), list(digit)) = list(digit).
|
|
pos_sub_rev(Xs, Ys) = Rev :-
|
|
list__reverse(Xs, RXs),
|
|
list__reverse(Ys, RYs),
|
|
Sum = pos_sub(RXs, RYs),
|
|
list__reverse(Sum, Rev).
|
|
|
|
:- pred pos_lt_rev(list(digit), list(digit)).
|
|
:- mode pos_lt_rev(in, in) is semidet.
|
|
pos_lt_rev(Xs, Ys) :-
|
|
list__reverse(Xs, RXs),
|
|
list__reverse(Ys, RYs),
|
|
C = big_cmp(i(1, RXs), i(1, RYs)),
|
|
C = lessthan.
|
|
|
|
:- pred pos_geq_rev(list(digit), list(digit)).
|
|
:- mode pos_geq_rev(in, in) is semidet.
|
|
pos_geq_rev(Xs, Ys) :-
|
|
list__reverse(Xs, RXs),
|
|
list__reverse(Ys, RYs),
|
|
C = big_cmp(i(1, RXs), i(1, RYs)),
|
|
( C = greaterthan ; C = equal ).
|
|
|
|
:- pred pos_is_zero(list(digit)).
|
|
:- mode pos_is_zero(in) is semidet.
|
|
pos_is_zero(Ds) :-
|
|
NDs = nuke_zeros(Ds),
|
|
NDs = [].
|
|
|
|
integer__pow(A, N, P) :-
|
|
Zero = zero,
|
|
( N < Zero ->
|
|
error("integer__pow: negative exponent")
|
|
;
|
|
P = big_pow(A, N)
|
|
).
|
|
|
|
:- func big_pow(integer, integer) = integer.
|
|
big_pow(A, N) = P :-
|
|
( N = zero ->
|
|
P = one
|
|
; big_odd(N) ->
|
|
P = A * big_pow(A, N-one)
|
|
; % even
|
|
P = big_sqr(big_pow(A, N//two))
|
|
).
|
|
|
|
:- func two = integer.
|
|
two = integer(2).
|
|
|
|
:- func big_sqr(integer) = integer.
|
|
big_sqr(A) = A * A.
|
|
|
|
:- pred big_odd(integer).
|
|
:- mode big_odd(in) is semidet.
|
|
big_odd(N) :-
|
|
N = i(_S, [D|_Ds]),
|
|
Dmod2 is D mod 2,
|
|
Dmod2 = 1.
|
|
|