Comments on "Proposal for Extension of Java(TM) Floating Point Semantics, Revision 1"

Joseph D. Darcy darcyacs.berkeley.edu
Mon Aug 17 23:43:57 PDT 1998


[David, let us know if you think this should be taken off
numeric-interest and go email-only.]

Hello.

> Lindholm on Darcy on PEJFPS

> > Darcy on PEJFPS

[predictability, performance, widefp, strictfp]

> Again, the attempt is to not lose predictability irrevocably, but to
> give the developer the choice of predictability or performance.  [I
> think we need a moratorium on use of the phrase "to give the developer
> a choice" in our industry.  You can no longer say it with a straight
> face...]

I don't think the choice has to be predictability xor performance.  As
described in my initial comments on PEJFPS, it is possible to address
the speed issue on the x86 and still keep the program largely
predictable.

There are other aspects of Java's semantics whose loosening could
allow greater levels of optimization.  For example, allowing imprecise
exceptions (and ignoring asynchronous exceptions) would make
optimization easier.  However, if such a change were made, it would be
very difficult to rely on or predict the values of variables modified
in a block that throws an exception.  (See Ada's complicated
description of what is allowed in this case.)  Having a semantics that
is simple to describe like "all exceptions are precise" allows the
programmer to more easily reason about the code while making life more
difficult for optimizing compiler writers.  This is probably the right
choice for Java given its goals and intentions.

