Every implementation of Modula-2, and of every computer language that is to be used in a scientific or academic environment, must also provide a number of standard mathematical functions. A name and contents of the module that contains these were suggested by Wirth--he called it *MathLib0*. However, in some versions, vendors called it either *MathLib* or *MathLib1*, and in a few the procedure names started with an uppercase letter. The ISO standard version is called *RealMath*. It makes available the two real constants:

CONSTpi = 3.1415926535897932384626433832795028841972; exp1 = 2.7182818284590452353602874713526624977572;

to as many decimal places as the implementation allows. In addition, the following sections detail the basic functions that are exported by *RealMath*, with their parameter lists, some comments and examples. (A few have been used before .)

PROCEDUREsqrt (x :REAL) :REAL;

This function procedure returns the square root of a positive real number. Naturally, there will be an error generated if one attempts to take the square root of a negative number.

Given two sides of a right triangle, compute the hypotenuse.

Ask the user for two numbers, the sides' lengths Read each into a real variable Compute the hypotenuse using Pythagoras' Theorem hyp = sqrt (a * a + b * b) Print out the result

*Variables:*

Two reals to hold the side lengths, one for the hypotenuse

*Imports*

WriteString, WriteLn, ReadReal, WriteReal, sqrt

MODULEPythagoras; (* Written by R.J. Sutcliffe *) (* using ISO Modula-2 *) (* to illustrate RealMath.sqrt *) (* last revision 1993 03 01 *)FROMSTextIOIMPORTWriteString, WriteLn, SkipLine, ReadChar;FROMSRealIOIMPORTReadReal, WriteFixed;FROMSIOResultIMPORTReadResult, ReadResults;FROMRealMathIMPORTsqrt;VARside1, side2, side3 :REAL; key :CHAR;PROCEDUREGetReal (VARnumToGet :REAL);VARtempResult : ReadResults;BEGINREPEATWriteString ("Please type in a real number ===> "); ReadReal (numToGet); tempResult := ReadResult (); SkipLine; (* swallow line marker *) WriteLn;UNTILtempResult = allRight;ENDGetReal;BEGIN(* main *) WriteString ("What is the first side length? "); WriteLn; GetReal (side1); WriteString ("What is the second side length? "); WriteLn; GetReal (side2); side3 := sqrt (side1 * side1 + side2 * side2); WriteString ("The hypotenuse is "); WriteFixed (side3, 2, 0); WriteString (" units long."); WriteLn; WriteString ("Press any key to continue"); ReadChar (key);ENDPythagoras.

What is the first side length? Please type in a real number ===> 20.0 What is the second side length? Please type in a real number ===> 21.0 The hypotenuse is 29.00 units long.

It was observed in section 4.9 that an amount *A* placed at compound interest *rate* for *time* years would grow to A(1 + rate)^{time}. Notice that if the interest is compounded *n* times a year, the amount will be higher than if it is compounded annually, even though the interest rate at each compounding period must be divided by *n*. For instance, the first example in that section found that $1000 at 6% compounded for 10 years would grow to 1790.85. If the interest is computed monthly, the rate at each application of interest is .06/12, or .005, and the number of applications becomes 10*12 or 120. Modifying the formula above yields A(1 + rate/n)^{n*time} and in this case the $1000 grows to $1819.40. If the compounding is done daily, the result is 1822.20, not much of a difference from monthly compounding. One might ask whether continuing to increase the number of compounding periods indefinitely would yield an indefinitely large (infinite) amount, or if there is some limit beyond which the amount will not grow.

The latter turns out to be the case. To see that this is so, consider a principal amount of $1.00 placed at 100% for a year, and increase the number of compounding periods indefinitely. In mathematical terms, this computes:

As the number of periods grows and the interest rate per period shrinks, this converges to a definite limit at about 2.7182818. (It has a non-repeating, non-terminating decimal representation.) This number, denoted *e* arises naturally in a variety of situations in mathematics, and mathematical libraries provide the exponential function to compute y = e^{x}. The inverse function, to compute the exponent, or logarithm of x given the number *y* is the logarithm function x = ln(y). These were mentioned in section 4.5 in connection with writing the function procedure *APowerB* and are found in *RealMath* as:

PROCEDUREexp (numb :REAL) :REAL;

and

