-
Notifications
You must be signed in to change notification settings - Fork 13.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hell yeah
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not new code, I just moved it. ;)
library/core/src/num/f64.rs
Outdated
// 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// 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 |
library/core/src/num/f16.rs
Outdated
// 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are right, that is redundant - I don't think that was done with any specific intent.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sorry, only noticed this typo on this last scan.
eb5f421
to
368a4c6
Compare
Typo fixed :) |
huzzah! looks good. |
Ah! Good point. Okay, this should fix it then -- I just have it skip the problematic comparison on i586 targets. |
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Like this, or so
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.