-
Notifications
You must be signed in to change notification settings - Fork 19
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
Add saturating_shl
and saturating_shr
for ints
#230
Comments
We discussed this in the libs-api meeting last week and we are open to adding these functions but there were concerns about the lack of a clear motivating example for how these functions could be used. There were also concerns that the exact semantics of saturating shifts aren't clear. With that said, I've spent some time thinking over this and there's only one reasonable definition of a saturating operation: it involves performing the operation with infinite precision and then saturating the result to fit into the destination type. In the case of |
We discussed this in the libs-api meeting today but did not come to a consensus. Some clear use case examples would help. |
Hi, thanks for looking into it. The reason for this proposal is to get the Personally, I only have use cases for the simple arithmetic operations like addition, subtraction and multiplication. |
I don't think feature parity is a prerequisite for stabilization. Methods could be added later if someone actually needs them. |
The main issue with saturating shifts is that it's not clear whether the result is saturated ( |
Add an outsider, it's pretty intuitive to me that any "saturating" operation applies to the result, not the operands. |
Do you also think that about checked/overflowing/wrapping shifts? Because all of those apply to the shift amount, not the result. Yes, that's often confusing, but that's what we have nonetheless. |
I see. That's a very good point then. On the one hand, people will often expect the following to be equal: foo.saturating_mul(2)
foo.saturating_shl(1) But people will also expect I suppose the reason that |
I personally think it's more useful for This is one of those cases where the Keep in mind that even
(Did Euclid happen to discuss ring arithmetic shifts, so we can justify calling the "mathematically useful" version
Footnotes
|
I think the current definitions of shifts were a mistake, in retrospect. Picking the "this is efficient on x86" definition over the "this makes sense" definition is usually not what Rust does for the default. But Drastic idea: What if we did an edition change? We could add new Or just add |
that's not what's generally accepted to be wrapping-result. rotate is basically never a substitute for shifting. wrapping generally means the value is computed to infinite precision and then reduced mod
this is wrong because:
there is, it's the definition i gave for wrapping result |
The implementation in stdlib has been removed as part of stabilizing rust-lang/rust#87920. Support for saturating shifts will be added back once rust-lang/libs-team#230 is fixed.
The current "wrapping" shift behavior is unintuitive. Every other wrapping or saturating operator applies to the result rather than the inputs, which is important for modular arithmetic. Shift is the only one that applies the rules to the inputs. Personally, I'd expect either Ultimately, Also like division, there's also So a full wrapping euclidean div_mod of x by 2^y would be fn shift_mask(x: i32, y: i32) -> (i32, i32) {
match y {
..=-32 => (0, 0),
-31..=-1 => (x << -y, 0),
0 => (x, 0),
1..=31 => (x >> y, x & (1 << y).wrapping_sub(1)),
32.. => (x >> 31, x),
}
} Without including versions that return a wider type than the inputs, this seems to be the most mathematically useful form of shifting, but also seems to be fairly slow. Unless the efficiency was a deal-breaker, the behavior of the two halves of this function would be useful to have available, either in bi-directional form with a signed shift or in uni-directional form with an unsigned shift. [EDIT] While phrased in mathematical language, these functions are particularly useful extracting signed bitfields, with the bidirectional one being for when the bitfields can have variable length. |
We took another run at this 🚴 bikeshed in today's libs-api meeting, and the existence of |
Proposal
Problem statement
There is
wrapping_shr
andwrapping_shl
a well asoverflowing_shr
andoveflowing_shl
but nosaturating_shl
andsaturating_shr
.So on the one hand, this is for completion purposes. But I also think this should be implemented before the
Saturating
type is stabilized ... if the effort is reasonable.Motivating examples or use cases
I am working on this mostly to get a
Saturating
type stabilized with more or less feature parity to theWrapping
type.Solution sketch
Will reopen rust-lang/rust#103441
Alternatives
Doing nothing and stabilize the
Saturating
type withoutsaturating_shl
/saturating_shr
.Links and related work
wrapping_shr
wrapping_shl
overflowing_shr
oveflowing_shl
What happens now?
This issue is part of the libs-api team API change proposal process. Once this issue is filed the libs-api team will review open proposals as capability becomes available. Current response times do not have a clear estimate, but may be up to several months.
Possible responses
The libs team may respond in various different ways. First, the team will consider the problem (this doesn't require any concrete solution or alternatives to have been proposed):
Second, if there's a concrete solution:
The text was updated successfully, but these errors were encountered: