• No results found

same program.

Elementary functions such as the trigonometric functions are predefined in the generic package

Ada.Numerics.Generic_Elementary_Functions§A.5.1, which can be instantiated with any float- ing point type. Ada.Numerics.Elementary_Functionsis a predefined instantiation for Float. A package generating random numbers of typeFloatis defined in §A.5.2.1

Annex §G‘Numerics’ has two sections. The first defines packages for complex numbers, including elementary functions and IO. The second ‘Numeric Performance Requirements’ gives a detailed model of computation with real types. The annex is briefly discussed in Section 10.8.

10.7

Fixed point types

Decimal fixed point types

§3.5.9

2 fixed_point_definition ::=

ordinary_fixed_point_definition | decimal_fixed_point_definition 4 decimal_fixed_point_definition ::=

deltastatic_expression digitsstatic_expression [real_range_specification]

8 The set of values of a fixed point type comprise the integral multiples of a number called thesmallof the type. . . .

9 For a decimal fixed point type, thesmallequals thedelta; thedeltashall be a power of 10. . . .

The values of the following type are in the range±9,999,999.99: type Moneyis delta 0.01 digits9;

There is a limit on the precision that can be specified: eventually, the implementation will run out of digits to store values of the requested range. In general, the smaller the delta, the smaller the range that can be specified.

Decimal fixed point types can be implemented usingbinary coded decimal (BCD), which is sup- ported in hardware on some computers. Four bits (a ‘nibble’) are sufficient to encode the ten values of a single digit, so two digits can be stored in a single byte. Alternatively, the multiple of the delta can be stored as a normal integer and the value scaled with the delta as needed.

Multiplication and division are problematical for fixed point types. Suppose thatM1andM2are two variables of typeMoneythat both contain the value 0.25. What is the type ofM1*M2which equals 0.0625? This answer is that the type must be given by the context; if the expressionM1*M2

is assigned to another variable of typeMoney, the value will be truncated to 0.06. The rules are given in §4.5.5and will be demonstrated in the next case study.

1There is also a generic package for random numbers that can be instantiated with adiscretetype; we used this package in the rocket simulation.

10.7 Fixed point types 169

Annex F Information Systems

Historically, there has been a large gap between the world of scientific and systems programming, and business programming, where COBOL has been the language of choice. Of course, most of the requirements for a language for business programming are not different from those of other fields: reliability, efficiency, system interfaces and support for software engineering. The primary extension needed is in the area of decimal types.

The decimal fixed point types in Ada provide this basic functionality, though an implementation need not support such types §3.5.9(21). Implementations conforming to Annex §F‘Information Systems’ are required to implement decimal fixed point types, as well as three packages: Ada.- Decimal, which contains named numbers specifying properties of the decimal types and a generic procedure for arbitrary decimal fixed point division, andAda.Text_IO.EditingandAda.Wide_- Text_IO.Editingfor formatted input–output.

Case study: currency conversion

The following program reads a currency and an amount, and writes the equivalent value in the other eight currencies. A table copied from my daily newspaper gives the conversion rates—to four digits after the decimal point—between the currencies.

Currencies ‡13is an enumeration type used internally;Signs ‡16–25is an array of bounded strings for display of the currency symbols. PackageAda.Characters.Latin_1§A.3.3contains characters for the British Pound and the Japanese Yen. My computer cannot display them, but the program is still portable.

- - File: CONVERT

1 - -

2 - - Currency conversion using decimal fixed types. 3 - -

4 withAda.Strings.Bounded;

5 packageBS is newAda.Strings.Bounded.Generic_Bounded_Length(10);

6 7 withBS; 8 withAda.Characters.Latin_1; 9 withAda.Text_IO.Editing; 10 use Ada.Text_IO; 11 procedure Convert is 12

13 type Currenciesis(US, UK, DM, Y, SF, FF, fl, LIT, BF);

14 packageCurrency_IO is newEnumeration_IO(Currencies);

15

16 Signs: constant array(Currencies)of BS.Bounded_String := (

17 BS.To_Bounded_String("$"),

18 BS.To_Bounded_String((1=>Ada.Characters.Latin_1.Pound_Sign)),

19 BS.To_Bounded_String("DM"),

20 BS.To_Bounded_String((1=>Ada.Characters.Latin_1.Yen_Sign)),

10.7 Fixed point types 170

22 BS.To_Bounded_String("FF"),

23 BS.To_Bounded_String("fl"),

24 BS.To_Bounded_String("LIT"),

25 BS.To_Bounded_String("BF"));

