Description
NaNs can behave in surprising ways. On top of that, a very common target is inherently buggy in more than one way. But on all other targets we actually follow fairly clear, if improperly documented, rules. See here for the current status.
Original issue
Several issues have been filed about surprising behavior of NaNs.
- Wrong signs on division producing NaN #55131, in which the sign of the result of
0.0 / 0.0
changed depending on whether the right-hand side came from a function argument or a literal. - i686 floating point behavior does not agree with unit tests in debug mode #73288/Some num tests fail for {i586, i686, x86_64}-unknown-linux-gnu #46948, in which the result of
f32::from_bits(x).to_bits()
was not always equal tox
.
The root cause of these issues is that LLVM does not guarantee that NaN payload bits are preserved. Empirically, this applies to the signaling/quiet bit as well as (surprisingly) the sign bit. At least one LLVM developer seems open to changing this, although doing so may not be easy.
Unless we are prepared to guarantee more, we should do a better job of documenting that, besides having all 1s in the exponent and a non-zero significand, the bitwise value of a NaN is unspecified and may change at any point during program execution. In particular, the from_bits
method on f32
and f64
types currently states:
This is currently identical to transmute::<u32, f32>(v) on all platforms.
and
this implementation favors preserving the exact bits. This means that any payloads encoded in NaNs will be preserved
These statements are misleading and should be changed.
We may also want to add documentation to {f32,f64}::NAN
to this effect, see #52897 (comment).
cc #10186?