raw floating-point bits in '==' value object comparisons (again/still)
Clement Cherlin
ccherlin at gmail.com
Mon Mar 11 15:27:30 UTC 2024
On Mon, Mar 11, 2024 at 8:34 AM Remi Forax <forax at univ-mlv.fr> wrote:
>
> Last week, I explain at JChateau (think JCrete in France, less sun, more chateaux) how value types work from the user POV, among other subject describing the semantics of ==.
>
> First, most of the attendee knew the semantics difference between == on double and Double.equals(). I suppose it's because people that attend to such (un-)conference have a more intimate knowledge of Java than an average developer. Second, no attendee knew that NaN was a prefix.
>
> So it let me think again on that subject.
>
> 1) The argument that of Dan that we want to be able to create a class with two different NaN, does not hold because instead of storing the values as double, the values can be stored as long.
>
> value class C {
> private double d;
> C(double d) { this.d = d; }
> long bits() { return Double.doubleToRawLongBits(d); }
> }
>
> C c1 = new C(Double.longBitsToDouble(0x7ff0000000000001L));
> C c2 = new C(Double.longBitsToDouble(0x7ff0000000000002L));
> assert c1.bits() != c2.bits();
>
> can be rewritten as
>
> value class C {
> private long l;
> C(double d) { this.l = Double.doubleToRawLongBits(d); }
> long bits() { return l; }
> }
>
>
> 2) The de-duplication of value instances by the GC works with both the bitwise equivalence and the representational equivalence.
>
> If the GC only de-duplicate the value instance based only on the bitwise equivalence, it is a valid algorithm under the representational equivalence.
>
>
> So I not convinced that the bitwise equivalence should be choosen instead of the representational equivalence, for me two semantics instead of three is a win.
>
> Rémi
Let's make nobody happy and define new operators for new semantics, à
la JavaScript:
Given double d1, d2;
d1 === d2 uses the algorithm implemented in Double.equals()
d1 ==== d2 uses the algorithm implemented in Double.equals() but with
doubleToRawLongBits instead of doubleToLongBits.
Same goes for floats. For float ===/==== double, the float is coerced
to double first, just as with == today.
These operators behave exactly the same as == for reference types
(except primitive wrappers, which they unbox first if both are
non-null) and non-floating-point primitive types, and apply their
respective definitions of equality recursively to the fields of value
types.
Alternatively, === is shorthand for Objects.equals() and we can all
stop using == for 99% of purposes (again, like JavaScript).
Cheers,
Clement Cherlin
More information about the valhalla-spec-observers
mailing list