float to/from bits and classify: update for float semantics RFC - #128598
Conversation
This comment has been minimized.
This comment has been minimized.
e79d748 to
55543a5
Compare
|
@rust-lang/wg-const-eval this also makes it so that to_bits / from_bits in const will expose the bit pattern of NaNs (and subnormals). That matches the accepted float semantics RFC: the exposed bit pattern is guaranteed to be some NaN bit pattern, but which exact bit pattern one gets is not fixed. (These functions are still unstable, though they could be stabilized soon.) |
|
Would you be able to update f16 and f128 too? If you run into anything too weird there then I can do it separately after this merges. ( |
|
I'll wait for a review before doing that so that I don't have to do the same edits 4 times. |
workingjubilee
left a comment
There was a problem hiding this comment.
cool, okay!
sorry for taking so long to review but I had to like... also go over the float rfc again with a fine-tooth comb.
|
|
||
| // Check that NaNs roundtrip their bits regardless of signalingness | ||
| // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits | ||
| // ...actually, let's just check that these break. :D |
There was a problem hiding this comment.
This is not new code, I just moved it. ;)
| // implementation. | ||
| // | ||
| // Unfortunately, there is hardware out there that does not correctly implement the IEEE | ||
| // float semantics Rust relies on: x87 uses a too large exponent, and some hardware flushes |
There was a problem hiding this comment.
| // float semantics Rust relies on: x87 uses a too large exponent, and some hardware flushes | |
| // float semantics Rust relies on: x87 uses a too-large exponent, and some hardware flushes |
1aed419 to
29232ca
Compare
|
I have done the same edits for f16 and f128, and also replaced the |
| // we are fine. | ||
| let b = self.to_bits(); | ||
| match (b & Self::MAN_MASK, b & Self::EXP_MASK) { | ||
| (0, Self::EXP_MASK) => FpCategory::Infinite, |
There was a problem hiding this comment.
@tgross35 f16 is somewhat odd here -- it checks for infinity above and then again with the bitwise check here. That's different from f32, which only checks it separately, and f64, which only checks it via the bits. Isn't this arm here dead code because we already checked is_infinite above?
There was a problem hiding this comment.
You are right, that is redundant - I don't think that was done with any specific intent.
There was a problem hiding this comment.
I will follow what f32 does then since it seems closest to f16.
Yeah same. :D |
This comment has been minimized.
This comment has been minimized.
29232ca to
b2664cf
Compare
This comment has been minimized.
This comment has been minimized.
b2664cf to
6df63ee
Compare
This comment has been minimized.
This comment has been minimized.
9339bdb to
eb5f421
Compare
workingjubilee
left a comment
There was a problem hiding this comment.
sorry, only noticed this typo on this last scan.
eb5f421 to
368a4c6
Compare
|
Typo fixed :) |
|
huzzah! looks good. |
852b9dd to
ec1cb80
Compare
|
@bors r=workingjubilee |
| const_assert!(f64::from_bits(MASKED_NAN1).to_bits(), MASKED_NAN1); | ||
| if !has_broken_floats() { | ||
| const_assert!(f64::from_bits(MASKED_NAN2).to_bits(), MASKED_NAN2); | ||
| } |
There was a problem hiding this comment.
| const_assert!(f64::from_bits(MASKED_NAN1).to_bits(), MASKED_NAN1); | |
| if !has_broken_floats() { | |
| const_assert!(f64::from_bits(MASKED_NAN2).to_bits(), MASKED_NAN2); | |
| } | |
| if !has_broken_floats() { | |
| const_assert!(f64::from_bits(MASKED_NAN1).to_bits(), MASKED_NAN1); | |
| } | |
| const_assert!(f64::from_bits(MASKED_NAN2).to_bits(), MASKED_NAN2); |
As f64 has an even number of explicit significand bits, MASKED_NAN1 will be the signalling NaN.
There was a problem hiding this comment.
let's rename these to SIGNALING_NAN and QUIET_NAN shall we?
I am aware of the mips differentiation, you can comment on "according to IEEE754-2008" if you like.
There was a problem hiding this comment.
The float semantics RFC states "Rust assumes that the quiet/signalling bit being set to 1 indicates a quiet NaN (QNaN), and a value of 0 indicates a signalling NaN (SNaN)." so it could also be "according to Rust's float semantics".
(As a side note, I don't think f{16,32,64,128}::NAN are explicitly documented as being quiet NaNs anywhere, although this has always been the case and is probably relied upon in practice. Now that the RFC has formally defined what Rust thinks a quiet NaN is, the documentation can probably be updated to guarantee that f{16,32,64,128}::NAN are quiet NaNs, although that's probably a task for a separate PR as it would technically make new stable guarantees.)
|
@bors r- per the above |
|
thank you ecstatic-morse for explicitly documenting this test is about preserving bits for simple casts even in the signaling/quieted cases, you just saved me from making a very bad suggestion. |
also fix typo in const-float-bits-conv
Co-authored-by: Jubilee <46493976+workingjubilee@users.noreply.github.com>
5811ab9 to
5f33085
Compare
|
@bors r=workingjubilee |
|
☀️ Test successful - checks-actions |
|
Finished benchmarking commit (426a60a): comparison URL. Overall result: ❌ regressions - no action needed@rustbot label: -perf-regression Instruction countThis is a highly reliable metric that was used to determine the overall result at the top of this comment.
Max RSS (memory usage)Results (primary -0.7%, secondary -2.3%)This is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.
CyclesResults (secondary 2.5%)This is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.
Binary sizeResults (primary 0.0%)This is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.
Bootstrap: 749.331s -> 750.684s (0.18%) |
With rust-lang/rfcs#3514 having been accepted, it is clear that hardware which e.g. flushes subnormal to zero is just non-conformant from a Rust perspective -- this is a hardware bug, or maybe an LLVM backend bug (where LLVM doesn't lower floating-point ops in a way that they have the standardized behavior). So update the comments here to make it clear that we don't have to do any of this, we're just being nice.
Also remove the subnormal/NaN checks from the (unstable) const-version of to/from-bits; they are not needed since we decided with the aforementioned RFC that it is okay to get a different result at const-time and at run-time.
r? @workingjubilee since I think you wrote many of the comments I am editing here.