2.9 REAL Variables

It must be made clear at the outset that a REAL variable is no more "real" than an INTEGER, at least not in the sense that the latter is, say, a figment of the imagination. Mathematically, the integers can be regarded as a subset of the reals, though this is not true in Modula-2, because the two are different types.

A Modula-2 REAL number is one that is expressed as a series of significant figures including a decimal point, and optionally followed by a scale factor (power of ten).

Figure 2.10 illustrates this.

The notation used for REALs is the standard or scientific one, with a slight change to make it more computer readable. Consider the following representations:

	Decimal		Scientific		Modula-2

	2000		2.000 x 10^3	2.000E+03
	0.058		5.8 x 10^-2		5.8E-02
			6.023 x 10^-23	6.023E-23

NOTE: For such simple exponents as in the first two examples, the numbers may also be entered for a Modula-2 program as 2000. and 0.058 respectively. That is, the scale factor indicator and digits after the decimal may not be always necessary, but the decimal point is. Note that one may not substitute a lower case e for E when writing literals in a program.

2.9.1 Real Operations

The operations and their precedence are the same for REALs as for INTEGERs and CARDINALs, except that REM, MOD and DIV are not defined and REAL division is indicated only with the / (slash).

  firstReal := 5.0 / 3.0;		Answer:  1.66666
  secondReal := 7.5 + 1.1 * 2.0;	Answer:  9.7

To output these answers to the screen, the appropriate WriteReal statement is imported as usual. One must import it from SRealIO (In non ISO standard versions, the library may be called RealIO or RealInOut or these items may simply be included in InOut.) As in the previous statements of this type, a number following the REAL to be printed specifies the size of the field of blanks in which it is to be right justified.

The following module is typical of many that can be written to do conversions or other computations using a well-defined formula and having a simple output. As its only purpose is to demonstrate output of reals, and few other new concepts are present, no detailed plan is provided.

Example:

Write a module to convert a 14 degree Fahrenheit temperature to Celsius units.

MODULE ConvertToCelsius;
(* by R. Sutcliffe *)

FROM STextIO IMPORT
  WriteLn, WriteString, WriteChar;

FROM SRealIO IMPORT  (* note separate import statements *)
  WriteReal;

CONST
  Fahrenheit = 14.0;  (* this can be changed *)
  conversion = 32.0;  (* difference between zero points *)
  ratio = 5.0 / 9.0;  (* ratio between Celsius and Fahrenheit *)

VAR
  Celsius : REAL;

BEGIN
  Celsius := ratio * (Fahrenheit - conversion);
  WriteReal (Fahrenheit, 12);
  WriteChar ('F');
  WriteString (" degrees equals ");
  WriteReal (Celsius, 12);
  WriteChar ('C');
  WriteString (" degrees.");

END ConvertToCelsius.

The output from this program module is as follows:

14.0000000000F degrees equals -10.000000000C degrees.

NOTES: 1. The number of significant figures and the maximum size of the exponent allowed depends on the computer system being used. Here, twelve figures have been printed. A typical size range for many small computers is about 10-308 < real < 10308, and similarly for negative reals.

2. There are other ways to format real number output that will be considered later.

3. The type LONGREAL is also available, and this extends the above range considerably.

Example:

Write a module to compute the area and circumference of a circle from a given radius.

MODULE CircleAreaCirc;

FROM STextIO IMPORT
  WriteLn, WriteString;

FROM SRealIO IMPORT
  WriteReal;

FROM RealMath IMPORT
  pi;

CONST
  twopi = 2.0 * pi;  (* note the real constant expression *)

VAR
  area, circumference, radius : REAL;

BEGIN
  radius := 4.0;
  (* calculate area and circumference *)
  area := pi * radius * radius;
  circumference := twopi * radius;
  (* inform the user *)
  WriteString ("A circle of radius ");
  WriteReal (radius, 0); (* spaces provided in the string parts *)
  WriteString (" units has a circumference of ");
  WriteLn;
  WriteReal (circumference, 0);
  WriteString (" units");
  WriteString (" and an area of ");
  WriteReal (area, 0);
  WriteString (" square units.");
END CircleAreaCirc.

The output from this program module is as follows:

A circle of radius  4.0000000 units has a circumference of
 2.5132740E+1 units and an area of  5.0265480E+1 square units.

2.9.2 The Format of Real Output

Sometimes a programmer wishes to print out real numbers, say to represent things like wages and bank balances in decimal or fixed form. At other times, the preference is for scientific or floating point notation. At still other times, engineering notation (in which the powers of ten are always multiples of three) is desired.

   Fixed         Floating    Engineering
   21421.5     2.14215E+4     21.4215E+3

