packages feed

language-Modula2-0.1: examples/Modula-2_Libraries/PMOS/sources/general/rational.mod

IMPLEMENTATION MODULE Rationals;

	(********************************************************)
	(*							*)
	(*		Arithmetic on rational numbers		*)
	(*							*)
	(*  Programmer:		P. Moylan			*)
	(*  Last edited:	2 May 1994			*)
	(*  Status:		OK				*)
	(*							*)
	(********************************************************)


PROCEDURE gcd (x, y: CARDINAL): CARDINAL;

    (* Returns the greatest common divisor of x and y. *)

    VAR temp: CARDINAL;

    BEGIN
	IF x < y THEN
	    temp := x;  x := y;  y := temp;
	END (*IF*);
	WHILE y <> 0 DO
	    temp := x MOD y;  x := y;  y := temp;
	END (*WHILE*);
	RETURN x;
    END gcd;

(****************************************************************)

PROCEDURE Reduce (VAR (*INOUT*) x: Rational);

    (* Removes common factors between the numerator and the denominator. *)

    VAR top, factor: CARDINAL;

    BEGIN
	top := ABS(x.num);
	factor := gcd (top, x.denom);
	x.num := x.num DIV INTEGER(factor);
	x.denom := x.denom DIV factor;
    END Reduce;

(****************************************************************)

PROCEDURE Zero (): Rational;

    (* Returns a representation of zero. *)

    VAR result: Rational;

    BEGIN
	result.num := 0;  result.denom := 1;
	RETURN result;
    END Zero;

(****************************************************************)

PROCEDURE Unity (): Rational;

    (* Returns a representation of the number 1. *)

    VAR result: Rational;

    BEGIN
	result.num := 1;  result.denom := 1;
	RETURN result;
    END Unity;

(****************************************************************)

PROCEDURE Add (x, y: Rational): Rational;

    (* Returns x+y. *)

    VAR result: Rational;

    BEGIN
	result.num := x.num*INTEGER(y.denom) + y.num*INTEGER(x.denom);
	result.denom := x.denom * y.denom;
	Reduce (result);
	RETURN result;
    END Add;

(****************************************************************)

PROCEDURE Subtract (x, y: Rational): Rational;

    (* Returns x-y. *)

    VAR result: Rational;

    BEGIN
	result.num := x.num*INTEGER(y.denom) - y.num*INTEGER(x.denom);
	result.denom := x.denom * y.denom;
	Reduce (result);
	RETURN result;
    END Subtract;

(****************************************************************)

PROCEDURE Compare (x, y: Rational): INTEGER;

    (* Returns 0 if x=y, <0 if x<y, and >0 if x>y. *)

    VAR test: INTEGER;

    BEGIN
	test := x.num*INTEGER(y.denom) - y.num*INTEGER(x.denom);
	IF test > 0 THEN RETURN +1
	ELSIF test = 0 THEN RETURN 0
	ELSE RETURN -1
	END (*IF*);
    END Compare;

(****************************************************************)

PROCEDURE Multiply (x, y: Rational): Rational;

    (* Returns x*y. *)

    VAR result: Rational;  temp: CARDINAL;

    BEGIN
	(* To reduce the chance of overflow, do the reductions	*)
	(* before the multiplication.				*)

	temp := x.denom;  x.denom := y.denom;  y.denom := temp;
	Reduce (x);  Reduce(y);
	result.num := x.num * y.num;
	result.denom := x.denom * y.denom;
	RETURN result;
    END Multiply;

(****************************************************************)

PROCEDURE Divide (x, y: Rational): Rational;

    (* Returns x/y. *)

    BEGIN
	RETURN Multiply (x, Reciprocal(y));
    END Divide;

(****************************************************************)

PROCEDURE Reciprocal (x: Rational): Rational;

    (* Returns 1/x. *)

    VAR result: Rational;

    BEGIN
	IF x.num < 0 THEN
	    result.num := -INTEGER(x.denom);  result.denom := -x.num;
	ELSE
	    result.num := x.denom;  result.denom := x.num;
	END (*IF*);
	RETURN result;
    END Reciprocal;

(****************************************************************)

END Rationals.