Value object equality & floating-point values
Joseph D. Darcy
joe.darcy at oracle.com
Tue Feb 13 02:54:41 UTC 2024
On 2/12/2024 3:50 PM, Stephen Colebourne wrote:
> On Mon, 12 Feb 2024 at 21:16, Dan Smith<daniel.smith at oracle.com> wrote:
>> Stephen Colebourne suggested a normalization approach to floating-point field storage:
>>
>>>> * For each `float` or `double` field in a value class, the constructor
>>>> will generate normalization code
>>>> * The normalization is equivalent to `longBitsToDouble(doubleToLongBits(field))`
>>>> * Normalization also applies to java.lang.Float and java.lang.Double
>>>> * == is a Bitwise implementation, but behaves like Representational
>>>> for developers
>> The Oracle-internal discussion last spring covered similar ground. There are different ways to stack it, but what they have in common is an interest in eradicating NaN encoding variations as some sort of unwanted anomaly. I get that this is often the case (for the tiny fraction of programmers who ever encounter NaN in the first place). But let's not overlook the fact that, since 1.3, there's an API that explicitly supports these encodings and promises to preserve them (Double.doubleToRawLongBits and Double.longBitsToDouble). Note that Double is a value class that wraps a field of type 'double'. Flattening out NaN encoding differences in the wrapped field would break that API.
> This claim doesn't stand up to scrutiny I'm afraid.
>
> longBitsToDouble() says this:
> "Note that this method may not be able to return a double NaN with
> exactly same bit pattern as the long argument"
> https://docs.oracle.com/javase/8/docs/api/java/lang/Double.html#longBitsToDouble-long-
> The whole paragraph is a vital read for anyone following this thread.
See also the more recent added text discussing "Floating-point Equality,
Equivalence, and Comparison:"
https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/Double.html#equivalenceRelation
>
> To put it simply, the spec *already allows* normalization (for the
> very good reason that no Java developer should ever be exposed to
> different NaNs).
The origin of that paragraph stems from idiosyncrasies of 64-bit double
support on the x87 FPU -- tl;dr a format changing load/store instruction
rather than a move instruction had to be used to get values on and off
the floating-point stack. Fortunately, JEP 306: "Restore Always-Strict
Floating-Point Semantics" removed most such issues from a spec
perspective, which had not been a serious concern from an implementation
perspective for some time.
>
> I'm really serious about this topic - because the proposed solution is
> simply not appropriate for Java as a blue collar language.
So-called "NaN boxing" -- storing and extracting extra information from
NaN significands -- seems to be a more-common-than-rare implementation
technique for some language runtimes; it come up reasonably frequently
on Hacker News as one data point. I don't think it is necessary for the
Java SE specs or JDK implementation to go out of their way to support
NaN boxing, but I don't think it is necessary to prevent the technique
from being used either.
-Joe
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-spec-observers/attachments/20240212/81bf0573/attachment-0001.htm>
More information about the amber-spec-observers
mailing list