JDK-8303035 : Release Note: java.lang.Float.floatToFloat16 and java.lang.Float.float16ToFloat May Return Different NaN Results when Optimized by the JIT Compiler
  • Type: Sub-task
  • Component: hotspot
  • Sub-Component: compiler
  • Affected Version: 20
  • Priority: P4
  • Status: Resolved
  • Resolution: Delivered
  • Submitted: 2023-02-21
  • Updated: 2023-10-18
  • Resolved: 2023-02-24
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 20
20Resolved
Related Reports
Relates :  
Relates :  
Description
JDK 20 introduces two new methods which can be used to convert to and from the IEEE 754 binary16 format: `java.lang.Float.floatToFloat16` and `java.lang.Float.float16ToFloat`.

The new methods may return different NaN results when optimized by the JIT compiler. To disable the JIT compiler optimization of these methods, the following command line options can be used:

`-XX:+UnlockDiagnosticVMOptions -XX:DisableIntrinsic=_floatToFloat16,_float16ToFloat`

Comments
Good point, I removed the "quiet vs. signaling NaNs" part.
28-02-2023

It's not just the quiet vs. signaling NaN bit that can be different. The rest of the implementation-specific NaN bits (sometimes called "payload") can also be different.
27-02-2023

Looks good.
27-02-2023

Okay, thanks for the clarifications. You convinced me, I updated the title and description accordingly.
27-02-2023

If the problem only involves NaN inputs then the RN should state that. Otherwise this makes it sound like the JIT version is broken in all cases IMO.
26-02-2023

We have the same transition (I don't want to call it an "issue") with double to float conversion as Sandhya pointed: float sNaN = Float.intBitsToFloat(0x7fa00000); double res = (double)sNaN; float fRes = (float)res; double res2 = (double)fRes; sNaN: 7fa00000 / NaN res: 7ffc000000000000 / NaN fRes: 7fe00000 / NaN res2: 7ffc000000000000 / NaN
25-02-2023

My understanding is that everything > 0x7c00 is NaN (does not matter which). I did 2 roundtrips and it keep NaN for float. float sNaN = Float.intBitsToFloat(0x7fa00000); short res = Float.floatToFloat16(sNaN); float fRes = Float.float16ToFloat(res); short res2 = Float.floatToFloat16(fRes); System.out.println("sNaN: " + Integer.toHexString(Float.floatToRawIntBits(sNaN)) + " res: " + Integer.toHexString(res)); System.out.println("fRes: " + Integer.toHexString(Float.floatToRawIntBits(fRes)) + " / " + fRes + " res2: " + Integer.toHexString(res2)); Java implementation (no HW instructions) output: sNaN: 7fa00000 res: 7d00 fRes: 7fa00000 / NaN res2: 7d00 x64 HW instructions ouput: sNaN: 7fa00000 res: 7f00 fRes: 7fe00000 / NaN res2: 7f00
25-02-2023

> I think "different NaN results" is not correct because with `Float.floatToFloat16` it's about NaN *inputs* and the differing result is not a NaN [~thartmann] FTR, did you mean sNaN? My understanding is that we get a qNaN instead of sNaN, but all "different" values are still a kind of NaN.
25-02-2023

What I meant to say is that Float.floatToFloat16(sNaN) returns 0x7f00 which is neither sNaN = Float.intBitsToFloat(0x7fa00000) = 0x7d00 nor qNaN = Float.intBitsToFloat(0x7fc00000) = 0x7e00, right?
25-02-2023

I agree with current general description.
24-02-2023

Similar to old release note JDK-8177129, we could go into more detail about signalling vs. quiet NaNs and/or could be more precise by saying something like "The new methods may return different results when converting NaN values". But I think in this case, it's better to be more generic to prepare the user for surprises, especially when the results of these methods are used inside of a more complex computation.
24-02-2023

Yes, I think we should use "different results" instead of "incorrect results". I changed the description accordingly, added a missing comma and added `-XX:+UnlockDiagnosticVMOptions`. I think "different NaN results" is not correct because with `Float.floatToFloat16` it's about NaN *inputs* and the differing result is not a NaN. For example: static float sNaN = Float.intBitsToFloat(0x7fa00000); public static void main(String[] args) { for (int i = 0; i < 100_000; ++i) { short res = Float.floatToFloat16(sNaN); if (res != 0x7d00) { throw new RuntimeException("sNaN input returns inconsistent result 0x" + Integer.toHexString(res)); } } } Prints "sNaN input returns inconsistent result 0x7f00" once `Float.floatToFloat16` is intrinsified (run with `-XX:-TieredCompilation -Xbatch`).
24-02-2023

Yes, and may be more precise "different NaN results".
22-02-2023

If it turns out that this only happens with NaNs then it might be more correct to say "different results" instead of "incorrect results".
22-02-2023