Indeed. During the early explorations for this feature we got fooled by
values for which casting from T to U lost precision, but the
corresponding cast back from U to T was also imprecise, and so the
round-trip T -> U -> T preserved the input value. We scratched our
heads over this for a while.
On 11/16/2022 10:15 AM, Dan Heidinga wrote:
It's good to hear that you and others are thinking through the details
on how float/doubles will work.
I still have some concern with user-intuition when writing pattern
matching code over floating point values if users base their intuition
on their experience with widening casts to float. There's a great
sample program (JLS Example 5.1.2-1) which shows the loss of precision
when casting a large int to a float which I would try to express with
pattern matching roughly as:
record FloatBox(float f) {}
int big = 1234567890;
FloatBox box = new FloatBox(big);
if (box instanceof FloatBox(int i)) {
// pattern won't match here
}
I think users would be surprised reading the code that the pattern
doesn't match because converting back to an int would lose precession.
The equivalent non-pattern code would be pretty clear that it accepted
the loss of precession:
if (box instanceof FLoatBox) {
int i = (int)box.f();
....
}
Users will find it confusing when the pattern seems to match
"sometimes" though this is likely due to existing confusion related to
floating types. Maybe expanding on the expected implementation will
make it easier to build a mental model for when the match will succeed?
--Dan
On Tue, Nov 15, 2022 at 6:13 PM Joseph D. Darcy <[email protected]>
wrote:
On 11/15/2022 12:13 PM, Brian Goetz wrote:
>
>
> On 11/15/2022 2:55 PM, Dan Heidinga wrote:
>> Hi Angelos,
>>
>> The overall direction and writeup for this looks good to me. I
think
>> we need to be more specific about how doubles & floats fit into
this
>> though as they are perpetual source of special cases.
>
> Indeed, floating point is the gift that keeps on giving.
>
> Joe recently did some nice work in the spec of Float and Double,
> outlining the various different ways in which floats can be
compared.
> This allows language features like pattern matching, casting, and
> switch to appeal to "compared by FooBar comparison", rather than
> spelling it out for each use.
>
>
FYI, the new text in question is:
https://download.java.net/java/early_access/jdk20/docs/api/java.base/java/lang/Double.html#fpNumericalEq
<https://urldefense.com/v3/__https://download.java.net/java/early_access/jdk20/docs/api/java.base/java/lang/Double.html*fpNumericalEq__;Iw!!ACWV5N9M2RV99hQ!NLeYfZTwyKuJa79r6BKK7vCpK18EfV6UFYQATED31R-rgD9GThj4b5Apwa-MjRhTkfthC6sXdBLheOEVZLA$>
For the cases in the draft JEP, there have been separate discussions
working through the details. Putting aside how it might be
implemented,
for the
floating-point type -> integral type
cases, conceptually if the same real number can be presented in the
floating-point type and the integral type, then the conversion is
exact.
(While floating-point values are often thought of as "fuzzy," each
finite floating-point value represents some particular real number.
Finite binary floating-point values are sums of the powers of 2 where
the exponent difference of the powers is bounded by the significand
width of the floating-point format in question.) The main special
case
is how conversion of -0.0 to an integral type is defined for
purposes of
instanceof. The desired double -> float behavior can be inferred from
IEEE 754 concepts.
HTH,
-Joe