-- -- Body for rational number package. -- with Gnat.Io; use Gnat.Io; package body Rational_Number is -- This is a private method to compute the GCD of two numbers using -- Euclid's Algorithm. function GCD(A, B: Integer) return Integer is Ar: Integer := A; -- These are the candidate values from the Br: Integer := B; -- algorithm. ModVal: Integer; -- Holds Ar mod Br. begin -- Algorithm repeats as long as you can create new Br values. Stop -- at zero when you cannot divide for next value. while Br > 0 loop -- Set for next iteration. ModVal := Ar mod Br; Ar := Br; Br := ModVal; end loop; return Ar; end GCD; -- Use the GCD funtion to place two integers into lowest terms. procedure Lowest(A, B: in out Unsigned) is -- Remember the GCD. The_GCD: Integer := GCD(A, B); begin A := A / The_GCD; B := B / The_GCD; end Lowest; -- Return the rational in lowest terms. function Lowest(R: Rational) return Rational is -- Return value. RetVal: Rational := R; begin -- Lower and send. Lowest(RetVal.Num, RetVal.Denom); return RetVal; end Lowest; -- Get there from an integer or pair of integers. function To_Rational(Num: Integer; Den: Integer := 1) return Rational is R: Rational; -- Return value. begin -- Build and send. R.Num := Num; R.Denom := Den; return R; end To_Rational; -- Output a rational. procedure Put(R: Rational) is -- Convert to lowest terms for printing. RLow: Rational := Lowest(R); begin Put(RLow.Num); if RLow.Denom /= 1 then Put("/"); Put(RLow.Denom); end if; end Put; -- This matches the denominators for addition and subtraction. The two -- functions are converted to have the same denominator. procedure Common_Denom(A, B: in out Rational) is -- The GCD of the denominators of A and B. GCD_Ad_Bd: Integer; AMult: Integer; -- Multiplier for A. begin -- Reduce the fractions and find the GCD.. A := Lowest(A); B := Lowest(B); GCD_Ad_Bd := GCD(A.Denom, B.Denom); -- Re-write with a common denomiator. AMult := B.Denom / GCD_Ad_Bd; -- Multiplier for A. A.Num := A.Num * AMult; -- Numerators. B.Num := B.Num * (A.Denom / GCD_Ad_Bd); A.Denom := A.Denom * AMult; -- Denominators. B.Denom := A.Denom; end Common_Denom; -- Four functions. function "+" (A, B: Rational) return Rational is -- Copies of the args so we can change them. ACopy: Rational := A; BCopy: Rational := B; begin Common_Denom(ACopy, BCopy); return To_Rational(ACopy.Num + BCopy.Num, ACopy.Denom); end "+"; function "-" (A, B: Rational) return Rational is -- Copies of the args so we can change them. ACopy: Rational := A; BCopy: Rational := B; begin Common_Denom(ACopy, BCopy); return To_Rational(ACopy.Num - BCopy.Num, ACopy.Denom); end "-"; function "*" (A, B: Rational) return Rational is -- Copies of the args so we can change them. ACopy: Rational := Lowest(A); BCopy: Rational := Lowest(B); begin -- These changes preserve the product and can prevent overflow under -- some circumstances. Lowest(ACopy.Num, BCopy.Denom); Lowest(BCopy.Num, ACopy.Denom); -- Make the answer. return To_Rational(ACopy.Num * BCopy.Num, ACopy.Denom * BCopy.Denom); end "*"; function "/" (A, B: Rational) return Rational is begin return A * To_Rational(B.Denom, B.Num); end "/"; -- Equality test. Sees if they are the same after reduction to -- lowest terms. function "=" (A, B: Rational) return Boolean is ALow: Rational := Lowest(A); BLow: Rational := Lowest(B); begin return ALow.Num = BLow.Num and ALow.Denom = BLow.Denom; end "="; end Rational_Number;