next up previous
Next: Variable precisions Up: Expression evaluation with mixed Previous: Expression evaluation with mixed

Precisions from a fixed set

Here are some possible rules

(i)
If a and b are of different widths, say a wider than b, c := a + b is done by converting b to width a, and adding, then storing (perhaps narrowing or widening) to width of c.

(ii)
if a and b are of widths less than c, c := a + b is done by converting a and b to the width of c, adding, then storing in c.

(iii)
Regardless of the widths of a, b, and c, c := a + b is done by adding in the machine's widest format, then storing (perhaps narrowing) in c.

(iv)
Require everything that is not obvious to be explicit, e.g. something like
 storeasdouble
  (&c, doubleadd(coercetodouble(a),
       coercetodouble(b)))
(v)
Runtime untyped variables, but typed-value system. Variables like a, b, c have no types, but every number value has a type. Compute the appropriate type of each operation at runtime, as needed. This would have to be entirely by synthesized attribute (bottom up) since the names would not have types (though they might have previous values).

(vi)
Method dispatch deferred to runtime (fully ``dynamic object-oriented'' approach)

c := A+B is treated as

 assign(&c,
    add(a,b,type-of-a,type-of-b,type-of-c)
     ,type-of-c)

In this case the add function looks at all the types and chooses the right method, and the assign function looks at all the types as well. What is implemented depends entirely on how the functions (or ``methods'') for assign and add are defined, and also what the actual values of a and b are.

The old C rules were (iii). This is better than (i), but perhaps wasteful compared to (ii) which is hardly ever (never) done.

Rule (iv) has the advantage of allowing for the possibility that a low precision input to a function may in fact give a high accuracy answer. Log(1.0[+-.1]*10e600) is a low precision input, uncertain even in its 2nd decimal digit, but the answer is 1385.55+-0.09, correct to about 5 decimal places.

Rule (v) is usually available only in interpreted languages with a very loose or non-existent type system. If used to full generality, it is not efficient in time or space since numbers have to be tagged as to length (etc), and repeatedly checked.

Rule (vi) is very flexible and probably slower than one would like, unless the generality can be compiled away either in a pre-pass or a ``JIT'' system. [Another idea Java took from Lisp, by the way]

IS THERE A WAY TO DO THIS RIGHT? Figuring out the best width for preserving what appears to be the most reasonable precision intended by a computation may require from the compiler, two passes over an expression. This allows propagation upward and downward in an expression tree.

This is not an intolerable burden for a compiler, and in fact some languages (Ada) already require this kind of activity.

If methods are overloaded, there is a potential for additional scans to achieve method resolution.

By themselves, numbers possess neither precision nor accuracy. In context, a number can be less accurate or ( like integers ) more accurate than the precision of the format in which it is stored.... What matters in floating-point computation is how closely a web of mathematical relationships can be maintained in the face of roundoff, and whether that web connects the program's output strongly enough to its input no matter how far the web sags in between....
from ``Java Hurts'' (Kahan/Darcy)


next up previous
Next: Variable precisions Up: Expression evaluation with mixed Previous: Expression evaluation with mixed

Richard J. Fateman
Thu Aug 13 21:54:23 PDT 1998