mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-14 05:12:33 +00:00
Estimated hours taken: 3 Branches: main Clean up in unused module imports in the Mercury system detected by --warn-unused-imports. analysis/*.m: browser/*.m: deep_profiler/*.m: compiler/*.m: library/*.m: mdbcomp/*.m: profiler/*.m: slice/*.m: Remove unused module imports. Fix some minor departures from our coding standards. analysis/Mercury.options: browser/Mercury.options: deep_profiler/Mercury.options: compiler/Mercury.options: library/Mercury.options: mdbcomp/Mercury.options: profiler/Mercury.options: slice/Mercury.options: Set --no-warn-unused-imports for those modules that are used as packages or otherwise break --warn-unused-imports, e.g. because they contain predicates with both foreign and Mercury clauses and some of the imports only depend on the latter.
249 lines
5.9 KiB
Mathematica
249 lines
5.9 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 1997-1998, 2003, 2005-2006 The University of Melbourne.
|
|
% This file may only be copied under the terms of the GNU Library General
|
|
% Public License - see the file COPYING.LIB in the Mercury distribution.
|
|
%-----------------------------------------------------------------------------%
|
|
%
|
|
% File: rat.m.
|
|
% Authors: vjteag, juliensf.
|
|
%
|
|
% Implements a rational number type using fixed precision integers.
|
|
% The functionality here is limited to that which is used in the
|
|
% lp_rational module.
|
|
%
|
|
% NOTE: if you actually want a general purpose rational number type then use
|
|
% the rational module in the standard library. The stuff in this module
|
|
% is pretty heavily geared towards a few specific tasks that are part of
|
|
% the termination analysis.
|
|
%
|
|
% TODO:
|
|
% - overflow checking would be nice
|
|
%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- module libs.rat.
|
|
:- interface.
|
|
|
|
:- import_module io.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- type rat.
|
|
|
|
:- pred '<'(rat::in, rat::in) is semidet.
|
|
|
|
:- pred '>'(rat::in, rat::in) is semidet.
|
|
|
|
:- pred '=<'(rat::in, rat::in) is semidet.
|
|
|
|
:- pred '>='(rat::in, rat::in) is semidet.
|
|
|
|
:- func rat.rat(int) = rat.
|
|
|
|
:- func rat.rat(int, int) = rat.
|
|
|
|
:- func '+'(rat) = rat.
|
|
|
|
:- func '-'(rat) = rat.
|
|
|
|
:- func rat + rat = rat.
|
|
|
|
:- func rat - rat = rat.
|
|
|
|
:- func rat * rat = rat.
|
|
|
|
:- func rat / rat = rat.
|
|
|
|
:- func rat.numer(rat) = int.
|
|
|
|
:- func rat.denom(rat) = int.
|
|
|
|
:- func rat.abs(rat) = rat.
|
|
|
|
:- func rat.one = rat.
|
|
|
|
:- func rat.zero = rat.
|
|
|
|
% Convert a rational to a string of the form: "(<Num>/<Denom>)".
|
|
%
|
|
:- func rat.to_string(rat) = string.
|
|
|
|
% Write a rat in the form: r(<Numerator>, <Denominator>).
|
|
%
|
|
:- pred rat.write_rat(rat::in, io::di, io::uo) is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module libs.compiler_util.
|
|
|
|
:- import_module int.
|
|
:- import_module string.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% The normal form of a rat number has the following
|
|
% properties:
|
|
% - numerator and denominator have no common factors.
|
|
% - denominator is positive.
|
|
% - denominator is not zero.
|
|
% - if numerator is zero, then denominator is one.
|
|
%
|
|
% These invariants must be preserved by any rat number
|
|
% constructed using this module since the equality predicate
|
|
% on rats is simply Mercury's default unification
|
|
% predicate =/2. If the invariants were not maintained,
|
|
% we would have pathologies like r(-1,2) \= r(1,-2).
|
|
%
|
|
% The rat_norm/2 function generates rationals in this
|
|
% normal form.
|
|
%
|
|
:- type rat
|
|
---> r(int, int).
|
|
|
|
'<'(X, Y) :- cmp(X, Y) = (<).
|
|
|
|
'>'(X, Y) :- cmp(X, Y) = (>).
|
|
|
|
'=<'(X, Y) :- cmp(X, Y) \= (>).
|
|
|
|
'>='(X, Y) :- cmp(X, Y) \= (<).
|
|
|
|
rat.rat(Int) = r(Int, 1).
|
|
|
|
rat.rat(Num, Den) = rat_norm(Num, Den).
|
|
|
|
rat.one = r(1, 1).
|
|
|
|
rat.zero = r(0, 1).
|
|
|
|
'+'(Rat) = Rat.
|
|
|
|
'-'(r(Num, Den)) = r(-Num, Den).
|
|
|
|
r(An, Ad) + r(Bn, Bd) = rat_norm(Numer, M) :-
|
|
M = lcm(Ad, Bd),
|
|
CA = M // Ad,
|
|
CB = M // Bd,
|
|
Numer = An * CA + Bn * CB.
|
|
|
|
X - Y = X + (-Y).
|
|
|
|
% XXX: need we call rat_norm here?
|
|
r(An, Ad) * r(Bn, Bd) = rat_norm(Numer, Denom) :-
|
|
G1 = gcd(An, Bd),
|
|
G2 = gcd(Ad, Bn),
|
|
Numer = (An // G1) * (Bn // G2),
|
|
Denom = (Ad // G2) * (Bd // G1).
|
|
|
|
X / Y = X * rat.reciprocal(Y).
|
|
|
|
:- func rat.reciprocal(rat) = rat.
|
|
|
|
reciprocal(r(Num, Den)) =
|
|
( Num = 0 ->
|
|
unexpected(this_file, "reciprocal/1: division by zero")
|
|
;
|
|
r(signum(Num) * Den, int.abs(Num))
|
|
).
|
|
|
|
rat.numer(r(Num, _)) = Num.
|
|
|
|
rat.denom(r(_, Den)) = Den.
|
|
|
|
rat.abs(r(Num, Den)) = r(int.abs(Num), Den).
|
|
|
|
:- func rat_norm(int, int) = rat.
|
|
|
|
rat_norm(Num, Den) = Rat :-
|
|
( Den = 0 ->
|
|
unexpected(this_file, "rat_norm: division by zero")
|
|
; Num = 0 ->
|
|
Rat = r(0, 1)
|
|
;
|
|
G = gcd(Num, Den),
|
|
Num2 = Num * signum(Den),
|
|
Den2 = int.abs(Den),
|
|
Rat = r(Num2 // G, Den2 // G)
|
|
).
|
|
|
|
:- func gcd(int, int) = int.
|
|
|
|
gcd(A, B) = gcd_2(int.abs(A), int.abs(B)).
|
|
|
|
:- func gcd_2(int, int) = int.
|
|
|
|
gcd_2(A, B) = ( B = 0 -> A ; gcd_2(B, A rem B) ).
|
|
|
|
:- func lcm(int, int) = int.
|
|
|
|
lcm(A, B) =
|
|
( A = 0 ->
|
|
0
|
|
; B = 0 ->
|
|
0
|
|
;
|
|
int.abs((A // gcd(A, B)) * B)
|
|
).
|
|
|
|
:- func signum(int) = int.
|
|
|
|
signum(N) = ( N = 0 -> 0 ; N < 0 -> -1 ; 1 ).
|
|
|
|
% Builtin comparison does not give a natural ordering on rats.
|
|
%
|
|
:- func cmp(rat, rat) = comparison_result.
|
|
|
|
cmp(X, Y) = Cmp :-
|
|
Diff = X - Y,
|
|
( is_zero(Diff) ->
|
|
Cmp = (=)
|
|
; is_negative(Diff) ->
|
|
Cmp = (<)
|
|
;
|
|
Cmp = (>)
|
|
).
|
|
|
|
:- pred is_zero(rat::in) is semidet.
|
|
|
|
is_zero(r(0, _)).
|
|
|
|
:- pred is_negative(rat::in) is semidet.
|
|
|
|
is_negative(r(Num, _)) :- Num < 0.
|
|
|
|
rat.to_string(r(Num, Denom)) =
|
|
( Num = 0 ->
|
|
"0"
|
|
;
|
|
"(" ++ string.int_to_string(Num) ++
|
|
( Denom = 1 ->
|
|
""
|
|
;
|
|
"/" ++ string.int_to_string(Denom)
|
|
)
|
|
++ ")"
|
|
).
|
|
|
|
write_rat(r(Numerator, Denominator), !IO) :-
|
|
io.write_string("r(", !IO),
|
|
io.write_int(Numerator, !IO),
|
|
io.write_string(", ", !IO),
|
|
io.write_int(Denominator, !IO),
|
|
io.write_char(')', !IO).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- func this_file= string.
|
|
|
|
this_file = "rat.m".
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
:- end_module rat.
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|