Java Numerics

Guy Steele - Sun Microsystems Labs glsalivia.East.Sun.COM
Thu Feb 13 10:59:33 PST 1997


   From jeromeabe.com Thu Feb 13 13:02:35 1997
   From: Jerome Coonen <jeromeabe.com>
   ...

Thanks for the commentary on Hough's remarks.
 
   IEEE 754 Exceptions
   
   We agree that some testing mechanism should be provided.  Bill Joy responded
   to Hough's comments with support for "well bracketed" exception handling in
   the form of try blocks:
   
    >> try enabling FloatingPointOverflow {
    >>     // code where overflow enabled
    >> } catch {
    >>     ...
    >> }

There are, of course, other linguistic possibilities that could be explored.
For example, a facility could be provided in expression form rather than,
or in addition to, statement form, which might be less unwieldy for
handling small regions of text.  An example off the top of my head:

	x = (y/z ifzerodivide 1.0);

We should also not overlook the possibility of providing a way to
deliver overflowed and underflowed results to a trap handler.

   The suggestion is that, in the event the exception arose, an unspecified amount
   of the try block would be excuted, but the catch block's execution would be
   guaranteed.  Hough points out
   
    >> There would be discernible differences in implementations that
    >> examined side effects produced by basic blocks whose partial execution
    >> was interrupted by an exception, but such programs could be deemed
    >> illegal Java.
   
   While good programming practice would dictate against dependence on the
   results of a partially executed block, results may differ, whether legally
   or not.  Might this not lead to exactly the kind of bit-checking between
   platforms Java's designers wish to avoid?

Indeed, and I would argue strongly against such uncertainty within Java.
Such uncertainty is sometimes desirable at the hardware level, principally
to allow the possibility of exploiting parallelism (such as pipelining)!
But it is possible to exploit such techniques at the low level without
having to reflect them at the high level.  The DEC Alpha architecture
provides one example of how this can be done.

   On a smaller scale, Bill Joy proposes that the exceptions be
   
    >> enabled only in the code that is marked as enabled, e.g. not in the
    >> methods called by this try statement.
    
   This would seem to incur a high implementation cost because of the need
   to isolate the flags (static sticky bits, or possibly static trap enable
   bits, on most current processors) across calls.  It also leads one to
   wonder whether the programmer who wrote a statement like
   
   z = x * exp(y);
   
   would care whether an overflow arose in the exponential (masked by Bill
   Joy's scheme) or in the product?

We should further distinguish between "arose in the source of the
code that implements the exponential" and "ought to be indicated to
the caller as part of the result of the exponential".  Ordinarily,
for reasons of abstraction, I would argue that a programming language
ought to be able to support delivering flag results to the caller
in a manner that is under programmer control, while making it easy
to hide details of implementation from the caller.  (If other behaviors
that violate such abstraction are nevertheless useful to the programmer,
then I am all for providing those behaviors also---but under programmer
control, not at the implementation-dependent whim of the compiler.)

By abstraction I mean the facility to encapsulate a compound behavior
so as to make it appear to be primitive.  Procedures are one such facility.
So I would be inclined to define the semantics of a procedure call
in such a way that any IEEE flags it returns are merged (OR'd) with the
flag state as of before the procedure call, and this merged state is
what is returned to the caller for use in its further execution.
In this way a user-defined exp procedure would behave in the same manner
with respect to the flags as a hardware-defined sqrt instruction.

I note that many numerical library routines I have seen use such roundabout
idioms as

	return 1/0;	/* overflow */

usually with a comment such as the one shown, to return +Infinity and
also set the overflow flag.  This may or may not be the fastest way
to accomplish this dual action at the machine instruction level, but
the fact that such a comment is usually included indicates that the
idiom is, by itself, linguistically deficient.  It might well be clearer
to be able to write something like

	return Infinity with overflow;

and leave it to the compiler to decide the most effective sequence
of machine instructions to produce this effect.  Similarly,

	return 0.0 with underflow;

may be more pleasant in a number of ways than

	double tiny = 1e-300;
	...
	return tiny*tiny;	/* underflow */

I hope that part of tomorrow's discussion can be devoted to the questions of
(a) what coders of numerical software need to be able to say in expressing
computations, and (b) what are clear and effective ways of saying those things.

A question of special interest for me is whether traps, especially traps that
"stop on a dime", are important for the expression of algorithms as such or whether
their principal use is in suspending a computation for inspection (debugging).

--Guy



More information about the Numeric-interest mailing list