Files
mercury/compiler/rat.m
Zoltan Somogyi b2012c0c0e Rename the types 'type', 'inst' and 'mode' to 'mer_type', 'mer_inst'
Estimated hours taken: 8
Branches: main

compiler/*.m:
	Rename the types 'type', 'inst' and 'mode' to 'mer_type', 'mer_inst'
	and 'mer_mode'. This is to avoid the need to parenthesize these type
	names in some contexts, and to prepare for the possibility of a parser
	that considers those words to be reserved words.

	Rename some other uses of those names (e.g. as item types in
	recompilation.m).

	Delete some redundant synonyms (prog_type, mercury_type) for mer_type.

	Change some type names (e.g. mlds__type) and predicate names (e.g.
	deforest__goal) to make them unique even without module qualification.

	Rename the function symbols (e.g. pure, &) that need to be renamed
	to avoid the need to parenthesize them. Make their replacement names
	more expressive.

	Convert some more modules to four space indentation.

	Avoid excessively long lines, such as those resulting from the
	automatic substitution of 'mer_type' for 'type'.
2005-10-24 04:14:34 +00:00

238 lines
5.4 KiB
Mathematica

%-----------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%-----------------------------------------------------------------------------%
% Copyright (C) 1997-1998, 2003, 2005 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 int.
:- import_module io.
:- import_module string.
%-----------------------------------------------------------------------------%
:- 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 exception.
% 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 ->
throw("rat.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 ->
throw("rat.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).
%-----------------------------------------------------------------------------%