mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-11 20:03:28 +00:00
Discussion of these changes can be found on the Mercury developers
mailing list archives from June 2018.
COPYING.LIB:
Add a special linking exception to the LGPL.
*:
Update references to COPYING.LIB.
Clean up some minor errors that have accumulated in copyright
messages.
2152 lines
59 KiB
Mathematica
2152 lines
59 KiB
Mathematica
%---------------------------------------------------------------------------%
|
|
% vim: ts=4 sw=4 et ft=mercury
|
|
%---------------------------------------------------------------------------%
|
|
% Copyright (C) 1997-2000, 2003-2007, 2011-2012 The University of Melbourne.
|
|
% Copyright (C) 2014-2018 The Mercury team.
|
|
% This file is distributed under the terms specified in COPYING.LIB.
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% File: integer.m.
|
|
% Main authors: aet, Dan Hazel <odin@svrc.uq.edu.au>.
|
|
% Stability: high.
|
|
%
|
|
% This modules defines an arbitrary precision integer type (named "integer")
|
|
% and basic arithmetic operations on it.
|
|
%
|
|
% The builtin Mercury type "int" is implemented as machine integers,
|
|
% which on virtually all modern machines will be 32 or 64 bits in size.
|
|
% If you need to manipulate integers that may not fit into this many bits,
|
|
% you will want to use "integer"s instead of "int"s.
|
|
%
|
|
% NOTE: All the operators we define on "integers" behave the same as the
|
|
% corresponding operators on "int"s. This includes the operators related
|
|
% to division: /, //, rem, div, and mod.
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- module integer.
|
|
:- interface.
|
|
|
|
:- type integer.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Constants.
|
|
%
|
|
|
|
% Equivalent to integer(-1).
|
|
%
|
|
:- func negative_one = integer.
|
|
|
|
% Equivalent to integer(0).
|
|
%
|
|
:- func zero = integer.
|
|
|
|
% Equivalent to integer(1).
|
|
%
|
|
:- func one = integer.
|
|
|
|
% Equivalent to integer(2).
|
|
%
|
|
:- func two = integer.
|
|
|
|
% Equivalent to integer(10).
|
|
%
|
|
:- func ten = integer.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% X < Y: Succeed if and only if X is less than Y.
|
|
%
|
|
:- pred '<'(integer::in, integer::in) is semidet.
|
|
|
|
% X > Y: Succeed if and only if X is greater than Y.
|
|
%
|
|
:- pred '>'(integer::in, integer::in) is semidet.
|
|
|
|
% X =< Y: Succeed if and only if X is less than or equal to Y.
|
|
%
|
|
:- pred '=<'(integer::in, integer::in) is semidet.
|
|
|
|
% X >= Y: Succeed if and only if X is greater than or equal to Y.
|
|
%
|
|
:- pred '>='(integer::in, integer::in) is semidet.
|
|
|
|
% Absolute value.
|
|
%
|
|
:- func abs(integer) = integer.
|
|
|
|
% True if the argument is equal to integer.zero.
|
|
%
|
|
:- pred is_zero(integer::in) is semidet.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Unary plus.
|
|
%
|
|
:- func '+'(integer) = integer.
|
|
|
|
% Unary minus.
|
|
%
|
|
:- func '-'(integer) = integer.
|
|
|
|
% Addition.
|
|
%
|
|
:- func integer + integer = integer.
|
|
|
|
% Subtraction.
|
|
%
|
|
:- func integer - integer = integer.
|
|
|
|
% Multiplication.
|
|
%
|
|
:- func integer * integer = integer.
|
|
|
|
% Flooring integer division.
|
|
% Behaves as int.div.
|
|
%
|
|
:- func integer div integer = integer.
|
|
|
|
% Truncating integer division.
|
|
% Behaves as int.(//).
|
|
%
|
|
:- func integer // integer = integer.
|
|
|
|
% Modulus.
|
|
% Behaves as int.mod.
|
|
%
|
|
:- func integer mod integer = integer.
|
|
|
|
% Remainder.
|
|
% Behaves as int.rem.
|
|
%
|
|
:- func integer rem integer = integer.
|
|
|
|
% divide_with_rem(X, Y, Q, R) where Q = X // Y and R = X rem Y
|
|
% where both answers are calculated at the same time.
|
|
%
|
|
:- pred divide_with_rem(integer::in, integer::in,
|
|
integer::out, integer::out) is det.
|
|
|
|
% Exponentiation.
|
|
% pow(X, Y) = Z: Z is X raised to the Yth power.
|
|
% Throws a `math.domain_error' exception if Y is negative.
|
|
%
|
|
:- func pow(integer, integer) = integer.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Left shift.
|
|
% Behaves as int.(<<).
|
|
%
|
|
:- func integer << int = integer.
|
|
|
|
% Right shift.
|
|
% Behaves as int.(>>).
|
|
%
|
|
:- func integer >> int = integer.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Bitwise complement.
|
|
%
|
|
:- func \ integer = integer.
|
|
|
|
% Bitwise and.
|
|
%
|
|
:- func integer /\ integer = integer.
|
|
|
|
% Bitwise or.
|
|
%
|
|
:- func integer \/ integer = integer.
|
|
|
|
% Bitwise exclusive or (xor).
|
|
%
|
|
:- func integer `xor` integer = integer.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Convert an integer to an int.
|
|
% Fails if the integer is not in the range [min_int, max_int].
|
|
%
|
|
:- pred to_int(integer::in, int::out) is semidet.
|
|
|
|
% As above, but throws an exception rather than failing.
|
|
%
|
|
:- func det_to_int(integer) = int.
|
|
|
|
:- func int(integer) = int.
|
|
:- pragma obsolete(int/1).
|
|
|
|
%---------------------%
|
|
|
|
% Convert an integer to a uint.
|
|
% Fails if the integer is not in the range [0, max_uint].
|
|
%
|
|
:- pred to_uint(integer::in, uint::out) is semidet.
|
|
|
|
% As above, but throws an exception rather than failing.
|
|
%
|
|
:- func det_to_uint(integer) = uint.
|
|
|
|
% Convert an integer to an int8.
|
|
% Fails if the integer is not in the range [-128, 127].
|
|
%
|
|
:- pred to_int8(integer::in, int8::out) is semidet.
|
|
|
|
% As above, but throws an exception rather than failing.
|
|
%
|
|
:- func det_to_int8(integer) = int8.
|
|
|
|
% Convert an integer to a uint8.
|
|
% Fails if the integer is not in the range [0, 255].
|
|
%
|
|
:- pred to_uint8(integer::in, uint8::out) is semidet.
|
|
|
|
% As above, but throws an exception rather than failing.
|
|
%
|
|
:- func det_to_uint8(integer) = uint8.
|
|
|
|
% Convert an integer to an int16.
|
|
% Fails if the integer is not in the range [-32768, 32767].
|
|
%
|
|
:- pred to_int16(integer::in, int16::out) is semidet.
|
|
|
|
% As above, but throws an exception rather than failing.
|
|
%
|
|
:- func det_to_int16(integer) = int16.
|
|
|
|
% Convert an integer to a uint16.
|
|
% Fails if the integer is not in the range [0, 65535].
|
|
%
|
|
:- pred to_uint16(integer::in, uint16::out) is semidet.
|
|
|
|
% As above, but throws an exception rather than failing.
|
|
%
|
|
:- func det_to_uint16(integer) = uint16.
|
|
|
|
% Convert an integer to an int32.
|
|
% Fails if the integer is not in the range [-2147483648, 2147483647].
|
|
%
|
|
:- pred to_int32(integer::in, int32::out) is semidet.
|
|
|
|
% As above, but throws an exception rather than failing.
|
|
%
|
|
:- func det_to_int32(integer) = int32.
|
|
|
|
% Convert an integer to a uint32.
|
|
% Fails if the integer is not in range [0, 4294967295].
|
|
%
|
|
:- pred to_uint32(integer::in, uint32::out) is semidet.
|
|
|
|
% As above, but throws an exception rather than failing.
|
|
%
|
|
:- func det_to_uint32(integer) = uint32.
|
|
|
|
% Convert an integer to an int64.
|
|
% Fails if the integer is not in the range [-2147483648, 2147483647].
|
|
%
|
|
:- pred to_int64(integer::in, int64::out) is semidet.
|
|
|
|
% As above, but throws an exception rather than failing.
|
|
%
|
|
:- func det_to_int64(integer) = int64.
|
|
|
|
% Convert an integer to a uint64.
|
|
% Fails if the integer is not in range [0, 4294967295].
|
|
%
|
|
:- pred to_uint64(integer::in, uint64::out) is semidet.
|
|
|
|
% As above, but throws an exception rather than failing.
|
|
%
|
|
:- func det_to_uint64(integer) = uint64.
|
|
|
|
%---------------------%
|
|
|
|
% Convert an integer to a float.
|
|
%
|
|
:- func float(integer) = float.
|
|
|
|
%---------------------%
|
|
|
|
% Convert an integer to a string (in base 10).
|
|
%
|
|
:- func to_string(integer) = string.
|
|
|
|
% to_base_string(Integer, Base) = String:
|
|
%
|
|
% Convert an integer to a string in a given Base.
|
|
%
|
|
% Base must be between 2 and 36, both inclusive; if it is not,
|
|
% the predicate will throw an exception.
|
|
%
|
|
:- func to_base_string(integer, int) = string.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Convert an int to integer.
|
|
%
|
|
:- func integer(int) = integer.
|
|
|
|
% Convert a uint to an integer.
|
|
%
|
|
:- func from_uint(uint) = integer.
|
|
|
|
% Convert an int8 to an integer.
|
|
%
|
|
:- func from_int8(int8) = integer.
|
|
|
|
% Convert a uint8 to an integer.
|
|
%
|
|
:- func from_uint8(uint8) = integer.
|
|
|
|
% Convert an int16 to an integer.
|
|
%
|
|
:- func from_int16(int16) = integer.
|
|
|
|
% Convert a uint16 to an integer.
|
|
%
|
|
:- func from_uint16(uint16) = integer.
|
|
|
|
% Convert an int32 to an integer.
|
|
%
|
|
:- func from_int32(int32) = integer.
|
|
|
|
% Convert a uint32 to an integer.
|
|
%
|
|
:- func from_uint32(uint32) = integer.
|
|
|
|
% Convert an int64 to an integer.
|
|
%
|
|
:- func from_int64(int64) = integer.
|
|
|
|
% Convert a uint64 to an integer.
|
|
%
|
|
:- func from_uint64(uint64) = integer.
|
|
|
|
% Convert a string to an integer. The string must contain only digits
|
|
% [0-9], optionally preceded by a plus or minus sign. If the string does
|
|
% not match this syntax, then the predicate fails.
|
|
%
|
|
:- func from_string(string::in) = (integer::out) is semidet.
|
|
:- pragma obsolete(from_string/1).
|
|
:- pred from_string(string::in, integer::out) is semidet.
|
|
|
|
% As above, but throws an exception rather than failing.
|
|
%
|
|
:- func det_from_string(string) = integer.
|
|
|
|
% Convert a string in the specified base (2-36) to an integer.
|
|
% The string must contain one or more digits in the specified base,
|
|
% optionally preceded by a plus or minus sign. For bases > 10, digits
|
|
% 10 to 35 are represented by the letters A-Z or a-z. If the string
|
|
% does not match this syntax, then the predicate fails.
|
|
%
|
|
:- func from_base_string(int, string) = integer is semidet.
|
|
:- pragma obsolete(from_base_string/2).
|
|
:- pred from_base_string(int::in, string::in, integer::out) is semidet.
|
|
|
|
% As above, but throws an exception rather than failing.
|
|
%
|
|
:- func det_from_base_string(int, string) = integer.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module char.
|
|
:- import_module exception.
|
|
:- import_module float.
|
|
:- import_module int.
|
|
:- import_module int8.
|
|
:- import_module int16.
|
|
:- import_module int32.
|
|
:- import_module int64.
|
|
:- import_module list.
|
|
:- import_module math.
|
|
:- import_module require.
|
|
:- import_module string.
|
|
:- import_module uint.
|
|
:- import_module uint8.
|
|
:- import_module uint16.
|
|
:- import_module uint32.
|
|
:- import_module uint64.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- interface.
|
|
|
|
% Exported for use by lexer.m.
|
|
%
|
|
:- pred from_base_string_underscore(int::in, string::in, integer::out)
|
|
is semidet.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
% 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.
|
|
% (djh: this is not really done although -ve integers include a list
|
|
% of -ve digits for faster comparison and so that normal mercury
|
|
% sorting produces an intuitive order)
|
|
%
|
|
% 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.)
|
|
% (djh: this is done)
|
|
%
|
|
% 3) Use an O(n^(3/2)) algorithm for multiplying large integers, rather than
|
|
% the current O(n^2) method. There is an obvious divide-and-conquer
|
|
% technique, Karatsuba multiplication. (this is done)
|
|
%
|
|
% 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.
|
|
% (djh: this is obsolete - digits lists are now in normal order)
|
|
%
|
|
% 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.
|
|
% (djh: this is done: /\ \/ << >> xor \)
|
|
%
|
|
% 7) The implementation of `div' is slower than it need be.
|
|
% (djh: this is much improved)
|
|
%
|
|
% 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.
|
|
%
|
|
% (djh: I'd like to see 1) done. integers are now represented as
|
|
% i(Length, Digits) where Digits are no longer reversed.
|
|
% The only penalty for not reversing is in multiplication by the base
|
|
% which now entails walking to the end of the list to append a 0.
|
|
% Therefore I'd like to see:
|
|
%
|
|
% 9) Allow empty tails for low end zeros.
|
|
% Base multiplication is then an increment to Length.
|
|
|
|
:- type sign == int. % sign of integer and length of digit list
|
|
:- type digit == int. % base 2^14 digit
|
|
|
|
:- type integer
|
|
---> i(sign, list(digit)).
|
|
|
|
:- func base = int.
|
|
|
|
base = 16384. % 2^14
|
|
|
|
:- func basediv2 = int.
|
|
|
|
basediv2 = 8192.
|
|
|
|
:- func log2base = int.
|
|
|
|
log2base = 14.
|
|
|
|
:- func basemask = int.
|
|
|
|
basemask = 16383.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- func length(integer) = int.
|
|
|
|
length(i(L, _)) = L.
|
|
|
|
:- func integer_signum(integer) = int.
|
|
|
|
integer_signum(i(Sign, _)) = signum(Sign).
|
|
|
|
:- func signum(int) = int.
|
|
|
|
signum(N) = Sign :-
|
|
( if N < 0 then
|
|
Sign = -1
|
|
else if N = 0 then
|
|
Sign = 0
|
|
else
|
|
Sign = 1
|
|
).
|
|
|
|
:- pred big_isnegative(integer::in) is semidet.
|
|
|
|
big_isnegative(i(Sign, _)) :-
|
|
Sign < 0.
|
|
|
|
%---------------------%
|
|
|
|
:- func decap(integer) = integer.
|
|
|
|
decap(i(_, [])) = integer.zero.
|
|
decap(i(L, [H | T])) = Result :-
|
|
( if H = 0 then
|
|
Result = decap(i(L - 1, T))
|
|
else
|
|
Result = i(L, [H | T])
|
|
).
|
|
|
|
%---------------------%
|
|
|
|
:- pred chop(int::in, digit::out, digit::out) is det.
|
|
|
|
chop(N, Div, Mod) :-
|
|
% The unchecked shifts here and in the uint case below
|
|
% are safe since log2base is 14.
|
|
Div = N `int.unchecked_right_shift` log2base, % i.e. Div = N div base
|
|
Mod = N /\ basemask. % i.e. Mod = N mod base
|
|
|
|
:- pred chop_uint(uint::in, uint::out, uint::out) is det.
|
|
|
|
chop_uint(N, Div, Mod) :-
|
|
% See the comments in chop/3.
|
|
Div = N `uint.unchecked_right_shift` log2base,
|
|
Mod = N /\ cast_from_int(basemask).
|
|
|
|
:- pred chop_uint32(uint32::in, uint32::out, uint32::out) is det.
|
|
|
|
chop_uint32(N, Div, Mod) :-
|
|
% See the comments in chop/3.
|
|
Div = N `uint32.unchecked_right_shift` log2base,
|
|
Mod = N /\ cast_from_int(basemask).
|
|
|
|
:- pred chop_int64(int64::in, int64::out, int64::out) is det.
|
|
|
|
chop_int64(N, Div, Mod) :-
|
|
% See the comments in chop/3.
|
|
Div = N `int64.unchecked_right_shift` log2base,
|
|
Mod = N /\ from_int(basemask).
|
|
|
|
:- pred chop_uint64(uint64::in, uint64::out, uint64::out) is det.
|
|
|
|
chop_uint64(N, Div, Mod) :-
|
|
% See the comments in chop/3.
|
|
Div = N `uint64.unchecked_right_shift` log2base,
|
|
Mod = N /\ cast_from_int(basemask).
|
|
|
|
%---------------------%
|
|
|
|
:- func det_first(integer) = digit.
|
|
|
|
det_first(i(_, Digits)) = First :-
|
|
(
|
|
Digits = [],
|
|
unexpected($module, $pred, "empty list")
|
|
;
|
|
Digits = [First | _]
|
|
).
|
|
|
|
:- func det_second(integer) = digit.
|
|
|
|
det_second(i(_, Digits)) = Second :-
|
|
(
|
|
Digits = [],
|
|
unexpected($module, $pred, "empty list")
|
|
;
|
|
Digits = [_],
|
|
unexpected($module, $pred, "short list")
|
|
;
|
|
Digits = [_, Second | _]
|
|
).
|
|
|
|
:- func det_tail(integer) = integer.
|
|
|
|
det_tail(i(Len, Digits)) = I :-
|
|
(
|
|
Digits = [],
|
|
unexpected($module, $pred, "empty list")
|
|
;
|
|
Digits = [_ | T],
|
|
I = i(Len - 1, T)
|
|
).
|
|
|
|
%---------------------%
|
|
|
|
% XXX What is the intended semantic difference between
|
|
% big_cmp and res_cmp?
|
|
%
|
|
:- func big_cmp(integer, integer) = comparison_result.
|
|
|
|
big_cmp(X, Y) = Result :-
|
|
compare(Result, X, Y).
|
|
|
|
:- func pos_cmp(integer, integer) = comparison_result.
|
|
|
|
pos_cmp(X, Y) = Result :-
|
|
compare(Result, X, Y).
|
|
|
|
:- pred pos_lt(integer::in, integer::in) is semidet.
|
|
|
|
pos_lt(X, Y) :-
|
|
Result = pos_cmp(X, Y),
|
|
Result = (<).
|
|
|
|
:- pred pos_geq(integer::in, integer::in) is semidet.
|
|
|
|
pos_geq(X, Y) :-
|
|
Result = pos_cmp(X, Y),
|
|
( Result = (>)
|
|
; Result = (=)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
negative_one = i(-1, [-1]).
|
|
|
|
zero = i(0, []).
|
|
|
|
one = i(1, [1]).
|
|
|
|
two = i(1, [2]).
|
|
|
|
ten = i(1, [10]).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
'<'(X, Y) :-
|
|
big_cmp(X, Y) = C,
|
|
C = (<).
|
|
|
|
'>'(X, Y) :-
|
|
big_cmp(X, Y) = C,
|
|
C = (>).
|
|
|
|
'=<'(X, Y) :-
|
|
big_cmp(X, Y) = C,
|
|
( C = (<) ; C = (=)).
|
|
|
|
'>='(X, Y) :-
|
|
big_cmp(X, Y) = C,
|
|
( C = (>) ; C = (=)).
|
|
|
|
abs(N) = big_abs(N).
|
|
|
|
is_zero(i(0, [])).
|
|
|
|
%---------------------%
|
|
|
|
:- func big_abs(integer) = integer.
|
|
|
|
big_abs(i(Sign, Ds)) = Result :-
|
|
( if Sign < 0 then
|
|
Result = big_neg(i(Sign, Ds))
|
|
else
|
|
Result = i(Sign, Ds)
|
|
).
|
|
|
|
:- func big_neg(integer) = integer.
|
|
|
|
big_neg(i(S, Digits0)) = i(-S, Digits) :-
|
|
neg_list(Digits0, Digits).
|
|
|
|
:- pred neg_list(list(int)::in, list(int)::out) is det.
|
|
|
|
neg_list([], []).
|
|
neg_list([H | T], [-H | NT]) :-
|
|
neg_list(T, NT).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
'+'(X) = X.
|
|
|
|
'-'(X) = big_neg(X).
|
|
|
|
X + Y = big_plus(X, Y).
|
|
|
|
X - Y = big_plus(X, big_neg(Y)).
|
|
|
|
X * Y = big_mul(X, Y).
|
|
|
|
X div Y = big_div(X, Y).
|
|
|
|
X // Y = big_quot(X, Y).
|
|
|
|
X mod Y = big_mod(X, Y).
|
|
|
|
X rem Y = big_rem(X, Y).
|
|
|
|
divide_with_rem(X, Y, Quotient, Remainder) :-
|
|
big_quot_rem(X, Y, Quotient, Remainder).
|
|
|
|
pow(A, N) = P :-
|
|
( if big_isnegative(N) then
|
|
throw(math.domain_error("integer.pow: negative exponent"))
|
|
else
|
|
P = big_pow(A, N)
|
|
).
|
|
|
|
%---------------------%
|
|
|
|
:- func big_plus(integer, integer) = integer.
|
|
|
|
big_plus(X, Y) = Sum :-
|
|
( if is_zero(X) then
|
|
Sum = Y
|
|
else if is_zero(Y) then
|
|
Sum = X
|
|
else
|
|
AbsX = big_abs(X),
|
|
AbsY = big_abs(Y),
|
|
SignX = integer_signum(X),
|
|
SignY = integer_signum(Y),
|
|
( if SignX = SignY then
|
|
Sum = big_sign(SignX, pos_plus(AbsX, AbsY))
|
|
else
|
|
C = pos_cmp(AbsX, AbsY),
|
|
(
|
|
C = (<),
|
|
Sum = big_sign(SignY, pos_minus(AbsY, AbsX))
|
|
;
|
|
C = (>),
|
|
Sum = big_sign(SignX, pos_minus(AbsX, AbsY))
|
|
;
|
|
C = (=),
|
|
Sum = integer.zero
|
|
)
|
|
)
|
|
).
|
|
|
|
:- func pos_plus(integer, integer) = integer.
|
|
|
|
pos_plus(i(L1, D1), i(L2, D2)) = Out :-
|
|
add_pairs(Div, i(L1, D1), i(L2, D2), Ds),
|
|
( if L1 > L2 then
|
|
Len = L1
|
|
else
|
|
Len = L2
|
|
),
|
|
( if Div = 0 then
|
|
Out = i(Len, Ds)
|
|
else
|
|
Out = i(Len + 1, [Div | Ds])
|
|
).
|
|
|
|
:- pred add_pairs(digit::out, integer::in, integer::in,
|
|
list(digit)::out) is det.
|
|
|
|
add_pairs(Div, i(L1, D1), i(L2, D2), Ds) :-
|
|
( if L1 = L2 then
|
|
add_pairs_equal(Div, D1, D2, Ds)
|
|
else if L1 < L2, D2 = [H2 | T2] then
|
|
add_pairs(Div1, i(L1, D1), i(L2 - 1, T2), Ds1),
|
|
chop(H2 + Div1, Div, Mod),
|
|
Ds = [Mod | Ds1]
|
|
else if L1 > L2, D1 = [H1 | T1] then
|
|
add_pairs(Div1, i(L1 - 1, T1), i(L2, D2), Ds1),
|
|
chop(H1 + Div1, Div, Mod),
|
|
Ds = [Mod | Ds1]
|
|
else
|
|
unexpected($module, $pred, "invalid integer")
|
|
).
|
|
|
|
:- pred add_pairs_equal(digit::out, list(digit)::in, list(digit)::in,
|
|
list(digit)::out) is det.
|
|
|
|
add_pairs_equal(0, [], _, []).
|
|
add_pairs_equal(0, [_ | _], [], []).
|
|
add_pairs_equal(Div, [X | Xs], [Y | Ys], [Mod | TailDs]) :-
|
|
add_pairs_equal(DivTail, Xs, Ys, TailDs),
|
|
chop(X + Y + DivTail, Div, Mod).
|
|
|
|
:- func pos_minus(integer, integer) = integer.
|
|
|
|
pos_minus(i(L1, D1), i(L2, D2)) = Out :-
|
|
diff_pairs(Mod, i(L1, D1), i(L2, D2), Ds),
|
|
( if L1 > L2 then
|
|
Len = L1
|
|
else
|
|
Len = L2
|
|
),
|
|
( if Mod = 0 then
|
|
Out = decap(i(Len, Ds))
|
|
else
|
|
Out = i(Len + 1, [Mod | Ds])
|
|
).
|
|
|
|
:- pred diff_pairs(digit::out, integer::in, integer::in,
|
|
list(digit)::out) is det.
|
|
|
|
diff_pairs(Div, i(L1, D1), i(L2, D2), Ds) :-
|
|
( if L1 = L2 then
|
|
diff_pairs_equal(Div, D1, D2, Ds)
|
|
else if L1 > L2, D1 = [H1 | T1] then
|
|
diff_pairs(Div1, i(L1 - 1, T1), i(L2, D2), Ds1),
|
|
chop(H1 + Div1, Div, Mod),
|
|
Ds = [Mod | Ds1]
|
|
else
|
|
unexpected($module, $pred, "invalid integer")
|
|
).
|
|
|
|
:- pred diff_pairs_equal(digit::out, list(digit)::in, list(digit)::in,
|
|
list(digit)::out) is det.
|
|
|
|
diff_pairs_equal(0, [], _, []).
|
|
diff_pairs_equal(0, [_ | _], [], []).
|
|
diff_pairs_equal(Div, [X | Xs], [Y | Ys], [Mod | TailDs]) :-
|
|
diff_pairs_equal(DivTail, Xs, Ys, TailDs),
|
|
chop(X - Y + DivTail, Div, Mod).
|
|
|
|
%---------------------%
|
|
|
|
:- func big_mul(integer, integer) = integer.
|
|
|
|
big_mul(X, Y) = Result :-
|
|
Sign = integer_signum(X) * integer_signum(Y),
|
|
Value = pos_mul(big_abs(X), big_abs(Y)),
|
|
Result = big_sign(Sign, Value).
|
|
|
|
:- func pos_mul(integer, integer) = integer.
|
|
|
|
pos_mul(i(L1, Ds1), i(L2, Ds2)) =
|
|
( if L1 < L2 then
|
|
pos_mul_karatsuba(i(L1, Ds1), i(L2, Ds2))
|
|
else
|
|
pos_mul_karatsuba(i(L2, Ds2), i(L1, Ds1))
|
|
).
|
|
|
|
% Use quadratic multiplication for less than threshold digits.
|
|
:- func karatsuba_threshold = int.
|
|
|
|
karatsuba_threshold = 35.
|
|
|
|
% Use parallel execution if number of digits of split numbers is larger
|
|
% than this threshold.
|
|
:- func karatsuba_parallel_threshold = int.
|
|
|
|
karatsuba_parallel_threshold = karatsuba_threshold * 10.
|
|
|
|
% Karatsuba / Toom-2 multiplication in O(n^1.585)
|
|
:- func pos_mul_karatsuba(integer, integer) = integer.
|
|
|
|
pos_mul_karatsuba(i(L1, Ds1), i(L2, Ds2)) = Res :-
|
|
( if L1 < karatsuba_threshold then
|
|
Res = pos_mul_list(Ds1, integer.zero, i(L2, Ds2))
|
|
else
|
|
( if L2 < L1 then
|
|
unexpected($module, $pred, "second factor smaller")
|
|
else
|
|
Middle = L2 div 2,
|
|
HiDigits = L2 - Middle,
|
|
HiDigitsSmall = max(0, L1 - Middle),
|
|
% Split Ds1 in [L1 - Middle];[Middle] digits if L1 > Middle
|
|
% or leave as [L1] digits.
|
|
list.split_upto(HiDigitsSmall, Ds1, Ds1Upper, Ds1Lower),
|
|
% Split Ds2 in [L2 - Middle; Middle] digits.
|
|
list.split_upto(HiDigits, Ds2, Ds2Upper, Ds2Lower),
|
|
LoDs1 = i(min(L1, Middle), Ds1Lower),
|
|
LoDs2 = i(Middle, Ds2Lower),
|
|
HiDs1 = i(HiDigitsSmall, Ds1Upper),
|
|
HiDs2 = i(HiDigits, Ds2Upper),
|
|
( if Middle > karatsuba_parallel_threshold then
|
|
Res0 = pos_mul(LoDs1, LoDs2) &
|
|
Res1 = pos_mul(LoDs1 + HiDs1, LoDs2 + HiDs2) &
|
|
Res2 = pos_mul(HiDs1, HiDs2)
|
|
else
|
|
Res0 = pos_mul(LoDs1, LoDs2),
|
|
Res1 = pos_mul(LoDs1 + HiDs1, LoDs2 + HiDs2),
|
|
Res2 = pos_mul(HiDs1, HiDs2)
|
|
)
|
|
),
|
|
Res = big_left_shift(Res2, 2*Middle*log2base) +
|
|
big_left_shift(Res1 - (Res2 + Res0), Middle*log2base) + Res0
|
|
).
|
|
|
|
:- func pos_mul_list(list(digit), integer, integer) = integer.
|
|
|
|
pos_mul_list([], Carry, _Y) = Carry.
|
|
pos_mul_list([X | Xs], Carry, Y) =
|
|
pos_mul_list(Xs, pos_plus(mul_base(Carry), mul_by_digit(X, Y)), Y).
|
|
|
|
:- func mul_base(integer) = integer.
|
|
|
|
mul_base(i(Len, Digits)) = Result :-
|
|
(
|
|
Digits = [],
|
|
Result = integer.zero
|
|
;
|
|
Digits = [_ | _],
|
|
Result = i(Len + 1, mul_base_2(Digits))
|
|
).
|
|
|
|
:- func mul_base_2(list(digit)) = list(digit).
|
|
|
|
mul_base_2([]) = [0].
|
|
mul_base_2([H | T]) = [H | mul_base_2(T)].
|
|
|
|
:- func mul_by_digit(digit, integer) = integer.
|
|
|
|
mul_by_digit(Digit, i(Len, Digits0)) = Out :-
|
|
mul_by_digit_2(Digit, Mod, Digits0, Digits),
|
|
( if Mod = 0 then
|
|
Out = i(Len, Digits)
|
|
else
|
|
Out = i(Len + 1, [Mod | Digits])
|
|
).
|
|
|
|
:- pred mul_by_digit_2(digit::in, digit::out, list(digit)::in,
|
|
list(digit)::out) is det.
|
|
|
|
mul_by_digit_2(_, 0, [], []).
|
|
mul_by_digit_2(D, Div, [X | Xs], [Mod | NewXs]) :-
|
|
mul_by_digit_2(D, DivXs, Xs, NewXs),
|
|
chop(D * X + DivXs, Div, Mod).
|
|
|
|
%---------------------%
|
|
|
|
:- func big_div(integer, integer) = integer.
|
|
|
|
big_div(X, Y) = Div :-
|
|
big_quot_rem(X, Y, Trunc, Rem),
|
|
( if integer_signum(Y) * integer_signum(Rem) < 0 then
|
|
Div = Trunc - integer.one
|
|
else
|
|
Div = Trunc
|
|
).
|
|
|
|
:- func big_quot(integer, integer) = integer.
|
|
|
|
big_quot(X, Y) = Quot :-
|
|
big_quot_rem(X, Y, Quot, _Rem).
|
|
|
|
:- func big_rem(integer, integer) = integer.
|
|
|
|
big_rem(X, Y) = Rem :-
|
|
big_quot_rem(X, Y, _Quot, Rem).
|
|
|
|
:- func big_mod(integer, integer) = integer.
|
|
|
|
big_mod(X, Y) = Mod :-
|
|
big_quot_rem(X, Y, _Trunc, Rem),
|
|
( if integer_signum(Y) * integer_signum(Rem) < 0 then
|
|
Mod = Rem + Y
|
|
else
|
|
Mod = Rem
|
|
).
|
|
|
|
%---------------------%
|
|
|
|
:- pred big_quot_rem(integer::in, integer::in, integer::out, integer::out)
|
|
is det.
|
|
|
|
big_quot_rem(X, Y, Quot, Rem) :-
|
|
( if is_zero(Y) then
|
|
throw(math.domain_error("integer.big_quot_rem: division by zero"))
|
|
else if is_zero(X) then
|
|
Quot = integer.zero,
|
|
Rem = integer.zero
|
|
else
|
|
X = i(SignX, _),
|
|
Y = i(SignY, _),
|
|
quot_rem(big_abs(X), big_abs(Y), Quot0, Rem0),
|
|
Quot = big_sign(SignX * SignY, Quot0),
|
|
Rem = big_sign(SignX, Rem0)
|
|
).
|
|
|
|
% 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 is all we use from Knuth;
|
|
% his MIX algorithm is fugly.
|
|
%
|
|
% [*] Knuth, Semi-numerical algorithms.
|
|
|
|
:- pred quot_rem(integer::in, integer::in, integer::out, integer::out) is det.
|
|
|
|
quot_rem(U, V, Quot, Rem) :-
|
|
( if U = i(_, [UI]), V = i(_, [VI]) then
|
|
Quot = shortint_to_integer(UI // VI),
|
|
Rem = shortint_to_integer(UI rem VI)
|
|
else
|
|
V0 = det_first(V),
|
|
( if V0 < basediv2 then
|
|
M = base div (V0 + 1),
|
|
quot_rem_2(integer.zero, mul_by_digit(M, U),
|
|
mul_by_digit(M, V), QuotZeros, R),
|
|
Rem = div_by_digit(M, R)
|
|
else
|
|
quot_rem_2(integer.zero, U, V, QuotZeros, Rem)
|
|
),
|
|
Quot = decap(QuotZeros)
|
|
).
|
|
|
|
:- pred quot_rem_2(integer::in, integer::in, integer::in, integer::out,
|
|
integer::out) is det.
|
|
|
|
quot_rem_2(Ur, U, V, Quot, Rem) :-
|
|
( if pos_lt(Ur, V) then
|
|
( if U = i(_, [Ua | _]) then
|
|
quot_rem_2(integer_append(Ur, Ua), det_tail(U), V,
|
|
Quot0, Rem0),
|
|
Quot = integer_prepend(0, Quot0),
|
|
Rem = Rem0
|
|
else
|
|
Quot = i(1, [0]),
|
|
Rem = Ur
|
|
)
|
|
else
|
|
( if length(Ur) > length(V) then
|
|
Qhat = (det_first(Ur) * base + det_second(Ur)) div det_first(V)
|
|
else
|
|
Qhat = det_first(Ur) div det_first(V)
|
|
),
|
|
QhatByV = mul_by_digit(Qhat, V),
|
|
( if pos_geq(Ur, QhatByV) then
|
|
Q = Qhat,
|
|
QByV = QhatByV
|
|
else
|
|
QhatMinus1ByV = pos_minus(QhatByV, V),
|
|
( if pos_geq(Ur, QhatMinus1ByV) then
|
|
Q = Qhat - 1,
|
|
QByV = QhatMinus1ByV
|
|
else
|
|
Q = Qhat - 2,
|
|
QByV = pos_minus(QhatMinus1ByV, V)
|
|
)
|
|
),
|
|
NewUr = pos_minus(Ur, QByV),
|
|
( if U = i(_, [Ua | _]) then
|
|
quot_rem_2(integer_append(NewUr, Ua), det_tail(U), V, Quot0, Rem0),
|
|
Quot = integer_prepend(Q, Quot0),
|
|
Rem = Rem0
|
|
else
|
|
Quot = i(1, [Q]),
|
|
Rem = NewUr
|
|
)
|
|
).
|
|
|
|
:- func div_by_digit(digit, integer) = integer.
|
|
|
|
div_by_digit(_, i(_, [])) = integer.zero.
|
|
div_by_digit(Digit, i(_, [X | Xs])) = div_by_digit_1(X, Xs, Digit).
|
|
|
|
:- func div_by_digit_1(digit, list(digit), digit) = integer.
|
|
|
|
div_by_digit_1(X, [], D) = Integer :-
|
|
Q = X div D,
|
|
( if Q = 0 then
|
|
Integer = integer.zero
|
|
else
|
|
Integer = i(1, [Q])
|
|
).
|
|
div_by_digit_1(X, [H | T], D) = Integer :-
|
|
Q = X div D,
|
|
( if Q = 0 then
|
|
Integer = div_by_digit_1((X rem D) * base + H, T, D)
|
|
else
|
|
i(L, Ds) = div_by_digit_2((X rem D) * base + H, T, D),
|
|
Integer = i(L + 1, [Q | Ds])
|
|
).
|
|
|
|
:- func div_by_digit_2(digit, list(digit), digit) = integer.
|
|
|
|
div_by_digit_2(X, [], D) = i(1, [X div D]).
|
|
div_by_digit_2(X, [H | T], D) = i(Len + 1, [X div D | Tail]) :-
|
|
i(Len, Tail) = div_by_digit_2((X rem D) * base + H, T, D).
|
|
|
|
:- func integer_append(integer, digit) = integer.
|
|
|
|
integer_append(i(L, List), Digit) = i(L + 1, NewList) :-
|
|
list.append(List, [Digit], NewList).
|
|
|
|
:- func integer_prepend(digit, integer) = integer.
|
|
|
|
integer_prepend(Digit, i(L, List)) = i(L + 1, [Digit | List]).
|
|
|
|
%---------------------%
|
|
|
|
:- func shortint_to_integer(int) = integer.
|
|
|
|
shortint_to_integer(D) = Result :-
|
|
( if D = 0 then
|
|
Result = integer.zero
|
|
else if D > 0 then
|
|
Result = i(1, [D])
|
|
else
|
|
Result = i(-1, [D])
|
|
).
|
|
|
|
:- func big_sign(int, integer) = integer.
|
|
|
|
big_sign(Sign, In) = Result :-
|
|
( if Sign < 0 then
|
|
Result = big_neg(In)
|
|
else
|
|
Result = In
|
|
).
|
|
|
|
%---------------------%
|
|
|
|
:- func big_pow(integer, integer) = integer.
|
|
|
|
big_pow(A, N) = Result :-
|
|
( if N = integer.zero then
|
|
Result = integer.one
|
|
else if N = integer.one then
|
|
Result = A
|
|
else if A = integer.one then
|
|
Result = integer.one
|
|
else if A = integer.zero then
|
|
Result = integer.zero
|
|
else if N = i(_, [_ | _]) then
|
|
Result = big_pow_sqmul(A, N)
|
|
else
|
|
Result = integer.zero
|
|
).
|
|
|
|
:- func big_pow_sqmul(integer, integer) = integer.
|
|
|
|
big_pow_sqmul(A, N) = Result :-
|
|
( if N = integer.zero then
|
|
Result = integer.one
|
|
else if N = integer.one then
|
|
Result = A
|
|
else
|
|
( if (N mod integer.two) = integer.zero then
|
|
% if exponent N is even -> Result = A^(N//2) * A^(N//2)
|
|
HalfResult = big_pow_sqmul(A, N // integer.two),
|
|
Result = HalfResult * HalfResult
|
|
else
|
|
% if odd, then Result = A * A^(N - 1)
|
|
SubResult = big_pow_sqmul(A, N - integer.one),
|
|
Result = A * SubResult
|
|
)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
X << I = Result :-
|
|
( if I > 0 then
|
|
Result = big_left_shift(X, I)
|
|
else if I < 0 then
|
|
Result = X >> -I
|
|
else
|
|
Result = X
|
|
).
|
|
|
|
:- func big_left_shift(integer, int) = integer.
|
|
|
|
big_left_shift(X, I) = Result :-
|
|
( if is_zero(X) then
|
|
Result = X
|
|
else if big_isnegative(X) then
|
|
Result = big_neg(pos_left_shift(big_neg(X), I))
|
|
else
|
|
Result = pos_left_shift(X, I)
|
|
).
|
|
|
|
:- func pos_left_shift(integer, int) = integer.
|
|
|
|
pos_left_shift(i(Len, Digits), I) = Integer :-
|
|
Div = I div log2base,
|
|
Mod = I mod log2base,
|
|
NewLen = Len + Div,
|
|
leftshift(Mod, log2base - Mod, NewLen, Digits, Carry, NewDigits),
|
|
( if Carry = 0 then
|
|
Integer = i(NewLen, NewDigits)
|
|
else
|
|
Integer = i(NewLen + 1, [Carry | NewDigits])
|
|
).
|
|
|
|
:- pred leftshift(int::in, int::in, int::in, list(digit)::in,
|
|
int::out, list(digit)::out) is det.
|
|
|
|
leftshift(_Mod, _InvMod, Len, [], Carry, DigitsOut) :-
|
|
Carry = 0,
|
|
zeros(Len, [], DigitsOut).
|
|
leftshift(Mod, InvMod, Len, [H | T], Carry, DigitsOut) :-
|
|
( if Len =< 0 then
|
|
Carry = 0,
|
|
DigitsOut = []
|
|
else
|
|
Carry = (H /\ (basemask << InvMod)) >> InvMod,
|
|
leftshift(Mod, InvMod, Len - 1, T, TailCarry, Tail),
|
|
DigitsOut = [TailCarry \/ ((H << Mod) /\ basemask) | Tail]
|
|
).
|
|
|
|
:- pred zeros(int::in, list(digit)::in, list(digit)::out) is det.
|
|
|
|
zeros(Len, Digits0, Digits) :-
|
|
( if Len > 0 then
|
|
zeros(Len - 1, Digits0, Digits1),
|
|
Digits = [0 | Digits1]
|
|
else
|
|
Digits = Digits0
|
|
).
|
|
|
|
%---------------------%
|
|
|
|
X >> I = Result :-
|
|
( if I < 0 then
|
|
Result = X << -I
|
|
else if I > 0 then
|
|
Result = big_right_shift(X, I)
|
|
else
|
|
Result = X
|
|
).
|
|
|
|
:- func big_right_shift(integer, int) = integer.
|
|
|
|
big_right_shift(X, I) = Result :-
|
|
( if is_zero(X) then
|
|
Result = X
|
|
else if big_isnegative(X) then
|
|
Result = \ pos_right_shift(\ X, I)
|
|
else
|
|
Result = pos_right_shift(X, I)
|
|
).
|
|
|
|
:- func pos_right_shift(integer, int) = integer.
|
|
|
|
pos_right_shift(i(Len, Digits), I) = Integer :-
|
|
Div = I div log2base,
|
|
( if Div < Len then
|
|
Mod = I mod log2base,
|
|
Integer = decap(rightshift(Mod, log2base - Mod,
|
|
i(Len - Div, Digits), 0))
|
|
else
|
|
Integer = integer.zero
|
|
).
|
|
|
|
:- func rightshift(int, int, integer, int) = integer.
|
|
|
|
rightshift(_Mod, _InvMod, i(_Len, []), _Carry) = integer.zero.
|
|
rightshift(Mod, InvMod, i(Len, [H | T]), Carry) = Integer :-
|
|
( if Len =< 0 then
|
|
Integer = integer.zero
|
|
else
|
|
NewH = Carry \/ (H >> Mod),
|
|
NewCarry = (H /\ (basemask >> InvMod)) << InvMod,
|
|
i(TailLen, NewTail) = rightshift(Mod, InvMod, i(Len - 1, T),
|
|
NewCarry),
|
|
Integer = i(TailLen + 1, [NewH | NewTail])
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
\ X = big_neg(big_plus(X, integer.one)).
|
|
|
|
%---------------------%
|
|
|
|
X /\ Y = Result :-
|
|
( if big_isnegative(X) then
|
|
( if big_isnegative(Y) then
|
|
Result = \ big_or(\ X, \ Y)
|
|
else
|
|
Result = big_and_not(Y, \ X)
|
|
)
|
|
else if big_isnegative(Y) then
|
|
Result = big_and_not(X, \ Y)
|
|
else
|
|
Result = big_and(X, Y)
|
|
).
|
|
|
|
X \/ Y = Result :-
|
|
( if big_isnegative(X) then
|
|
( if big_isnegative(Y) then
|
|
Result = \ big_and(\ X, \ Y)
|
|
else
|
|
Result = \ big_and_not(\ X, Y)
|
|
)
|
|
else if big_isnegative(Y) then
|
|
Result = \ big_and_not(\ Y, X)
|
|
else
|
|
Result = big_or(X, Y)
|
|
).
|
|
|
|
X `xor` Y = Result :-
|
|
( if big_isnegative(X) then
|
|
( if big_isnegative(Y) then
|
|
Result = big_xor(\ X, \ Y)
|
|
else
|
|
Result = big_xor_not(Y, \ X)
|
|
)
|
|
else if big_isnegative(Y) then
|
|
Result = big_xor_not(X, \ Y)
|
|
else
|
|
Result = big_xor(X, Y)
|
|
).
|
|
|
|
%---------------------%
|
|
|
|
:- func big_and(integer, integer) = integer.
|
|
|
|
big_and(X, Y) = decap(and_pairs(X, Y)).
|
|
|
|
:- func and_pairs(integer, integer) = integer.
|
|
|
|
and_pairs(i(L1, D1), i(L2, D2)) = Integer :-
|
|
( if L1 = L2 then
|
|
Integer = i(L1, and_pairs_equal(D1, D2))
|
|
else if L1 < L2, D2 = [_ | T2] then
|
|
i(_, DsT) = and_pairs(i(L1, D1), i(L2 - 1, T2)),
|
|
Integer = i(L1, DsT)
|
|
else if L1 > L2, D1 = [_ | T1] then
|
|
i(_, DsT) = and_pairs(i(L1 - 1, T1), i(L2, D2)),
|
|
Integer = i(L2, DsT)
|
|
else
|
|
unexpected($module, $pred, "invalid integer")
|
|
).
|
|
|
|
:- func and_pairs_equal(list(digit), list(digit)) = list(digit).
|
|
|
|
and_pairs_equal([], _) = [].
|
|
and_pairs_equal([_ | _], []) = [].
|
|
and_pairs_equal([X | Xs], [Y | Ys]) = [X /\ Y | and_pairs_equal(Xs, Ys)].
|
|
|
|
%---------------------%
|
|
|
|
:- func big_or(integer, integer) = integer.
|
|
|
|
big_or(X, Y) = decap(or_pairs(X, Y)).
|
|
|
|
:- func or_pairs(integer, integer) = integer.
|
|
|
|
or_pairs(i(L1, D1), i(L2, D2)) = Integer :-
|
|
( if L1 = L2 then
|
|
Integer = i(L1, or_pairs_equal(D1, D2))
|
|
else if L1 < L2, D2 = [H2 | T2] then
|
|
i(_, DsT) = or_pairs(i(L1, D1), i(L2 - 1, T2)),
|
|
Integer = i(L2, [H2 | DsT])
|
|
else if L1 > L2, D1 = [H1 | T1] then
|
|
i(_, DsT) = or_pairs(i(L1 - 1, T1), i(L2, D2)),
|
|
Integer = i(L1, [H1 | DsT])
|
|
else
|
|
unexpected($module, $pred, "invalid integer")
|
|
).
|
|
|
|
:- func or_pairs_equal(list(digit), list(digit)) = list(digit).
|
|
|
|
or_pairs_equal([], _) = [].
|
|
or_pairs_equal([_ | _], []) = [].
|
|
or_pairs_equal([X | Xs], [Y | Ys]) = [X \/ Y | or_pairs_equal(Xs, Ys)].
|
|
|
|
%---------------------%
|
|
|
|
:- func big_xor(integer, integer) = integer.
|
|
|
|
big_xor(X, Y) = decap(xor_pairs(X, Y)).
|
|
|
|
:- func xor_pairs(integer, integer) = integer.
|
|
|
|
xor_pairs(i(L1, D1), i(L2, D2)) = Integer :-
|
|
( if L1 = L2 then
|
|
Integer = i(L1, xor_pairs_equal(D1, D2))
|
|
else if L1 < L2, D2 = [H2 | T2] then
|
|
i(_, DsT) = xor_pairs(i(L1, D1), i(L2 - 1, T2)),
|
|
Integer = i(L2, [H2 | DsT])
|
|
else if L1 > L2, D1 = [H1 | T1] then
|
|
i(_, DsT) = xor_pairs(i(L1 - 1, T1), i(L2, D2)),
|
|
Integer = i(L1, [H1 | DsT])
|
|
else
|
|
unexpected($module, $pred, "invalid integer")
|
|
).
|
|
|
|
:- func xor_pairs_equal(list(digit), list(digit)) = list(digit).
|
|
|
|
xor_pairs_equal([], _) = [].
|
|
xor_pairs_equal([_ | _], []) = [].
|
|
xor_pairs_equal([X | Xs], [Y | Ys]) =
|
|
[int.xor(X, Y) | xor_pairs_equal(Xs, Ys)].
|
|
|
|
%---------------------%
|
|
|
|
:- func big_and_not(integer, integer) = integer.
|
|
|
|
big_and_not(X, Y) = decap(and_not_pairs(X, Y)).
|
|
|
|
:- func and_not_pairs(integer, integer) = integer.
|
|
|
|
and_not_pairs(i(L1, D1), i(L2, D2)) = Integer :-
|
|
( if L1 = L2 then
|
|
Integer = i(L1, and_not_pairs_equal(D1, D2))
|
|
else if L1 < L2, D2 = [_ | T2] then
|
|
i(_, DsT) = and_not_pairs(i(L1, D1), i(L2 - 1, T2)),
|
|
Integer = i(L1, DsT)
|
|
else if L1 > L2, D1 = [H1 | T1] then
|
|
i(_, DsT) = and_not_pairs(i(L1 - 1, T1), i(L2, D2)),
|
|
Integer = i(L1, [H1 | DsT])
|
|
else
|
|
unexpected($module, $pred, "invalid integer")
|
|
).
|
|
|
|
:- func and_not_pairs_equal(list(digit), list(digit)) = list(digit).
|
|
|
|
and_not_pairs_equal([], _) = [].
|
|
and_not_pairs_equal([_ | _], []) = [].
|
|
and_not_pairs_equal([X | Xs], [Y | Ys]) =
|
|
[X /\ \ Y | and_not_pairs_equal(Xs, Ys)].
|
|
|
|
%---------------------%
|
|
|
|
:- func big_xor_not(integer, integer) = integer.
|
|
|
|
big_xor_not(X1, NotX2) =
|
|
\ big_and_not(big_or(X1, NotX2), big_and(X1, NotX2)).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
to_int(Integer, Int) :-
|
|
Integer >= integer(int.min_int),
|
|
Integer =< integer(int.max_int),
|
|
Integer = i(_Sign, Digits),
|
|
Int = int_list(Digits, 0).
|
|
|
|
:- func int_list(list(int), int) = int.
|
|
|
|
int_list([], Accum) = Accum.
|
|
int_list([H | T], Accum) = int_list(T, Accum * base + H).
|
|
|
|
det_to_int(Integer) = Int :-
|
|
( if integer.to_int(Integer, IntPrime) then
|
|
Int = IntPrime
|
|
else
|
|
throw(math.domain_error(
|
|
"integer.det_to_int: domain error (conversion would overflow)"))
|
|
).
|
|
|
|
int(Integer) = integer.det_to_int(Integer).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
to_uint(Integer, UInt) :-
|
|
Integer >= integer.zero,
|
|
Integer =< integer.from_uint(uint.max_uint),
|
|
Integer = i(_Sign, Digits),
|
|
UInt = uint_list(Digits, 0u).
|
|
|
|
:- func uint_list(list(int), uint) = uint.
|
|
|
|
uint_list([], Accum) = Accum.
|
|
uint_list([H | T], Accum) =
|
|
uint_list(T, Accum * cast_from_int(base) + cast_from_int(H)).
|
|
|
|
det_to_uint(Integer) = UInt :-
|
|
( if integer.to_uint(Integer, UIntPrime) then
|
|
UInt = UIntPrime
|
|
else
|
|
throw(math.domain_error(
|
|
"integer.det_to_uint: domain error (conversion would overflow)"))
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
to_int8(Integer, Int8) :-
|
|
( if is_zero(Integer) then
|
|
Int8 = 0i8
|
|
else
|
|
Integer = i(_, [Digit]),
|
|
int8.from_int(Digit, Int8)
|
|
).
|
|
|
|
det_to_int8(Integer) = Int8 :-
|
|
( if integer.to_int8(Integer, Int8Prime) then
|
|
Int8 = Int8Prime
|
|
else
|
|
throw(math.domain_error(
|
|
"integer.det_to_int8: domain error (conversion would overflow)"))
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
to_uint8(Integer, UInt8) :-
|
|
( if is_zero(Integer) then
|
|
UInt8 = 0u8
|
|
else
|
|
Integer = i(_, [Digit]),
|
|
uint8.from_int(Digit, UInt8)
|
|
).
|
|
|
|
det_to_uint8(Integer) = UInt8 :-
|
|
( if integer.to_uint8(Integer, UInt8Prime) then
|
|
UInt8 = UInt8Prime
|
|
else
|
|
throw(math.domain_error(
|
|
"integer.det_to_uint8: domain error (conversion would overflow)"))
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
to_int16(Integer, Int16) :-
|
|
integer.to_int(Integer, Int),
|
|
int16.from_int(Int, Int16).
|
|
|
|
det_to_int16(Integer) = Int16 :-
|
|
( if integer.to_int16(Integer, Int16Prime) then
|
|
Int16 = Int16Prime
|
|
else
|
|
throw(math.domain_error(
|
|
"integer.det_to_int16: domain error (conversion would overflow)"))
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
to_uint16(Integer, UInt16) :-
|
|
integer.to_int(Integer, Int),
|
|
uint16.from_int(Int, UInt16).
|
|
|
|
det_to_uint16(Integer) = UInt16 :-
|
|
( if integer.to_uint16(Integer, UInt16Prime) then
|
|
UInt16 = UInt16Prime
|
|
else
|
|
throw(math.domain_error(
|
|
"integer.det_to_uint16: domain error (conversion would overflow)"))
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
to_int32(Integer, Int32) :-
|
|
integer.to_int(Integer, Int),
|
|
int32.from_int(Int, Int32).
|
|
|
|
det_to_int32(Integer) = Int32 :-
|
|
( if integer.to_int32(Integer, Int32Prime) then
|
|
Int32 = Int32Prime
|
|
else
|
|
throw(math.domain_error(
|
|
"integer.det_to_int32: domain error (conversion would overflow"))
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
to_uint32(Integer, UInt32) :-
|
|
Integer = i(Sign, Digits),
|
|
Sign >= 0, % i.e. Integer >= 0.
|
|
Integer =< integer_max_uint32,
|
|
UInt32 = uint32_list(Digits, 0u32).
|
|
|
|
% Return max_uint32 as an integer.
|
|
%
|
|
:- func integer_max_uint32 = integer.
|
|
|
|
integer_max_uint32 = i(3, [15, 16383, 16383]).
|
|
|
|
:- func uint32_list(list(int), uint32) = uint32.
|
|
|
|
uint32_list([], Accum) = Accum.
|
|
uint32_list([H | T], Accum) =
|
|
uint32_list(T, Accum * cast_from_int(base) + cast_from_int(H)).
|
|
|
|
det_to_uint32(Integer) = UInt32 :-
|
|
( if integer.to_uint32(Integer, UInt32Prime) then
|
|
UInt32 = UInt32Prime
|
|
else
|
|
throw(math.domain_error(
|
|
"integer.det_to_uint32: domain error (conversion would overflow"))
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
to_int64(Integer, Int64) :-
|
|
Integer = i(Sign, Digits),
|
|
compare(SignRes, Sign, 0),
|
|
(
|
|
SignRes = (<),
|
|
Integer >= integer_min_int64,
|
|
Int64 = int64_list(Digits, from_int(0))
|
|
;
|
|
SignRes = (=),
|
|
Int64 = from_int(0)
|
|
;
|
|
SignRes = (>),
|
|
Integer =< integer_max_int64,
|
|
Int64 = int64_list(Digits, from_int(0))
|
|
).
|
|
|
|
% Return min_int64 as an integer.
|
|
%
|
|
:- func integer_min_int64 = integer.
|
|
|
|
% 128 * 2^(14*4) + 0 * 2^(14*3) + ... + 0 * 2^(14*0)
|
|
% = 2^7 * 2^56 + 0 ... + 0
|
|
% = 2^63.
|
|
integer_min_int64 = i(-5, [-128, 0, 0, 0, 0]).
|
|
|
|
% Return max_int64 as an integer.
|
|
%
|
|
:- func integer_max_int64 = integer.
|
|
|
|
% 127 * 2^(14*4) + 16383 * 2^(14*3) + ... + 16383 * 2^(14*0)
|
|
% = (2^7 - 1) * 2^56 + (2^14 - 1) * 2^42 + ... + (2^14 - 1) * 1
|
|
% = 2^63 - 1.
|
|
integer_max_int64 = i(5, [127, 16383, 16383, 16383, 16383]).
|
|
|
|
:- func int64_list(list(int), int64) = int64.
|
|
|
|
int64_list([], Accum) = Accum.
|
|
int64_list([H | T], Accum) =
|
|
int64_list(T, Accum * from_int(base) + from_int(H)).
|
|
|
|
det_to_int64(Integer) = Int64 :-
|
|
( if integer.to_int64(Integer, Int64Prime) then
|
|
Int64 = Int64Prime
|
|
else
|
|
throw(math.domain_error(
|
|
"integer.det_to_int64: domain error (conversion would overflow"))
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
to_uint64(Integer, UInt64) :-
|
|
Integer = i(Sign, Digits),
|
|
Sign >= 0, % i.e. Integer >= 0.
|
|
Integer =< integer_max_uint64,
|
|
UInt64 = uint64_list(Digits, uint64.cast_from_int(0)).
|
|
|
|
% Return max_uint64 as an integer.
|
|
%
|
|
:- func integer_max_uint64 = integer.
|
|
|
|
% 255 * 2^(14*4) + 16383 * 2^(14*3) + ... + 16383 * 2(14*0)
|
|
% = (2^8 - 1) * 2^56 + (2^14 - 1) * 2^42 + ... + (2^14 - 1) * 2^0
|
|
% = 2^64 - 2^56 + 2^56 - 2^42 + ... + 2^14 - 1
|
|
% = 2^64 - 1.
|
|
integer_max_uint64 = i(5, [255, 16383, 16383, 16383, 16383]).
|
|
|
|
:- func uint64_list(list(int), uint64) = uint64.
|
|
|
|
uint64_list([], Accum) = Accum.
|
|
uint64_list([H | T], Accum) =
|
|
uint64_list(T, Accum * cast_from_int(base) + cast_from_int(H)).
|
|
|
|
det_to_uint64(Integer) = UInt64 :-
|
|
( if integer.to_uint64(Integer, UInt64Prime) then
|
|
UInt64 = UInt64Prime
|
|
else
|
|
throw(math.domain_error(
|
|
"integer.det_to_uint64: domain error (conversion would overflow"))
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
float(i(_, List)) = float_list(float.float(base), 0.0, List).
|
|
|
|
:- func float_list(float, float, list(int)) = float.
|
|
|
|
float_list(_, Accum, []) = Accum.
|
|
float_list(FBase, Accum, [H | T]) =
|
|
float_list(FBase, Accum * FBase + float.float(H), T).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Converting integers to strings.
|
|
%
|
|
|
|
to_string(Integer) = to_base_string(Integer, 10).
|
|
|
|
to_base_string(Integer, Base) = String :-
|
|
( if 2 =< Base, Base =< 36 then
|
|
true
|
|
else
|
|
unexpected($module, $pred, "invalid base")
|
|
),
|
|
PrintBase = printbase(pow(Base, printbase_exponent)),
|
|
Integer = i(Sign, Digits),
|
|
( if Sign < 0 then
|
|
neg_list(Digits, AbsDigits),
|
|
String = "-" ++ digits_to_string(Base, PrintBase, AbsDigits)
|
|
else
|
|
String = digits_to_string(Base, PrintBase, Digits)
|
|
).
|
|
|
|
:- func digits_to_string(int, printbase, list(digit)) = string.
|
|
|
|
digits_to_string(_Base, _PrintBase, []) = "0".
|
|
digits_to_string(Base, PrintBase, Digits) = Str :-
|
|
Digits = [_ | _],
|
|
printbase_rep(PrintBase, printbase_pos_int_to_digits(PrintBase, base),
|
|
Digits, i(_, DigitsInPrintBase)),
|
|
(
|
|
DigitsInPrintBase = [Head | Tail],
|
|
string.int_to_base_string(Head, Base, HeadStr),
|
|
digits_to_strings(Base, Tail, [], TailStrs),
|
|
string.append_list([HeadStr | TailStrs], Str)
|
|
;
|
|
DigitsInPrintBase = [],
|
|
unexpected($module, $pred, "empty list")
|
|
).
|
|
|
|
:- pred printbase_rep(printbase::in, integer::in, list(digit)::in,
|
|
integer::out) is det.
|
|
|
|
printbase_rep(PrintBase, Base, Digits, Result) :-
|
|
Result = printbase_rep_1(PrintBase, Digits, Base, integer.zero).
|
|
|
|
:- func printbase_rep_1(printbase, list(digit), integer, integer) = integer.
|
|
|
|
printbase_rep_1(_PrintBase, [], _Base, Carry) = Carry.
|
|
printbase_rep_1(PrintBase, [X | Xs], Base, Carry) =
|
|
printbase_rep_1(PrintBase, Xs, Base,
|
|
printbase_pos_plus(PrintBase,
|
|
printbase_pos_mul(PrintBase, Base, Carry),
|
|
printbase_pos_int_to_digits(PrintBase, X))).
|
|
|
|
:- pred digits_to_strings(int::in, list(digit)::in,
|
|
list(string)::in, list(string)::out) is det.
|
|
|
|
digits_to_strings(_Base, [], !Strs).
|
|
digits_to_strings(Base, [H | T], !Strs) :-
|
|
digit_to_string(Base, H, Str),
|
|
digits_to_strings(Base, T, !Strs),
|
|
!:Strs = [Str | !.Strs].
|
|
|
|
:- pred digit_to_string(int::in, digit::in, string::out) is det.
|
|
|
|
digit_to_string(Base, D, S) :-
|
|
string.int_to_base_string(D, Base, S1),
|
|
string.pad_left(S1, '0', printbase_exponent, S).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Essentially duplicated code to work in base `printbase' follows.
|
|
%
|
|
|
|
:- type printbase
|
|
---> printbase(int). % base^printbase_exponent
|
|
|
|
:- func printbase_exponent = int.
|
|
|
|
printbase_exponent = 3.
|
|
|
|
:- func printbase_pos_int_to_digits(printbase, int) = integer.
|
|
|
|
printbase_pos_int_to_digits(Base, D) =
|
|
printbase_pos_int_to_digits_2(Base, D, integer.zero).
|
|
|
|
:- func printbase_pos_int_to_digits_2(printbase, int, integer) = integer.
|
|
|
|
printbase_pos_int_to_digits_2(Base, D, Tail) = Result :-
|
|
( if D = 0 then
|
|
Result = Tail
|
|
else
|
|
Tail = i(Length, Digits),
|
|
printbase_chop(Base, D, Div, Mod),
|
|
Result = printbase_pos_int_to_digits_2(Base, Div,
|
|
i(Length + 1, [Mod | Digits]))
|
|
).
|
|
|
|
:- pred printbase_chop(printbase::in, int::in, digit::out, digit::out) is det.
|
|
|
|
printbase_chop(printbase(Base), N, Div, Mod) :-
|
|
Mod = N mod Base,
|
|
Div = N div Base.
|
|
|
|
:- func printbase_mul_by_digit(printbase, digit, integer) = integer.
|
|
|
|
printbase_mul_by_digit(Base, D, i(Len, Ds)) = Out :-
|
|
printbase_mul_by_digit_2(Base, D, Div, Ds, DsOut),
|
|
( if Div = 0 then
|
|
Out = i(Len, DsOut)
|
|
else
|
|
Out = i(Len + 1, [Div | DsOut])
|
|
).
|
|
|
|
:- pred printbase_mul_by_digit_2(printbase::in, digit::in, digit::out,
|
|
list(digit)::in, list(digit)::out) is det.
|
|
|
|
printbase_mul_by_digit_2(_Base, _, 0, [], []).
|
|
printbase_mul_by_digit_2(Base, D, Div, [X | Xs], [Mod | NewXs]) :-
|
|
printbase_mul_by_digit_2(Base, D, DivXs, Xs, NewXs),
|
|
printbase_chop(Base, D * X + DivXs, Div, Mod).
|
|
|
|
:- func printbase_pos_plus(printbase, integer, integer) = integer.
|
|
|
|
printbase_pos_plus(Base, i(L1, D1), i(L2, D2)) = Out :-
|
|
printbase_add_pairs(Base, Div, i(L1, D1), i(L2, D2), Ds),
|
|
( if L1 > L2 then
|
|
Len = L1
|
|
else
|
|
Len = L2
|
|
),
|
|
( if Div = 0 then
|
|
Out = i(Len, Ds)
|
|
else
|
|
Out = i(Len + 1, [Div | Ds])
|
|
).
|
|
|
|
:- pred printbase_add_pairs(printbase::in, digit::out,
|
|
integer::in, integer::in, list(digit)::out) is det.
|
|
|
|
printbase_add_pairs(Base, Div, i(L1, D1), i(L2, D2), Ds) :-
|
|
( if L1 = L2 then
|
|
printbase_add_pairs_equal(Base, Div, D1, D2, Ds)
|
|
else if L1 < L2, D2 = [H2 | T2] then
|
|
printbase_add_pairs(Base, Div1, i(L1, D1), i(L2 - 1, T2), Ds1),
|
|
printbase_chop(Base, H2 + Div1, Div, Mod),
|
|
Ds = [Mod | Ds1]
|
|
else if L1 > L2, D1 = [H1 | T1] then
|
|
printbase_add_pairs(Base, Div1, i(L1 - 1, T1), i(L2, D2), Ds1),
|
|
printbase_chop(Base, H1 + Div1, Div, Mod),
|
|
Ds = [Mod | Ds1]
|
|
else
|
|
unexpected($module, $pred, "integer.printbase_add_pairs")
|
|
).
|
|
|
|
:- pred printbase_add_pairs_equal(printbase::in, digit::out,
|
|
list(digit)::in, list(digit)::in, list(digit)::out) is det.
|
|
|
|
printbase_add_pairs_equal(_, 0, [], _, []).
|
|
printbase_add_pairs_equal(_, 0, [_ | _], [], []).
|
|
printbase_add_pairs_equal(Base, Div, [X | Xs], [Y | Ys], [Mod | TailDs]) :-
|
|
printbase_add_pairs_equal(Base, DivTail, Xs, Ys, TailDs),
|
|
printbase_chop(Base, X + Y + DivTail, Div, Mod).
|
|
|
|
:- func printbase_pos_mul(printbase, integer, integer) = integer.
|
|
|
|
printbase_pos_mul(Base, i(L1, Ds1), i(L2, Ds2)) =
|
|
( if L1 < L2 then
|
|
printbase_pos_mul_list(Base, Ds1, integer.zero, i(L2, Ds2))
|
|
else
|
|
printbase_pos_mul_list(Base, Ds2, integer.zero, i(L1, Ds1))
|
|
).
|
|
|
|
:- func printbase_pos_mul_list(printbase, list(digit), integer, integer)
|
|
= integer.
|
|
|
|
printbase_pos_mul_list(_Base, [], Carry, _Y) = Carry.
|
|
printbase_pos_mul_list(Base, [X | Xs], Carry, Y) =
|
|
printbase_pos_mul_list(Base, Xs,
|
|
printbase_pos_plus(Base, mul_base(Carry),
|
|
printbase_mul_by_digit(Base, X, Y)), Y).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Converting ints to integers.
|
|
%
|
|
|
|
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 :-
|
|
( if D = 0 then
|
|
Int = integer.zero
|
|
else if D > 0, D < base then
|
|
Int = i(1, [D])
|
|
else if D < 0, D > -base then
|
|
Int = i(-1, [D])
|
|
else
|
|
( if int.min_int(D) then
|
|
% Were we to call int.abs, int overflow might occur.
|
|
Int = integer(D + 1) - integer.one
|
|
else
|
|
Int = big_sign(D, pos_int_to_digits(int.abs(D)))
|
|
)
|
|
).
|
|
|
|
:- func pos_int_to_digits(int) = integer.
|
|
|
|
pos_int_to_digits(D) = pos_int_to_digits_2(D, integer.zero).
|
|
|
|
:- func pos_int_to_digits_2(int, integer) = integer.
|
|
|
|
pos_int_to_digits_2(D, Tail) = Result :-
|
|
( if D = 0 then
|
|
Result = Tail
|
|
else
|
|
Tail = i(Length, Digits),
|
|
chop(D, Div, Mod),
|
|
Result = pos_int_to_digits_2(Div, i(Length + 1, [Mod | Digits]))
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Converting uints to integers.
|
|
%
|
|
|
|
from_uint(U) = Integer :-
|
|
( if U = 0u then
|
|
Integer = integer.zero
|
|
else if U < cast_from_int(base) then
|
|
Integer = i(1, [cast_to_int(U)])
|
|
else
|
|
Integer = uint_to_digits(U)
|
|
).
|
|
|
|
:- func uint_to_digits(uint) = integer.
|
|
|
|
uint_to_digits(U) = uint_to_digits_2(U, integer.zero).
|
|
|
|
:- func uint_to_digits_2(uint, integer) = integer.
|
|
|
|
uint_to_digits_2(U, Tail) = Result :-
|
|
( if U = 0u then
|
|
Result = Tail
|
|
else
|
|
Tail = i(Length, Digits),
|
|
chop_uint(U, Div, Mod),
|
|
Result = uint_to_digits_2(Div,
|
|
i(Length + 1, [cast_to_int(Mod) | Digits]))
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
from_int8(I8) = Integer :-
|
|
I = int8.to_int(I8),
|
|
Integer = integer(I).
|
|
|
|
from_uint8(U8) = Integer :-
|
|
I = uint8.to_int(U8),
|
|
Integer = integer(I).
|
|
|
|
from_int16(I16) = Integer :-
|
|
I = int16.to_int(I16),
|
|
Integer = integer(I).
|
|
|
|
from_uint16(U16) = Integer :-
|
|
I = uint16.to_int(U16),
|
|
Integer = integer(I).
|
|
|
|
from_int32(I32) = Integer :-
|
|
I = int32.to_int(I32),
|
|
Integer = integer(I).
|
|
|
|
from_uint32(U32) = Integer :-
|
|
( if U32 = 0u32 then
|
|
Integer = integer.zero
|
|
else if U32 < cast_from_int(base) then
|
|
Integer = i(1, [cast_to_int(U32)])
|
|
else
|
|
Integer = uint32_to_digits(U32)
|
|
).
|
|
|
|
:- func uint32_to_digits(uint32) = integer.
|
|
|
|
uint32_to_digits(U) = uint32_to_digits_2(U, integer.zero).
|
|
|
|
:- func uint32_to_digits_2(uint32, integer) = integer.
|
|
|
|
uint32_to_digits_2(U, Tail) = Result :-
|
|
( if U = 0u32 then
|
|
Result = Tail
|
|
else
|
|
Tail = i(Length, Digits),
|
|
chop_uint32(U, Div, Mod),
|
|
Result = uint32_to_digits_2(Div,
|
|
i(Length + 1, [cast_to_int(Mod) | Digits]))
|
|
).
|
|
|
|
from_int64(I64) = Integer :-
|
|
( if
|
|
I64 = from_int(0)
|
|
then
|
|
Integer = integer.zero
|
|
else if
|
|
I64 > from_int(0),
|
|
I64 < from_int(base)
|
|
then
|
|
Integer = i(1, [cast_to_int(I64)])
|
|
else if
|
|
I64 < from_int(0),
|
|
I64 > from_int(-base)
|
|
then
|
|
Integer = i(-1, [cast_to_int(I64)])
|
|
else if I64 = int64.min_int64 then
|
|
% If we were to call int64.abs with mint_int64 as an argument it would
|
|
% overflow.
|
|
Integer = integer.from_int64(I64 + from_int(1)) - integer.one
|
|
else
|
|
Magnitude = pos_int64_to_digits(int64.abs(I64)),
|
|
( if I64 < int64.from_int(0) then
|
|
Integer = big_neg(Magnitude)
|
|
else
|
|
Integer = Magnitude
|
|
)
|
|
).
|
|
|
|
:- func pos_int64_to_digits(int64) = integer.
|
|
|
|
pos_int64_to_digits(D) = pos_int64_to_digits_2(D, integer.zero).
|
|
|
|
:- func pos_int64_to_digits_2(int64, integer) = integer.
|
|
|
|
pos_int64_to_digits_2(D, Tail) = Result :-
|
|
( if D = int64.from_int(0) then
|
|
Result = Tail
|
|
else
|
|
Tail = i(Length, Digits),
|
|
chop_int64(D, Div, Mod),
|
|
Result = pos_int64_to_digits_2(Div,
|
|
i(Length + 1, [cast_to_int(Mod) | Digits]))
|
|
).
|
|
|
|
from_uint64(U64) = Integer :-
|
|
( if U64 = cast_from_int(0) then
|
|
Integer = integer.zero
|
|
else if U64 < cast_from_int(base) then
|
|
Integer = i(1, [cast_to_int(U64)])
|
|
else
|
|
Integer = uint64_to_digits(U64)
|
|
).
|
|
|
|
:- func uint64_to_digits(uint64) = integer.
|
|
|
|
uint64_to_digits(U) = uint64_to_digits_2(U, integer.zero).
|
|
|
|
:- func uint64_to_digits_2(uint64, integer) = integer.
|
|
|
|
uint64_to_digits_2(U, Tail) = Result :-
|
|
( if U = cast_from_int(0) then
|
|
Result = Tail
|
|
else
|
|
Tail = i(Length, Digits),
|
|
chop_uint64(U, Div, Mod),
|
|
Result = uint64_to_digits_2(Div,
|
|
i(Length + 1, [cast_to_int(Mod) | Digits]))
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Converting strings to integers.
|
|
%
|
|
|
|
from_string(S) = Big :-
|
|
integer.from_string(S, Big).
|
|
|
|
from_string(S, Big) :-
|
|
string.to_char_list(S, Cs),
|
|
string_to_integer(Cs, Big).
|
|
|
|
:- pred string_to_integer(list(char)::in, integer::out) is semidet.
|
|
|
|
string_to_integer(Chars, Integer) :-
|
|
Chars = [HeadChar | TailChars],
|
|
( if HeadChar = ('-') then
|
|
TailChars = [_ | _], % Don't accept just "-" as an integer.
|
|
string_to_integer_acc(TailChars, integer.zero, PosInteger),
|
|
Integer = big_sign(-1, PosInteger)
|
|
else if HeadChar = ('+') then
|
|
TailChars = [_ | _], % Don't accept just "+" as an integer.
|
|
string_to_integer_acc(TailChars, integer.zero, Integer)
|
|
else
|
|
string_to_integer_acc(Chars, integer.zero, Integer)
|
|
).
|
|
|
|
:- pred string_to_integer_acc(list(char)::in, integer::in, integer::out)
|
|
is semidet.
|
|
|
|
string_to_integer_acc([], !Integer).
|
|
string_to_integer_acc([C | Cs], !Integer) :-
|
|
% The if-then-else here is acting as a sequential conjunction.
|
|
% It is needed to guarantee termination with --reorder-conj.
|
|
% Without it, the value of `Digit0 - Z' might be negative and
|
|
% then the call to pos_int_to_digits/1 may not terminate.
|
|
( if char.is_digit(C) then
|
|
Digit0 = char.to_int(C),
|
|
Z = char.to_int('0'),
|
|
Digit = pos_int_to_digits(Digit0 - Z),
|
|
!:Integer = pos_plus(Digit, mul_by_digit(10, !.Integer)),
|
|
string_to_integer_acc(Cs, !Integer)
|
|
else
|
|
fail
|
|
).
|
|
|
|
det_from_string(S) = I :-
|
|
( if integer.from_string(S, IPrime) then
|
|
I = IPrime
|
|
else
|
|
unexpected($module, $pred, "conversion failed")
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Converting base strings to integers.
|
|
%
|
|
|
|
from_base_string(Base, String) = Integer :-
|
|
integer.from_base_string(Base, String, Integer).
|
|
|
|
from_base_string(Base, String, Integer) :-
|
|
string.index(String, 0, Char),
|
|
Len = string.length(String),
|
|
( if Char = ('-') then
|
|
Len > 1,
|
|
string.foldl_between(accumulate_integer(Base), String, 1, Len,
|
|
integer.zero, PosInteger),
|
|
Integer = -PosInteger
|
|
else if Char = ('+') then
|
|
Len > 1,
|
|
string.foldl_between(accumulate_integer(Base), String, 1, Len,
|
|
integer.zero, Integer)
|
|
else
|
|
string.foldl_between(accumulate_integer(Base), String, 0, Len,
|
|
integer.zero, Integer)
|
|
).
|
|
|
|
:- pred accumulate_integer(int::in, char::in, integer::in, integer::out)
|
|
is semidet.
|
|
|
|
accumulate_integer(Base, Char, !N) :-
|
|
char.base_digit_to_int(Base, Char, Digit0),
|
|
Digit = integer(Digit0),
|
|
!:N = (integer(Base) * !.N) + Digit.
|
|
|
|
det_from_base_string(Base, String) = Integer :-
|
|
( if integer.from_base_string(Base, String, IntegerPrime) then
|
|
Integer = IntegerPrime
|
|
else
|
|
unexpected($module, $pred, "conversion failed")
|
|
).
|
|
|
|
from_base_string_underscore(Base, String, Integer) :-
|
|
string.index(String, 0, Char),
|
|
Len = string.length(String),
|
|
( if Char = ('-') then
|
|
Len > 1,
|
|
string.foldl_between(accumulate_integer_underscore(Base), String,
|
|
1, Len, integer.zero, PosInteger),
|
|
Integer = -PosInteger
|
|
else if Char = ('+') then
|
|
Len > 1,
|
|
string.foldl_between(accumulate_integer_underscore(Base), String,
|
|
1, Len, integer.zero, Integer)
|
|
else
|
|
string.foldl_between(accumulate_integer_underscore(Base), String,
|
|
0, Len, integer.zero, Integer)
|
|
).
|
|
|
|
:- pred accumulate_integer_underscore(int::in, char::in,
|
|
integer::in, integer::out) is semidet.
|
|
|
|
accumulate_integer_underscore(Base, Char, !N) :-
|
|
( if char.base_digit_to_int(Base, Char, Digit0) then
|
|
Digit = integer(Digit0),
|
|
!:N = (integer(Base) * !.N) + Digit
|
|
else if Char = '_' then
|
|
true
|
|
else
|
|
false
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|