Value object equality & floating-point values
Dan Smith
daniel.smith at oracle.com
Tue Feb 13 15:48:03 UTC 2024
[PSA that this discussion has ended up in the wrong mailing list, please be sure to send further replies to valhalla-spec-observers and remove amber-spec-observers.]
On Feb 12, 2024, at 6:54 PM, Joe Darcy <joe.darcy at oracle.com> wrote:
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><mailto: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/valhalla-spec-observers/attachments/20240213/8d5e2bc4/attachment.htm>
More information about the valhalla-spec-observers
mailing list