-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
Expose float from_bits and to_bits in libcore. #46931
Conversation
r? @bluss (rust_highfive has picked a reviewer for you, use r? to override) |
f7fbd0f
to
4a1a4a3
Compare
Not sure why I didn't do it back in #39271. You should probably copy over the tests from std as well as the docs. |
It makes sense to have these operations in core, but note that we currently don't have a good way to expose those to end users. The This PR shouldn't/doesn't have to address that, I'm just saying this will not really be usable by anyone except other code in the standard library. There are indeed places in core that could use these methods (float parsing, and probably formatting too), so I'm in favor of this change. |
@rkruppe thanks for explaining, probably that's why I didnt do it in my PR :). As this is for internal use only, the single line of docs that we have now is probably enough. |
Isn't the Long term I assume that the goal is to have multiple inherent impl blocks, so that Regardless, I'm going to proceed with this and replace the existing unions that are used with |
Nope: https://play.rust-lang.org/?gist=6b061936c1e1e0d872210e120f6d0ae3&version=stable |
0cbe181
to
80d5bbf
Compare
80d5bbf
to
a2cdeb5
Compare
@rkruppe I noticed! :( Regardless, it appears that these methods would be useful in |
@@ -363,8 +337,7 @@ pub fn next_float<T: RawFloat>(x: T) -> T { | |||
// too is exactly what we want! | |||
// Finally, f64::MAX + 1 = 7eff...f + 1 = 7ff0...0 = f64::INFINITY. | |||
Zero | Subnormal | Normal => { | |||
let bits: u64 = x.transmute(); | |||
T::from_bits(bits + 1) | |||
T::from_bits(x.to_bits() + T::Bits::from(1u8)) |
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 technically changes the overflow behaviour on release, but I don't think it should be a problem, as this function isn't expected to ever trigger the assert that was originally in from_bits
here.
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.
Yeah this can't overflow. If x was the all-ones bit pattern, it'd be a NaN and we wouldn't enter this branch.
src/libcore/num/mod.rs
Outdated
@@ -2872,6 +2872,10 @@ pub enum FpCategory { | |||
reason = "stable interface is via `impl f{32,64}` in later crates", | |||
issue = "32110")] | |||
pub trait Float: Sized { | |||
/// Type used by `to_bits` and `from_bits`. | |||
#[stable(feature = "core_float_bits", since = "1.24.0")] | |||
type Bits: ops::Add<Output = Self::Bits> + From<u8> + TryFrom<u64>; |
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.
These bounds are pretty arbitrary. I guess it's okay for an internal trait, but alternatively you could move them to RawFloat
(assuming that's the only place where they are needed).
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 made this work by duplicating the associated type in the RawFloat
trait.
To be clear -- they are not really offered as anything but doc(hidden) and unstable in libcore even with this PR, right? It seems we have no stable float methods with just libcore. |
Marking the methods as stable in the #![no_std]
#![crate_type="lib"]
pub fn foo() -> bool {
::core::num::Float::is_nan(0f32)
} |
Oh, right, that damn stability hole =/ Well, since this already applies to some existing methods, this PR doesn't really make it worse. |
ugh. It's very unfortunate that in no_std, |
I hope that we can reach the best kind of solution by providing inherent methods for f32, f64 in libcore (composable with the additional inherent methods in std) |
Happy new year from triage, @bluss! Will you be able to check this out sometime? |
Ping from triage, @bluss! It's been over 6 days since we've heard from you, maybe @rust-lang/libs could assign a new reviewer? |
} | ||
|
||
/// Construct a subnormal. A mantissa of 0 is allowed and constructs zero. | ||
pub fn encode_subnormal<T: RawFloat>(significand: u64) -> T { | ||
assert!(significand < T::MIN_SIG, "encode_subnormal: not actually subnormal"); | ||
// Encoded exponent is 0, the sign bit is 0, so we just have to reinterpret the bits. | ||
T::from_bits(significand) | ||
T::from_bits(significand.try_into().unwrap_or_else(|_| unreachable!())) |
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 seems to be a step back, isn't there a way to keep this using just from_bits? Do you know if it has any performance impact?
The assertion assert!(bits < u32::MAX as u64, "f32::from_bits: too many bits");
from the old code has been lost, but I suppose it is unreachable here.
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 wouldn't worry about performance impact, this is only called near the end of the slowest of slow paths. Edit: The other instance of this pattern, in encode_normal
above, is also called in the slightly-less-slow-path, Algorithm R, but that path is still really slow in absolute terms. So I stand by my assesment.
It's still ugly as hell but that ugliness will have to be somewhere unless all the dec2flt code is restructured to work with the Bits
associated type instead of u64 (which would probably not be pretty either). Maybe it could move into RawFloat::from_bits
? (But if so, it should gain a nicer panic message than unreachable
)
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'll try seeing what needs to be done to use Bits
instead of u64
here.
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.
That's probably far too big a refactor to be worthwhile for this PR.
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.
Moving the try_into
to from_bits
seems more fruitful.
@shepmaster sure, that seems like a good idea |
Review ping for @rust-lang/libs! Randomly reassigning to another team member due to #46931 (comment). r? @BurntSushi Also @clarcharr could you address @bluss's comment in #46931 (review)? |
@rfcbot fcp merge |
Team member @BurntSushi has proposed to merge this. The next step is review by the rest of the tagged teams: No concerns currently listed. Once these reviewers reach consensus, this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! See this document for info about what commands tagged team members can give me. |
🔔 This is now entering its final comment period, as per the review above. 🔔 |
1 similar comment
🔔 This is now entering its final comment period, as per the review above. 🔔 |
🔔 This is now entering its final comment period, as per the review above. 🔔 |
@bors: r+ |
📌 Commit 556fb02 has been approved by |
Expose float from_bits and to_bits in libcore. These methods have no dependencies on libm and thus should be offered in libcore.
☀️ Test successful - status-appveyor, status-travis |
Did this really land in 1.25.0? Because I still get a compiler error with that version:
Strangely I don't get warnings about conflicting keywords, which I got with older compilers (at least 1.22 and 1.23). |
These methods have no dependencies on libm and thus should be offered in libcore.