• No results found

If precise arithmetic with rational numbers is required the Ada language can be extended by the inclusion of a package that provides a new type Rational. Instances of this type may be used as if they were normal numeric values such as integer.

The following extension to the language Ada is created by defining the class Rational. This class defines the following operations: +, -, * on an instance of a Rational number.

The responsibilities of this class are as follows::

Method Responsibility

+ Delivers the sum of two rational numbers as a rational number.

- Delivers the difference of two rational numbers as a rational number.

* Delivers the product of two rational numbers as a rational

number.

/ Delivers the division of two rational numbers as a rational

number.

In addition the following methods are used to create a rational constant and to help output a rational number in a canonical form.

Method Responsibility

Rat_Const Creates a rational number from two Integer numbers.

Image Returns a string image of a rational number in the canonical form ‘a b/c’. For example:

Put( Image( Rat_Const(3,2) ) );

would print

1 1/2

12.2.1Ada specification of the package

The specification of the package is as follows:

package Class_Rational is type Rational is private;

function "+" ( F:in Rational; S:in Rational ) return Rational; function "-" ( F:in Rational; S:in Rational ) return Rational; function "*" ( F:in Rational; S:in Rational ) return Rational; function "/" ( F:in Rational; S:in Rational ) return Rational; function Rat_Const( F:in Integer;

S:in Integer:=1 ) return Rational; function Image( The:in Rational ) return String; private

type Rational is record

Above : Integer := 0; --Numerator Below : Integer := 1; --Denominator end record;

Using the above package, the following code can be written:

with Ada.Text_Io, Class_Rational; use Ada.Text_Io, Class_Rational; procedure Main is

A,B : Rational; begin

A := Rat_Const( 1, 2 ); B := Rat_Const( 1, 3 );

Put( "a = " ); Put( Image(A) ); New_Line; Put( "b = " ); Put( Image(B) ); New_Line; Put( "a + b = " ); Put( Image(A+B) ); New_Line; Put( "a - b = " ); Put( Image(A-B) ); New_Line; Put( "b - a = " ); Put( Image(B-A) ); New_Line; Put( "a * b = " ); Put( Image(A*B) ); New_Line; Put( "a / b = " ); Put( Image(A/B) ); New_Line; end Main;

which when run will deliver the following output:

a = 1/2 b = 1/3 a + b = 5/6 a - b = 1/6 b - a = -1/6 a * b = 1/6 a / b = 1 1/2

12.2.2Ada implementation of the package

The internal function sign makes sure that only the top part of the rational number may be negative. By ensuring this form, the processing of rational numbers is simplified in later code.

package body Class_Rational is

function Sign( The:in Rational ) return Rational is begin

if The.Below >= 0 then -- -a/b or a/b return The;

else -- a/-b or -a/-b return Rational'( -The.Above, -The.Below ); end if;

The internal function simplify reduces the rational number to its simplest form. Thus the rational number

4/8 is reduced to 1/2.

function Simplify( The:in Rational ) return Rational is Res: Rational := The;

D : Positive; --Divisor to reduce with begin

if Res.Below = 0 then --Invalid treat as 0 Res.Above := 0; Res.Below := 1;

end if;

D := 2; --Divide by 2, 3, 4 ... while D < Res.Below loop

while Res.Below rem D = 0 and then Res.Above rem D = 0 loop Res.Above := Res.Above / D; Res.Below := Res.Below / D; end loop; D := D + 1; end loop; return Res; end Simplify;

Note: It is left to the reader to improve the efficiency of the algorithm used.

The standard operators of +, -, /, and * are overloaded to allow these standard operations to be performed between instances of rational numbers.

function "+" (F:in Rational; S:in Rational) return Rational is Res : Rational;

begin

Res.Below := F.Below * S.Below;

Res.Above := F.Above * S.Below + S.Above * F.Below; return Simplify(Res);

end "+";

function "-" (F:in Rational; S:in Rational) return Rational is Res : Rational;

begin

Res.Below := F.Below * S.Below;

Res.Above := F.Above * S.Below - S.Above * F.Below; return Simplify(Res);

end "-";

function "*" (F:in Rational; S:in Rational) return Rational is Res : Rational;

begin

Res.Above := F.Above * S.Above; Res.Below := F.Below * S.Below; return Simplify(Res);

end "*";

function "/" (F:in Rational; S:in Rational) return Rational is Res : Rational;

begin

Res.Above := F.Above * S.Below; Res.Below := F.Below * S.Above; return Simplify(Res);

The function Rat_Const is used to construct a constant rational number. The second formal parameter may be omitted when converting a whole number into a rational number.

function Rat_Const( F:in Integer;

S:in Integer:=1 ) return Rational is begin

if F = 0 then

return Rational'(0,1); else

return Simplify( Sign( Rational'( F, S ) ) ); end if;

end Rat_Const;

Note: A rational constant could have been created by overloading the operator / between two integers to deliver a rational number. The disadvantage of this approach is that the two distinct meanings for /

The function Image returns a string representing a rational number in canonical form. The strategy used is to use the inbuilt function Integer’Image to convert a number into a character string. However, as this leaves a leading space for the sign character an internal function Trim is provided to strip off the leading character from such a string.

The nested function To_String delivers a string representation in canonical form of a positive rational number. By using a single case of recursion this function can deal with the case when a rational number is of the form “a b/c”.

function Image( The:in Rational ) return String is Above : Integer := The.Above;

Below : Integer := The.Below;

function Trim( Str:in String ) return String is begin

return Str( Str'First+1 .. Str'Last ); end Trim;

function To_String( Above, Below : in Integer ) return String is

begin

if Above = 0 then --No fraction return "";

elsif Above >= Below then --Whole number

return Trim( Integer'Image(Above/Below) ) & " " & To_String( Above rem below, Below ); else

return Trim( Integer'Image( Above ) ) & "/" & Trim( Integer'Image( Below ) );

end if; end To_String; begin

if Above = 0 then

return "0"; --Zero elsif Above < 0 then

return "-" & To_String( abs Above, Below ); ---ve else

return To_String( Above, Below ); --+ve end if;

end Image;

end Class_Rational;

Related documents