Feature suggestion: Add static equals methods to Float and Double

Hans Boehm hboehm at google.com
Tue Jan 8 18:55:59 UTC 2019

The IEEE standard does say that for quiet NaNs, the value (or one of them)
"should" be preserved by most operations on the quiet NaN. I have not heard
of implementations violating this for anything other than the "quiet" bit.
Thus I don't immediately see why it would be problematic to encode an
explicitly programmer-introduced error cause in the remaining bits (as
opposed to relying on hardware-generated patterns). I have not seen
non-testing code that does so, but I would be mildly surprised if it
doesn't exist somewhere.

On Tue, Jan 8, 2019 at 1:16 AM Ulf Adams <ulfjack at google.com> wrote:

> Technically, another option would be to have Java standardize a meaning,
> and I take it you're not mentioning that because of the performance
> implications?
> On Tue, Jan 8, 2019 at 2:37 AM John Rose <john.r.rose at oracle.com> wrote:
>> As I think you expect, isSubstitutible(x,y) will mean that x and y are
>> equivalent
>> for all practical purposes.  One hard question is nailing down what are
>> "all practical purposes".  Certainly it's unfair to flip a coin while
>> evaluating
>> x and y separately, and claim that a distinct outcome proves a difference.
>> What about viewing the bits of x and y using the Unsafe API?  That's
>> unfair also, since it opens the door to implementation-dependent behavior
>> which might detect a difference (an irrelevant difference) between x and
>> y.
>> Now, floatToRawIntBits can detect differences between NaNs which
>> have different numeric codes.  Are two such NaNs substitutable or not?
>> The evidence in favor:
>>  - They become equivalent when boxed in a Float, and Float claims to
>>   be an all-purpose box for float values.
>>  - The extra information produced by floatToRawIntBits is implementation
>>   specific, and in particular processor dependent.
>>  - Joe Darcy suggested to me that some processors, like x87, may
>>   perturb NaN bits (turning off the "signalling" bit, for example), even
>>   if the float value is simply bound to a parameter.  This means that
>>   the operand to floatToRawIntBits *might*, in compiled code, possibly
>>   have *some* of its bits perturbed.  (Thanks, Joe, for that and similar
>>   hair-raising stories.)
>>  - The previous point implies that compiled code and interpreted code
>>   might, in the same JVM instance, produce different results on the
>>   same argument.  That is quite implementation specific indeed!
>> The evidence against:
>>  - The existing standard API point floatToRawIntBits is not going away.
>>   So the isSubstitutable API point must document that floatToRawIntBits
>>   has the processor-dependent ability to conjure up different bits for
>>   x and y.  Maybe it should be called isAlmostSubstitutable??
>> The right trade-off here, I think, is to align isSubstitutable with
>> Float::equals
>> and simply increase the warnings on floatToRawIntBits, that this method
>> can produce platform-specific results in an unpredictable way, and that
>> in particular it can produce distinct answers for otherwise substitutable
>> results.
>> I also suggested to Dr. Deprecator (Stuart Marks) that floatToRawIntBits
>> might be a candidate for deprecation; he said it would be a lot of expense
>> for relatively little benefit.  I think at least the javadoc for
>> floatToRawIntBits
>> should not speak so confidently, as it does, of "preserving Not-a-Number
>> (NaN) values", as if these values were something that had a stable
>> semantics, as if they could somehow carry application information.
>> More background (thanks again to Joe):  The NaN bits don't have a standard
>> format.  Different CPUs can (and often do) disagree on which bits
>> mean what, and how standard arithmetic operations consume and produce
>> them.  There is apparently no agreed standard NaN pattern, although
>> Java favors the "all zero" bit pattern as normative.  Different CPUs
>> may disagree on which bits denote signaling or quiet NaNs, and when
>> such bits may be queried or modified.  Adding the possible distinct
>> treatment of the "same" NaN value in compiled vs. interpreted code
>> (as well as strictfp vs. non-strictfp code), and the use of "raw" NaN
>> bits seems a very risky proposition, useful only for people writing
>> processor-specific code, with great care.
>> In hindsight, I think it would have been nice to place the "raw bits"
>> API points to Unsafe or a separate module.  But when those API
>> points were designed (1.0), there were no such hiding places.
>> And it's probably too costly to fix now.  If the sweet spot is to
>> acknowledge the wart, but not let it spread, then we design the
>> substitutability test based on Float::equals, not floatToRawIntBits.
>> — John
>> On Jan 6, 2019, at 4:36 PM, Hans Boehm <hboehm at google.com> wrote:
>> >
>> > IIUC,  isSubstitutible() is not quite what's being proposed here. The
>> > proposed definition here uses floatToIntBits(), not floatToRawIntBits().
>> >
>> > Hans
>> >
>> > On Sun, Jan 6, 2019 at 3:59 PM Brian Goetz <brian.goetz at oracle.com>
>> wrote:
>> >
>> >> Followers of Project Valhalla will see that this issue comes up when
>> >> defining equality on value types.  The relation you are looking for is
>> >> being called "substitutible"; it asks whether there is any way to
>> >> distinguish between two values.  For primitives other than
>> float/double,
>> >> this coincides with `==`, and similarly for references.
>> >>
>> >> An `isSubstitutible()` API point will likely emerge from Valhalla.

More information about the core-libs-dev mailing list