PROCEDUREln (numb :REAL) :REAL;

In addition, *RealMath* exports the related function procedure:

PROCEDUREpower (base, exponent:REAL):REAL;

**NOTE**: Some non-standard mathematical library modules also export some or all of the following related function procedures:

For Base 10 Logarithms:

PROCEDURElog (numb :REAL) :REAL;PROCEDURETenToX (numb :REAL) :REAL;

For other power and magnitude operations:

PROCEDUREipower (numb1 :REAL; numb2 :INTEGER) :REAL; (* Both return numb1 to the numb2 power *)PROCEDUREMagnitude (numb :REAL) :INTEGER; (* returns the order of magnitude of numb, namely the largest integer less than or equal to the scale factor or log10 of numb *)

One application of the logarithmic and exponential functions is to compute radioactive (and other) decay processes. Under normal conditions, a quantity of radioactive material decays over time according to the formula

A = A_{0} e^{kt}

where A_{0} is the amount of the substance present at time zero, *A* is the amount at the time being examined, *t* is the elapsed time in appropriate units, and *k* is a constant that is a property of the substance.

In the standard literature, one often finds the constant *k* expressed indirectly as the half-life, that is, the time it would take for half of any given quantity of the substance to decay.

A lab is gathering data from experiments done on radioactive samples and determines experimentally the amount of a radioactive substance present at time zero and also at some subsequent time. Write a program to calculate the half-life of the substance from this data. (This is often one way of identifying an unknown radioactive material.)

The formula A = A_{0} e^{kt} may be rewritten as

and, upon taking natural logarithms on both sides and solving for k, one obtains

In the case where half of the material is supposed to have decayed, the right hand side of the latter formula becomes

or, solving for t,

With these variations on the initial formula, all the tools are at hand to write the code to do the computation.

MODULEHalfLife; (* Written by R.J. Sutcliffe *) (* using ISO Modula-2 *) (* to illustrate RealMath.ln *) (* last revision 1994 08 30 *)FROMSTextIOIMPORTWriteString, WriteLn, ReadChar, SkipLine;FROMSRealIOIMPORTReadReal, WriteFixed;FROMSIOResultIMPORTReadResult, ReadResults;FROMRealMathIMPORTln;PROCEDUREGetReal (VARnumToGet :REAL);VARtempResult : ReadResults;BEGINREPEATWriteString ("Please type in a real number ===> "); ReadReal (numToGet); tempResult := ReadResult (); SkipLine; (* swallow line marker *) WriteLn;UNTILtempResult = allRight;ENDGetReal;VARinitialAmount, laterAmount, timePassed, constant, halfLife :REAL; key:CHAR;BEGINWriteString ("What was the initial amount? "); GetReal (initialAmount); WriteString ("How much time elapsed til the second reading? "); GetReal (timePassed); WriteString ("And, how much material was left then? "); GetReal (laterAmount); constant := ln (laterAmount / initialAmount) / timePassed; halfLife := ln ( 0.5) / constant; WriteString ("The half life of this material is "); WriteFixed (halfLife, 6, 10); WriteLn; WriteString ("Press a key to continue ==>"); ReadChar (key);ENDHalfLife.

What was the initial amount? Please type in a real number ===>100.0How much time elapsed til the second reading? Please type in a real number ===>10.0And, how much material was left then? Please type in a real number ===>25.0The half life of this material is 5.000000 Press a key to continue ==>

Naturally, the units for the half life will be the same as those of the elapsed time given by the user.

Exponential growth works in much the same way, except that the constant k is positive instead of negative.

It is discovered in elementary geometry that in two similar triangles, the sides are in proportion.

In particular, for right triangles, one may relate these fixed ratios to a particular acute angle, such as angle *B* in figure 6.8. When this is done, and the right triangle labelled as in figure 6.9, the trigonometric ratios are defined as follows:

The symbols *sin*, *cos*, and *tan* are themselves abbreviations for *sine*, *cosine*, and *tangent*, respectively. Auxiliary to these three are their inverse functions *arcsin*, *arccos*, and *arctan* for producing an angle given one of the fixed ratios. Wirth suggested that *MathLib0* provide only three of these functions; the minimum necessary for work in trigonometry, but the ISO library *RealMath* supplies all six. They are:

