#### More Attributes

Ada provides many attributes, all described in Annex K of the Ada 95 RM. The most important ones that we haven't yet discussed are these:

For any real type or subtype (floating or fixed), **'Small** and
**'Large** are the smallest and largest positive model numbers. Thus
**Float'Small** is the difference between zero and the next larger number in
type Float. Also, for any floating point (sub)type, **'Model_Epsilon**
is the difference between one and the next larger number. (In Ada 83,
**'Model_Epsilon** is simply called **'Epsilon**.) We'll use
**'Epsilon** in an Ada 83 generic function in a moment.

For a floating point (sub)type, **'Digits** returns the value given for
**digits** in the declaration, and for a fixed point (sub)type, **'Delta**
returns the value given for **delta** in the declaration. These
attributes may not seem too useful, because the programmer already knows what
he or she wrote in the declarations. However, they're useful in generic
packages and subprograms. For example, if the generic part says **type
Dummy is delta <>;**, the body can use **Dummy'Delta**.

Ada 95 has **'Max** and **'Min**, both of which take two scalar
parameters. For example, if we have **I : Integer := 1;** and
**J : Integer := 2;**, then **Integer'Max(I, J)** is 2.

For any discrete (sub)type, **'Width** gives the maximum length that the
attribute **'Image** can produce. **Boolean'Width** is 5 because
“False” has length 5. With our earlier definition of
Rainbow_Color, **Rainbow_Color'Width** is 6. For versions of Ada using
16-bit Integers, **Integer'Width** is also 6, the length of
&lduqo;-32768”.

**'Count** is used with the name of a task entry. It returns the
number of calls presently queued on the entry. **'Terminated** is of
type Boolean. It's used with a task name, and tells if the task is
terminated.

Ada 95 has a package Ada.Numerics.Generic_Elementary_Functions containing a square root (Sqrt) function, but Ada 83 doesn't have this package. As an exercise, let's write a generic Ada 83 function to compute the square root for any floating point type, using Newton-Raphson iteration.

Let's suppose that G is our guess of the square root of X. If our guess is correct, then X/G equals G. If our guess is too low, then X/G is larger than G, and if our guess is too high, then X/G is smaller than G. The Newton- -Raphson method simply says that our next guess is the average of G and X/G (one of which is too high, and the other of which is too low). For example, if we want to compute the square root of 9.0 and our first guess is 9.0, successive guesses are 5.0, 3.4, 3.02352941, 3.00009155, 3.00000000. Note that convergence is very rapid.

However, the problem in writing a program like this is knowing when to stop
the iteration. We'll use the Ada 83 attribute **'Epsilon** (called
**'Model_Epsilon** in Ada 95). Since G*G/X should be 1.0, we'll quit
when the absolute value of the difference between G*G/X and 1.0 is less than or
equal to 3.0 times Epsilon. Recall that **Dummy'Epsilon** is the
difference between 1.0 and the next higher number for type Dummy. If we
use 1.0 times Epsilon, the loop might never terminate, and if we use 10.0 times
Epsilon, we might not get full precision. So we'll use 3.0 times
Epsilon. Here's our function:

generic type Dummy is digits <>; function Sqrt(X :in Dummy) return Dummy; function Sqrt(X :in Dummy) return Dummy is Guess : Dummy := X; begin if X < 0.0 then raise Constraint_Error; end if; while X /= 0.0 and then abs(Guess*Guess/X - 1.0) > 3.0*Dummy'Epsilon loop Guess := (X/Guess + Guess) * 0.5; end loop; return Guess; end Sqrt;

We tested our Sqrt with an implementation of Ada 83 having types Float, Long_Float, and Long_Long_Float. The last gives at least 33 decimal digits of precision. Sqrt was instantiated for all three floating point types, as was Float_IO to display the results. When tested with the three types, all displayed digits of the answers were correct.

## No comments:

Post a Comment