Sometimes the number of significant figure needs to be specified. At other times it is the number of figures after the decimal that is of importance. For instance, when printing money values such as $15.34, fixed notation with two decimal places is necessary.

In ISO standard Modula-2 the library SRealIO has three additional procedures besides WriteReal for writing out real numbers.

WriteFloat (real, sigFigs, width);

writes out the specified real in floating point form with leading spaces if required to make the total space taken equal to width characters. One leading space is used if the width is zero. (This is the same behaviour as the width parameter for WriteCard and WriteInt.) If the value of sigFigs is greater than zero, it specifies the number of significant figures in the result. If the user of this procedure specifies zero figures, the particular implementation is free to define the outcome, and the manuals will have to be consulted. A sign is written only for negative values, and the exponent part is only written if it is not zero. No decimal point is included if there are no figures after it to print. The code

  WriteFloat (pi, 4, 0);
  WriteLn;
  WriteFloat (1000.0 * pi, 4, 10);
  WriteLn;
  WriteFloat (10000.0 * pi, 6, 10);
  WriteLn;
  WriteFloat (pi/10000.0, 2, 10);

produces the output

 3.142
 3.142E+03
3.14159E+04
   3.1E-04
WriteEng  (real, sigFigs, width);

writes out the specified real in engineering form (exponents are multiples of three) with leading spaces if required to make the total space taken equal to width characters. The rest of the behaviour of WriteEng is the same as that of WriteFloat. The code

  WriteEng (pi, 4, 0);
  WriteLn;
  WriteEng (1000.0 * pi, 4, 10);
  WriteLn;
  WriteEng (10000.0 * pi, 6, 10);
  WriteLn;
  WriteEng (pi/10000.0, 2, 10);

produces the output

  3.142
 3.142E+3
31.4159E+3
   310E-6
WriteFixed (real, place, width);

writes out the specified real in fixed point form (ordinary decimal form) and rounded off to place figures after the decimal, with leading spaces if required to make the total space taken equal to width characters. The rest of the behaviour of WriteFixed is the same as that of WriteFloat. The code

  WriteFixed (pi, 4, 0);
  WriteLn;
  WriteFixed (1000.0 * pi, 4, 10);
  WriteLn;
  WriteFixed (10000.0 * pi, 6, 10);
  WriteLn;
  WriteFixed (pi/10000.0, 2, 10);

produces the output

 3.1416
 3141.5930
31415.930000
      0.00

Notice that the last number is zero to three figures, so that is all that gets written.

Returning to the idea of printing currency values, the code

  WriteChar("$");
  WriteFixed(pi,2,5)

produces the output

 $ 3.14

with one space before the leading digit because four of the five spaces are occupied.

WriteReal (real, width);

behaves like a call to WriteFixed (real, place, width); if the number can fit in the width provided. The value of place is chosen to exactly fill the remaining field. If the width is insufficient, the call to WriteReal behaves like one to WriteFloat (real, sigFigs, width); with a value of sigFigs at least one, limited to those that can be included in the given width along with the exponent and sign. The code

  WriteReal (pi, 0);
  WriteLn;
  WriteReal (1000.0 * pi, 10);
  WriteLn;
  WriteReal (10000.0 * pi, 10);
  WriteLn;
  WriteReal (pi/10000.0, 10);

produces the output

3.1415927
3141.59270
31415.9270
3.1415E-04

This matter presented somewhat of a difficulty for early implementors of Modula-2, because no such flexibility was defined or even suggested by Wirth as part of the standard operating environment. Indeed, in some Modula-2 implementations, it may not be possible to achieve the goal of formatting reals in these ways without doing some very hard programming work.

In fact,non-ISO standard compliant versions of Modula-2 may provide something like:

WriteReal (real, width, n);

where real represents the value to be written, and the second number is the width of the space to write in as before. The meaning of the third number, in such versions may be either the number of significant figures of the real to print, or the number of decimal places of the real to print. The library location of the alternate WriteReal may vary in such versions. Moreover, some non-standard versions of WriteReal switch to scientific notation whenever a negative sign is placed in front of the third supplied number. Observe that the usual ordering of the second and third numbers in non-ISO versions is often the opposite to that in ISO standard packages.

NOTES: 1. The user documentation for the compiler package of a non-ISO standard implementation must be checked carefully to determine which version of the WriteReal procedure has been provided, and in what library it is located.

2. Where more than one WriteReal is available, a specific implementation may even give them different names and/or place them in different libraries.


Contents