PROCEDUREsin (x :REAL) :REAL;PROCEDUREcos (x :REAL) :REAL;PROCEDUREtan (x :REAL) :REAL;PROCEDUREarcsin (x :REAL) :REAL;PROCEDUREarccos (x :REAL) :REAL;PROCEDUREarctan (x :REAL) :REAL;

**NOTES**: 1. The first three require the angle to be in radians, and return the sine, cosine, and tangent, respectively, of the angle supplied. The last three takes the sine, cosine, and tangent of an angle and returns the principal value of the angle measure (in radians). For arcsine and arctangent, the values returned are in the range -/2 < ø < /2. For arccosine, the values returned are in the range 0 < ø < . (Recall that one radian is 180/ degrees.)

2. Many non-standard implementations are much less generous in their supply of trigonometric functions than this, and may omit as many as three of these.

3. While angles larger than 2 (about 6.28) will work correctly, specific implementations may have a maximum argument for trigonometric functions that is much smaller than MAX (REAL).

Here is another useful procedure:

PROCEDUREdegToRad (x :REAL) :REAL; (* converts degrees to radians *)BEGINRETURN(x * pi / 180.0);ENDdegToRad;

Basic trigonometric identities and formulas can be employed to extend the scope of the available mathematical functions.

Write a module that computes the area of any triangle given two adjacent sides and an included angle.

Consider the triangle ABC in figure 6.10 below. If the base *b* (here AC) and the altitude *h* (here BD) is known, the area of the triangle is given by

S = .5bh

However, since BD is the side opposite angle C, in the right triangle BCD, and sin (C) = BD/BC,

h = BC sin (C) = a sin (C).

That is, provided the given data consists of two sides *a* and *b* of the triangle and an included angle C, its area can be computed by using the formula

s = .5ab sin (C)

which reduces to the original formula when C is a right angle, because the sine of 90° is one.

MODULETriArea; (* Written by R.J. Sutcliffe *) (* using ISO Modula-2 *) (* to illustrate RealMath.sin *) (* last revision 1993 03 01 *)FROMSTextIOIMPORTWriteString, WriteLn, ReadChar, SkipLine;FROMSRealIOIMPORTReadReal, WriteFixed;FROMSIOResultIMPORTReadResult, ReadResults;FROMRealMathIMPORTsin, pi;PROCEDUREGetReal (VARnumToGet :REAL); (* prompts for a real number, reads it, loops until a correct one is typed, swallows the end-of-line state and returns the number read *)VARtempResult : ReadResults;BEGINREPEATWriteString ("Please type in a real number ===> "); ReadReal (numToGet); tempResult := ReadResult (); SkipLine; (* swallow line marker *) WriteLn;UNTILtempResult = allRight;ENDGetReal;PROCEDUREdegToRad (x :REAL) :REAL; (* converts degrees to radians *)BEGINRETURN(x * pi / 180.0);ENDdegToRad;VARangleC, sideA, sideB, area:REAL; key :CHAR;BEGIN(* main *) (* obtain triangle data *) WriteString ("What is the first side length? "); GetReal (sideA); WriteString ("What is the second side length? "); GetReal (sideB); WriteString ("Now, what is the included angle "); WriteString ("in degrees? "); GetReal (angleC); (* do calculation *) angleC := degToRad (angleC); area := 0.5 * sideA * sideB * sin (angleC); (* inform user of result *) WriteString ("The area is "); WriteFixed (area, 5, 0); WriteString (" square units "); WriteLn; WriteString ("Press a key to continue ==>"); ReadChar (key);ENDTriArea.

What is the first side length? Please type in a real number ===>10.0What is the second side length? Please type in a real number ===>8.0Now, what is the included angle in degrees? Please type in a real number ===>30.0The area is 20.00000 square units

What is the first side length? Please type in a real number ===>10.0What is the second side length? Please type in a real number ===>20.0Now, what is the included angle in degrees? Please type in a real number ===>90.0The area is 100.0000 square units

**NOTE**: Some nonstandard versions of the math library module use *atan* instead of *arctan* and may not export *asin*, or *acos*. Others provide the hyperbolic functions *sinh*, *cosh* and *tanh*.

*RealMath* also offers the useful conversion function:

PROCEDUREround (x:REAL):INTEGER;

which rounds off a real to the nearest integer.