Money ‡26is a decimal fixed point type with two digits after the decimal point. To read a currency and an amount, Ada.Text_IO.Enumeration_IO §A.10.10is instantiated‡14with typeCurren- cies, andAda.Text_IO.Decimal_IO§A.10.9is instantiated‡27with typeMoney.

26 type Moneyis delta 0.01digits 9;

27 packageMoney_IO is newDecimal_IO(Money);

28

Conversion ‡31–40is a table of the exchange rates; the component typeRates ‡29has four digits. Since the denominations of currencies vary, a table Factors ‡42–44provides additional scaling; for example, one US dollar is worth 1.8399 thousand Italian Lira, or conversely, one thousand

Lira is worth $0.5435.

29 type Ratesis delta 0.0001 digits6;

30

31 Conversion: constant array(Currencies, Currencies)of Rates :=

32 (( 1.0, 0.6265, 1.8807, 1.1877, 1.5315, 6.3741, 2.1191, 1.8399, 3.8840), 33 (1.5961, 1.0, 3.0018, 1.8957, 2.4443, 10.1304, 3.3823, 2.9367, 6.1991), 34 (0.5317, 0.3331, 1.0, 0.6315, 0.8143, 3.3748, 1.1268, 0.9783, 2.0652), 35 (0.8419, 0.5275, 1.5835, 1.0, 1.2894, 5.3439, 1.7842, 1.5491, 3.2701), 36 (0.6530, 0.4091, 1.2280, 0.7755, 1.0, 4.1444, 1.3837, 1.2014, 2.5361), 37 (0.1576, 0.0987, 0.2963, 0.1871, 0.2413, 1.0, 0.3339, 0.2899, 0.6119), 38 (0.4719, 0.2957, 0.8875, 0.5605, 0.7227, 2.9951, 1.0, 0.8682, 1.8328), 39 (0.5435, 0.3405, 1.0222, 0.6455, 0.8324, 3.4496, 1.1517, 1.0, 2.1109), 40 (0.2575, 0.1613, 0.4824, 0.3058, 0.3943, 1.6342, 0.5456, 0.4737, 1.0)); 41

42 Factors: constant array(Currencies) of Integer :=

43 (US => 1, UK => 1, DM => 1, Y => 100, SF => 1, FF => 1,

44 FL => 1, LIT => 1000, BF => 10);

Function Get_Value ‡45–51 performs the conversion. The expression we want to compute is (M/F1)·R·F2, whereM is the amount of money,Ris the conversion rate, andF1 andF2 are the factors for the original currency and the new one.

45 functionGet_Value(M: Money; From, To: Currencies)returnMoneyis

46 type Intermediate is delta 0.000001digits13;

47 begin

48 returnMoney(

49 (Intermediate(M) / Factors(From)) *

50 (Intermediate(Conversion(From, To)) * Factors(To)) );

10.7 Fixed point types 171

The operators we have at our disposal are:

§4.5.5

13 The following multiplication and division operators, with an operand of the prede- fined type Integer, are predefined for every specific fixed point typeT:

14 function"*"(Left : T; Right : Integer)returnT

function"*"(Left : Integer; Right : T) returnT

function"/"(Left : T; Right : Integer)returnT

§4.5.5

18 Multiplication and division between any two fixed point types are provided by the following two predefined operators:

19 function"*"(Left, Right : universal_fixed)

returnuniversal_fixed

function"/"(Left, Right : universal_fixed)

returnuniversal_fixed

The division M/F1 has a fixed point dividend and an integer divisor and returns a fixed point quotient of thesametype as the dividend. If we divide 999.99 Italian Lira by 1000, the result will be 0.99 after truncation to two fractional digits. To maintain precision, we have declared a new typeIntermediate ‡46with six fractional digits. The amount of money is converted to this type before division by the factor.

The expression can be computed in one of two orders: ((M/F1)·R) ·F2 or (M/F1)·(R· F2). We have chosen the second order: the result ofR·F2 is also converted to a value of type

Intermediate and the final multiplication between the two fixed point values returns a result of typeuniversal_fixed, which is converted to the typeMoney.

Writing the converted amounts is done usingAda.Text_IO.Editing.Decimal_Output§F.3.3in- stantiated with type Money ‡52. This package supplies a private type Picture that is used for format control. A value of typePictureis created by callingTo_Picturewith a string of format control characters‡53.

52 packageEdit is newEditing.Decimal_Output(Money);

53 Money_Picture: Editing.Picture := Editing.To_Picture("###*_***_**9.99");

The syntax and semantics of formatting are specified in §F.3.1and §F.3.2; you can also consult a COBOL textbook, since picture formatting is almost identical in the two languages. The picture we use is"###*_***_**9.99", where the meaning of each character is as follows:

• ’9’- Decimal digit.

• ’.’- Radix mark (‘decimal point’).

• ’_’- Separator character.

• ’*’- Fill character.

10.7 Fixed point types 172

The amount 4156.34 French Francs will be written as FF***4,156.34.

Fill characters are used instead of blanks to prevent forgery. The picture characters are fixed in the language, but the displayed characters are parameters of the procedurePutand can be changed for localization. Alternatively, new default values can be specified whenDecimal_IOis instantiated.2 The main subprogram performs the interactive dialog and calls Get_Value ‡74 for each target currency. The dialog is in a loop containing a block ‡56–86 with exception handlers ‡81–85. Entering an invalid code for a currency will raiseData_Error§A.13(6). If the value is too large, eitherConstraint_Errorwill be raised during the computation orPicture_Error§F.3.3(9) will be raised during formatting. After the exception is handled, the block is left and the next iteration of loop gives the user a chance to fix the error. IfEnd_Error§A.13(12) occurs, the loop is exited.

54 begin 55 loop 56 declare 57 Source: Currencies; 58 Amount: Money; 59 begin 60 Put("Currency (");

61 for Cin Currenciesloop

62 Currency_IO.Put(C);

63 ifC /= Currencies’Last then Put(", "); end if;

64 end loop;

65 Put(")and amount: ");

66 Currency_IO.Get(Source);

67 Money_IO.Get(Amount);

68 Skip_Line;

69 Edit.Put(Amount, Money_Picture, BS.To_String(Signs(Source))); 70 Put_Line("is worth ");

71 for Targetin Currenciesloop

72 ifSource /= Target then

73 Edit.Put(

74 Get_Value(Amount, Source, Target),

75 Money_Picture, BS.To_String(Signs(Target))); 76 New_Line; 77 end if; 78 end loop; 79 New_Line; 80 exception 81 whenData_Error =>

82 Skip_Line; Put_Line("Illegal input");

83 whenEditing.Picture_Error | Constraint_Error =>

84 Put_Line("Amount too large");

2These localization features are not found in COBOL. Furthermore, COBOL does not have the’#’currency string, which allows a fixed-width currency field unlike’$’.

10.7 Fixed point types 173

85 whenEnd_Error =>exit;

86 end;

87 end loop;

88 endConvert;

Ordinary fixed point types

§3.5.9

8 The set of values of a fixed point type comprise the integral multiples of a number called the small of the type. For a type defined by an ordi- nary_fixed_point_definition (an ordinary fixed point type), the small may be specified by anattribute_definition_clause (see 13.3); if so specified, it shall be no greater than thedeltaof the type. If not specified, thesmallof an ordinary fixed point type is an implementation-defined power of two less than or equal to thedelta.

Ordinary fixed point types are similar to decimal fixed point types, except that their small can be any number. The small is usually a power of two so that values of the type can be exactly represented in binary. Ordinary fixed point types are extremely useful for programming embedded systems for two reasons: (a) small computers may not have floating point hardware, and (b) external peripherals transfer binary numbers that represent physical quantities.

The following program shows how a 16-bit word received from a sensor‡7can be easily converted to an ordinary fixed point value. The assumed representation is that the least significant bit repre- sents 1/16 of a degree of temperature‡10–12. First a fixed point typeTemperatureis declared, followed by representation attributes that specify that 16 bits should be used for objects of the type and that the least significant (binary) digit represent 1/16. After the conversion‡14–15,17, fixed point operators could be used for further computation, though we just print the value.

- - File: TEMP

1 - -

2 - - Hardware interface using ordinary fixed point types.

3 - -

4 withInterfaces; withUnchecked_Conversion;

5 withAda.Text_IO; use Ada.Text_IO;

6 procedure Tempis

7 Sensor: Interfaces.Integer_16 := 2#0_001_0001_0001_1100#;

8 - - 256 + 16 + 1 + 1/2 + 1/4 = 273.75

9

10 type Temperaturesis delta 2.0**(-4)range -2048.0..2048.0;

11 forTemperatures’Size use 16;

12 forTemperatures’Smalluse 2.0**(-4);

13

14 functionTo_Temp is newUnchecked_Conversion(

15 Source => Interfaces.Integer_16, Target => Temperatures);

16 begin

17 Put_Line(Temperatures’Image(To_Temp(Sensor)));