-
Notifications
You must be signed in to change notification settings - Fork 20
Add ((un)checked_)exact_div
methods for integer types
#337
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
Comments
For the const case, as in your example, it's best to do that assertion at compile time: const PAGE_SIZE: usize = 1 << 14;
const OS_PAGE_SIZE: usize = 1 << 12;
const _: () = {
assert!(PAGE_SIZE % OS_PAGE_SIZE == 0);
}; I recommend you provide a different example that shows how this method would be beneficial at runtime. |
The point is that constant definitions with static assertions (we use them in our code, but they are not relevant here) can be quite far away from operations which depend on the assert. The motivation for the proposed methods is to clearly express that we expect that two numbers divide without remainder without any additional clutter associated with Also, the second part of the example is for runtime values. |
In that case, you should provide a I missed the runtime example All that said, this seems pretty niche. Also for the name, I'm not a fan of |
Here's another alternative. If we had a std version of if let (quotient, 0) = whatever.div_rem(PAGE_SIZE) {
// divides evenly
} else {
// there was a remainder
} |
One usecase for this is a subproblem of Advent of Code 2024 day 13 (spoiler ahead). The problem overall deals with integer systems of equations, and it is interested in whether or not the solution values are integers. At the final step of my solver, it has integer equations of the form if b % a == 0 && d % c == 0 {
Some((b / a, d / c))
} else {
None
} With a function like b.checked_norem_div(a).zip(d.checked_norem_div(c)) Before finding this issue, the name that I thought of is |
The name that popped into my head was |
At first, I did think of |
*Except for |
We already have Footnotes
|
fn evenly_divide(n: u64, d: u64) -> Option<u64> {
(n % d == 0).then_some(n / d)
} |
Note that the Makes me wonder if it makes sense to have a safe (And I wonder if it's make sense to have at least the unsafe version take |
Unstable intrinsics are not a precedent for stable names by any means. They typically get added without much thought about the name. So, we can take it as one data point, but it's completely fine if the stable API has a different name -- this happens all the time. Sometimes we rename the intrinsic, many times we do not bother. |
I think |
I don't have any particular attachment to the |
(checked_)norem_div
methods for integer types((un)checked_)exact_div
methods for integer types
I just encountered a use case for this where a SIMD search returns a bit mask which always contains an even number of one bits. The bit count needs to be divided by 2, but this is always an exact division due to the way the mask is calculated. By using unsafe fn search64(keys: *const i64, search: i64) -> usize {
unsafe {
let search = _mm256_set1_epi64x(search);
let cmp = |offset: usize| {
let vec = _mm256_load_si256(keys.cast::<__m256i>().add(offset));
_mm256_cmpgt_epi64(search, vec)
};
let a = cmp(0);
let b = cmp(1);
let c = cmp(2);
let d = cmp(3);
let tmp1 = _mm256_blend_epi32(a, b, 0b01010101);
let tmp2 = _mm256_blend_epi32(c, d, 0b01010101);
let tmp3 = _mm256_packs_epi32(tmp1, tmp2);
let mask = _mm256_movemask_epi8(tmp3);
mask.count_ones() as usize / 2
}
} Regarding naming, I don't see much use in the panicking version of pub const fn exact_div(self, rhs: Self) -> Option<Self> { ... }
pub unsafe const fn exact_div_unchecked(self, rhs: Self) -> Self { ... } I've put the |
I disagree. As I wrote in the OP, there is a plenty of cases where we know that we divide without remainder and it would be a bug if this assumption is wrong for some reason. We would have to add a bunch of annoying |
I don't have a strong opinion on whether we should have a panicking version of this or not (although I do weakly think we should), but I do somewhat strongly feel that if we have an exact division method returning an Overall +1 on adding these. Seems like we can probably mark this as accepted and hash out the naming later. |
Maybe the panicking version should be called |
We discussed this in the libs-api meeting. We see value in both checked and unchecked versions of this. There were some concerns about the panicking This ACP can be closed once a tracking issue has been created. |
David: the optimization that it enables is that (The unsafe intrinsic version was originally added for slice iterators, so that the |
Tracking issue: rust-lang/rust#139911 |
On the other hand we have the |
Proposal
Problem statement
In some cases it desirable to get division result and ensure that the division has no remainder. For example, a function which works with memory mappings may accept size in bytes, but it requires that the size must be multiple of OS page size. Today we have to insert separate checks (e.g.
assert_eq!(size / OS_PAGE_SIZE, 0)
) somewhere near the division. It makes code less concise and not great at expressing intent.Motivating examples or use cases
In our code we have code which works with pages and accepts size in bytes. It requires that the size should be multiple of the page size. The size is provided in bytes for user convenience and because page size can depend on OS and constants.
So we have a bunch of code like this:
To simplify the code we can introduce a helper extension trait and implement it for necessary integer types, but we need to introduce the trait and import it every time the methods are used. Also in a multi-crate projects it becomes even more annoying. We either have to define the trait in each crate where it needed or introduce a whole separate crate for this small functionality.
Solution sketch
Introduce the following methods to all integers through
int_impl!
anduint_impl!
macros:For signed integer the conditions also include potential overflow when
MIN
is divided by-1
.Alternatives
Users may use explicit checks based on the remainder operator or custom traits as shown in the examples section. Arguably, the functionality is too small for a separate crate.
Links and related work
rust-lang/rust#116632
The text was updated successfully, but these errors were encountered: