%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Rational arithmetic predicates
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


:- op(800,xfy,is_rnl).   % Rational expression evaluation
:- op(800,xfy,lt_rnl).	 % Less than for rational numbers

(Z is_rnl [Nx,Dx]) :-
	!, is_rnl_norm([Nx,Dx],Z), !.
([X,1] is_rnl X) :-
	integer(X), !.
(Z is_rnl X) :-
	float(X), Y is 10^15, X1 is floor(X*Y),
	Z is_rnl [X1,Y], !.
(Z is_rnl -X) :- !,
	Z is_rnl 0-X, !.
(Z is_rnl X + Y) :- !,
	[Nx,Dx] is_rnl X,
	([Ny,Dy] is_rnl (Y)),
        is_rnl_norm([(Nx*Dy+Ny*Dx),Dx*Dy],Z), !.
(Z is_rnl X - Y) :- !,
	[Ny,Dy] is_rnl Y,
        Z is_rnl X + [-Ny,Dy], !.
(Z is_rnl (X * Y)) :-
	[Nx,Dx] is_rnl X,
	[Ny,Dy] is_rnl Y,
        !, is_rnl_norm([Nx*Ny,Dx*Dy],Z), !.
(Z is_rnl X / Y) :-
        [Ny,Dy] is_rnl Y,
	Z is_rnl X*[Dy,Ny], !.

(X lt_rnl Y) :-
	[Nz,_] is_rnl X-Y,
	Nz < 0.

is_rnl_norm([X1,Y1],[X2,Y2]) :-
	X3 is X1, Y3 is Y1,
	X3 \= 0, !,
	gcd(X3,Y3,Gcd),
	X4 is X3//Gcd, Y4 is Y3//Gcd,
	is_rnl_norm1([X4,Y4],[X2,Y2]).
is_rnl_norm(_,[0,1]) :- !.

is_rnl_norm1([X1,Y1],[X2,Y2]) :-
	Y1 < 0, !,
	X2 is -X1, Y2 is -Y1.
is_rnl_norm1(X,X).

gcd(X,X,X) :- !.
gcd(X,Y,Z) :- X < 0, !, X1 is -X, gcd(X1,Y,Z).
gcd(X,Y,G) :-
  X < Y,
  Y1 is Y mod X,
  (Y1 = 0 -> G = X; gcd(X,Y1,G)).
gcd(X,Y,G) :- X > Y, gcd(Y,X,G).