[The VM can indicate extended precision is being used when it actually
isn't.]

> Yep.  However, I don't have a problem with that.  The proposal does not
> intend that people should think of wide code as guaranteeing more
> precision, just that it can be taken advantage of if that makes sense
> to the implementation.

If the various fields don't have to reflect what the VM actually does,
why bother having them?

As a minor implementation note, the expressions setting these
variables shouldn't be integer literals.  If the fields were assigned
using integer literals, the values of the fields could be
constant-propagated on the system that *compiled* a program instead of
the system that ran the program (the fields would be constant
expressions according to [JLS] section 15.27).

For example, let's say that in a particular VM these fields
(faithfully) indicated that double extended would be used.  A double
variable cannot overflow if 8 or fewer finite float values are
multiplied together.  A doubled extended variable cannot overflow if
fewer than 128 float variables are multiplied together.  Knowing that
double precision (or greater) will be used, a programmer might want to
block products of float array elements into groups that cannot
overflow so that overflow can be prevented by scaling.  For example,
consider the following code skeleton to compute the geometric mean:

static double geoMean(double A[])
{
  double product=1.0;	// product of elements of A
  int count=0;		// number of times exponent is adjusted up or down

// for expository purposes, assuming length of A is a multiple of
// Double.WIDEFP_MAX_EXPONENT/127; strip-mining code elided

  int i=0;
  while(i < a.length)
    {
      // multiply in groups guaranteed not to overflow
      for(j=0; j < Double.WIDEFP_MAX_EXPONENT/127; j++,i++)
        product *= a[i];

      // check current magnitude of product
      if(product near overflow)
        {
          count++;
          product *= 2^(-known_adjustment_factor);
        }
      else if(product near underflow)
        {
          count--;
          product *= 2^known_adjustment_factor;
        }
    }

  // calculate geometric mean taking exponent adjustment into account
  return ...;
}

If this code were compiled on a machine supporting double extended but
run on a machine supporting only double, the code would not have the
intended affect of preventing all overflows since
Double.WIDEFP_MAX_EXPONENT would be taken from the platform compiling
the program.

[in a widefp context, assigning a float to a double can overflow]

> I think you mean that float can be promoted to float-extended -- the
> float and double-extended formats are independent.  But your conclusion
> holds.

Both double and double extended meet the constraints of float
extended.  Under PEJFPS on the x86, it is likely that float (and
double) will be promoted to 80 bit double extended.

>  We didn't want to constrain things where IEEE 754 didn't force
> us to.

As pointed out previously, IEEE 754 also allows extended exponent
range when rounding to double or float precision.

>  We could further constrain the use of extended formats or the
> parameters defining permitted formats if there's a good reason to do
> that (suggestions?).

There are three IEEE 754 formats that have hardware support on desktop
processors, 32 bit float, 64 bit double, and 80 bit double extended.
On these processors, double usually serves as float extended (some
DSP's have a 40 bit float extended format that differs from double,
but Java is generally not targeting such processors).  To use C9X
terminology, on desktop processors I don't see much point in having
separate float_t and double_t types/formats.  There are several
possible expression evaluation polices to provide:

* strict evaluation:  Java's current policy

* "anonymous double": promote float and double operands to double,
pre-ANSI C semantics

* "anonymous indigenous": promote everything to the indigenous type,
the widest hardware format that runs fast on your processor

These are the options C9X can implement; there is no option "promote
float to double but promote double to double extended."

C9X also has width(float_t) <= width(double_t).  Why would someone
want to have float variables be wider than double variables?  I don't
see any reason someone would want float variables promoted to double
extended but double variables in the same expression kept as double.

If you are interested in providing higher-precision floating point
types in software (quad, oct etc.), the IEEE 854 standard discusses
useful relationships to preserve between a format and the format twice
as large.  For example, if one floating point format has p bits of
precision, if the next larger format has at least 2p+2 bits of
precision, an operation on p bit numbers can be done in 2p+2 bits and
then rounded back to p bits giving the same answer that would have
been gotten by directly operating on and returning p bit numbers.  In
other words, to support float (p=24), a processor only needs double
(p=53 > 2*24+2) operations and a way to round double to float.

[time-varying behavior from interpreting versus jitting a method]

> I think your point is correct although your wording is misleading.  This
> is not a question of alternating strict semantics with wide semantics.
> Rather, the code is wide, period, and when interpreting the implementation
> is not taking advantage of a double-extended format.  Wide code should
> expect this kind of thing.  Strict code is guaranteed never to see it.

Yes, the code is semantically always widefp but a valid implementation
of widefp amounts to strictfp.  Since the implementation of a method
can *vary over time*, effectively a widefp method may sometimes be
implemented using strictfp semantics and other times be implemented
using widefp-not-equal-to-strictfp semantics.

[double extended values can be spilled as double]

> Such rounding on spilling is permitted, and was requested by compiler
> writers.  Implementations are permitted to make and advertise stronger
> guarantees.

But if a Java program needs and relies on these stronger guarantees,
it is no longer portable even to a different VM on the same platform.

[p. 30 of PEJFPS allows flush to zero]

> Sorry, I don't understand the p. 30 reference, so I'm not sure I
> understand the point.

Page 30 of PEJFPS states in the "Notes for Implementors" section "In
particular, the Java programming language and virtual machine
currently require support of IEEE 754 denormalized floating-point
numbers and gradual underflow.  In the present proposal, these
properties continue to apply to FP-strict code but not FP-wide code."
Therefore, variables in widefp contexts don't have to represent
subnormals, meaning the presumably "wider" variables might actually be
allowed to hold fewer floating point values.  Presumably, subnormal
constants loaded from the constant pool would be flushed to zero.

> [Another way]
> 
> I don't necessarily have any problems with these proposals, but have to
> point out that there would be no way we could have introduced new types
> or expression evaluation policies into 1.2 in the time that was
> available.

Providing "anonymous double" only requires compiler changes; the JVM
is not affected.  It would be possible (but a little tricky to get all
the details right) to implement indigenous with Java compiler changes
and a class that was marked for aggressive inlining by the VM.

>  That means we'd be committed to leaving things as they
> were for an undefined time, or would have had to take a big performance
> hit on x86 to hold people to the spec.

New major releases of Java (version changes in the tenths place) seem
to be coming out about once a year.  I agree that Java' floating point
semantics should be changed, but I think it is a false choice to say
it must be either the current semantics or something like PEJFPS.

Java 1.0 floating point design is simple and coherent.  The original
Java floating point design has a number of good properties; such as
requiring correctly rounded binary <--> decimal conversion and
mandating IEEE 754 format numbers.  Other aspects of Java's floating
point design should be revised; such as allowing the x86 to run
reasonablely fast (at least some of the time) and providing access to
IEEE 754 sticky flags and rounding modes.

PEJFPS is less simple and less coherent than original Java.  Since its
inception, Java's credo has been "write once, run anywhere."  PEJFPS
removes any hope of predictability for non-strict code.  The main
problem with PEJFPS is that it cannot be undone.  If PEJFPS is added
to Java, for years and years to come Java programmers will have to
guard against compiler excesses that may or may not occur.  Worse,
code may work as intended on one compiler/VM but not work properly on
another even though both VMs follow the specification.  PEJFPS doesn't
give the programmer enough information about what the VM can and will
do.  Weren't Java's strictly defined semantics intended to prevent
this situation?

There are numerous proposals for adding some form of parameterized
types to Java.  Some of these proposals have been implemented and have
actual users (Pizza).  The recent language proposal GJ builds on
experience with Pizza and includes better backwards compatibility with
Java.  I assume such proposals have not yet been incorporated into
Java since Sun is taking a conservative approach to avoid adding
language features that may turn out to be costly later.  At least the
same level of reticence should be shown towards floating point.  Most
of the parametric polymorphism proposals can be desugared into Java
and/or JVM.  Therefore, strictly speaking Sun does not need to adopt
any of these proposals for these capabilities to be available to
Java/JVM programmers.  If a few changes were made to Java and JVM,
other languages (or Java dialects) wanting to fully support IEEE 754
floating point could also use JVM as a target.

There are also a number of proposals to change Java's floating point,
including Borneo and RealJava.  These proposals have somewhat
different design goals; one of Borneo's design goals is to maintain
upwards compatibility with Java.  Given Java's marketing, I'm very
surprised this goal was not paramount in PEJFPS.  C and Fortran
already have loosely defined floating point; Java is distinguished by
having strictly defined floating point.  Java's floating point
performance and semantics can be improved without sacrificing
predictability.

It is better to leave Java's floating point as it is than to implement
something like PEJFPS.

-Joe Darcy
darcyacs.berkeley.edu




More information about the Numeric-interest mailing list