A proposal for RealJava
David Chase
chaseaworld.std.com
Sat Jul 5 12:48:10 PDT 1997
At 05:14 PM 7/4/97 -0800, Jerome T. Coonen wrote:
>A Proposal for RealJava
...
>Rounding modes
>--------------
>
>RealJava extends java.lang.Math to include methods to test and alter
>the rounding mode, as specified by the IEEE standard. The two
>methods get and set the rounding mode as an integer value, whose
>possibilities are given by the constants. The ROUNDMASK value permits
>a program to extract the rounding mode from an environment value or to
>insert one back in.
>
>The rounding modes apply to the floating point operations +, -, *, /,
>to specified conversion methods like roundedIntValue() and
>roundedLongValue(), and to methods like rint(), which rounds to an
>integral value within a floating format. Other mathematical methods
>will differ with respect to the extent to which they honor the IEEE
>rounding modes. Some methods deliver results rounded according to
>the mode in which they are called; others save the caller's mode and
>run rounding to nearest; still others simply run in whatever mode
>they're called. Check the documentation.
>
>The arrangement and values of the rounding mode bits are inspired by the
>most widely used architecture, iA.
>
> // Constants and methods in java.lang.Math
> public static final int TONEAREST = 0x00000000;
> public static final int UPWARD = 0x08000000;
> public static final int DOWNWARD = 0x04000000;
> public static final int TOWARDZERO = 0x0C000000;
> public static final int ROUNDMASK = 0x0C000000;
> public static int getRound();
> public static void setRound(int round);
>
>RealJava and IEEE 754
>=====================
>* The standard requires that results be rounded under program
> control. RealJava supports the four types of rounding, using
> a dynamic mode setting.
I'm not thrilled by this proposal, but I am least thrilled by
the way IEEE promotes dynamic control of rounding modes, and
how that dynamic control is reflected in this proposal. I've
never understood why anyone would want to use this feature; if
I write a piece of code in "Java", I don't want to have to worry
about what rounding modes might be in effect when someone decides
to call it. The possibility of 4 different rounding modes
complicates both proof (as if anyone proved anything correct
anymore, but we can pretend) and testing. True, those people
who care about reproducible behavior (aka "run anywhere") could
guard against this by always setting rounding modes to default,
but this means that extra work is required to get the sensible,
expected behavior, and that is wrong. (The proposal also lacks
a name for the default Java rounding mode -- there should be
something there with a name like JAVA_DEFAULT_ROUNDING).
Having the rounding modes exist as some sort of a dynamic flag
also adds expense to exception-handling (the same problem
occurs with setjmp/longjmp in C, I don't know if anyone bothers
to get this right); if I write:
try {
int x = JAVA_DEFAULT_ROUNDING;
setRound(x);
foo();
} catch (fooException x) {
// In my un-humble opinion, getRound() had better be equal to x,
// no matter what "foo" did.
}
If control of rounding modes is truly necessary, why not either (a)
make its control lexically scoped, and not dynamic or (b) simply
introduce a package loaded with static methods (that could be
inlined and/or specially expanded by a competent compiler) to
give the desired operations. For instance,
package IEEE754;
class Rtz {
public static double plus(double a, double b);
public static double minus(double a, double b);
...
}
and thus round-to-zero inner product might look like this:
import IEEE754.Rtz;
double innerProductRTZ(double[]x, double[]y) {
double sum = 0.0;
for (int i = 0; i < x.length; i++) {
sum = Rtz.plus(sum,Rtz.times(x[i],y[i]));
}
}
Certainly, this is what I would expect to see at the byte code level,
even if it looked more like rounding were a lexically scoped property
at the source language level. Use of lexical scoping would provide
a way around the icky syntax. Again, a competent compiler can simply
propagate around the rounding mode setting like any other optimizable
operation, and presumably (on a machine with rounding flags, like most
of them) set the flags before the loop began and reset them after it
was all done.
I'm also a little uneasy about the floating point "exceptions" -- why
not map them onto Java exceptions? They would not accumulate the way
that some people might like, but the behavior would be more Java-like,
and would still be usable:
double[] x, y;
for (int i=0; i<Math.max(x.length, y.length); i++) {
try {
x[i] = IEEE754.timesEX(x[i],y[i]);
} catch (Math.OverflowException x) {
x[i] = Double.MAX_VALUE / 128.0;
}
}
OR
double[] x, y;
try {
for (int i=0; i<Math.max(x.length, y.length); i++) {
x[i] = IEEE754.timesEX(x[i],y[i]);
} catch (Math.OverflowException x) {
// Do it more slowly here.
}
But basically, no, I do not like this proposal (that includes the parts
I did not comment on, fused operations and extended representations).
As an implementor, it only adds more work (I've still got to do all
that tricky slow stuff to get it right for Pure Java) and will only
fragment the market, and subvert write-once-run-anywhere.
Enquiring minds want to know:
what is wrong with C++?
what is wrong with Fortran?
why not just let Java be what it was intended to be?
There are other choices that probably have everything that you want
except for Java's bandwagon -- Modula-3, for instance, has garbage
collection, "objects", generics, better array support than Java,
and it has a generally available "standard interface" that provides
IEEE support pretty much like what was described in Jerome Coonen's
proposal.
David Chase
chaseaworld.std.com
More information about the Numeric-interest
mailing list