Two function procedures that *may* be in the traditionally named *MathLib0* that are of more specialized interest are the following integer/real conversions.

PROCEDUREreal (m :INTEGER) :REAL;PROCEDUREentier (x :REAL) :INTEGER;

The first of these is essentially the same as FLOAT except that it only operates on the type INTEGER (and assignment compatible cardinals.) This is important in older versions of Modula-2 where FLOAT works only on CARDINAL (not on either one as in the ISO standard.)

The second one is sometimes called the greatest integer function. It takes a real argument, and returns the greatest integer less than or equal to the real. Note that this is not the same as TRUNC even in those versions where both can return integers. Compare the following:

entier (5.7) produces 5 and **TRUNC** (5.7) also produces 5, but

entier (-4.3) produces -5 while **TRUNC** (-4.3) yields -4

That is, for positive numbers, the result is the same, but for negative ones, it will be different, because in those cases entier gives the nearest integer less than the argument and TRUNC simply "hacks off" the decimal fractional portion. Notice that an order of magnitude function would be written using entier rather than TRUNC.

PROCEDUREMagnitude (num :REAL) :INTEGER; (* uses non-ISO functions *)BEGINRETURN(entier (ln (num) / ln (10.0) ))ENDMagnitude;

This procedure returns -6 when given 4.5E-6 and 2 when given 3.8E2, having computed the base ten logarithms as approximately -5.346 and 2.579 respectively. Notice that a base ten logarithm of a number (or one in any other base) is computed by dividing the natural logarithm of the number by the natural logarithm of the base, for if

x = log_{10}y then 10^{y} = x,

so that, taking natural logarithms on both sides yields

y ln(10) = ln (x)

and therefore

y = ln(10)/ln(x)

as used in the procedure.

DEFINITIONMODULERealMath;CONSTpi = 3.1415926535897932384626433832795028841972; exp1 = 2.7182818284590452353602874713526624977572;PROCEDUREsqrt (x:REAL):REAL;PROCEDUREexp (x:REAL):REAL;PROCEDUREln (x:REAL):REAL;PROCEDUREsin (x:REAL):REAL;PROCEDUREcos (x:REAL):REAL;PROCEDUREtan (x:REAL):REAL;PROCEDUREarcsin (x:REAL):REAL;PROCEDUREarccos (x:REAL):REAL;PROCEDUREarctan (x:REAL):REAL;PROCEDUREpower (base, exponent:REAL):REAL;PROCEDUREround (x:REAL):INTEGER;ENDRealMath.

A wide variety of other function procedures and error handling may be provided in some auxiliary modules associated with *RealMath*, or, in non-standard versions, added to *MathLib0*.

The ISO standard libraries, and some non-standard versions as well, include a second module that is identical to *RealMath* but that acts on and returns long types.

DEFINITIONMODULELongMath;CONSTpi = 3.1415926535897932384626433832795028841972; exp1 = 2.7182818284590452353602874713526624977572;PROCEDUREsqrt (x:LONGREAL):LONGREAL;PROCEDUREexp (x:LONGREAL):LONGREAL;PROCEDUREln (x:LONGREAL):LONGREAL;PROCEDUREsin (x:LONGREAL):LONGREAL;PROCEDUREcos (x:LONGREAL):LONGREAL;PROCEDUREtan (x:LONGREAL):LONGREAL;PROCEDUREarcsin (x:LONGREAL):LONGREAL;PROCEDUREarccos (x:LONGREAL):LONGREAL;PROCEDUREarctan (x:LONGREAL):LONGREAL;PROCEDUREpower (base, exponent:LONGREAL):LONGREAL;PROCEDUREround (x:LONGREAL):INTEGER;ENDLongMath.

This second module (along with the built-in type LONGREAL itself) are provided because many systems have two or more real types of different precisions. ISO Modula-2 defines the precision of LONGREAL to be equal to or greater than that of REAL. Thus, if there is only one underlying type in the actual system being used, the programmer may use either or both of the Modula-2 logical types to refer to this actual type. Both *RealMath* and *LongMath* also include an error enquiry function not listed here but the use of this will be postponed to a later chapter.

It should be noted that the name and the contents of both modules in non-standard versions, can vary widely from one implementation to another. For further information, see the Appendix on standard module definitions or consult the manuals that are available with the system.