With the general consensus that functions will be sufficient for now, the implementation becomes simpler and more minimal. I feel there’s really just one question left now, other than the bikeshedding. Other than that, this proposal should be fairly minimal (and it’s just a case of making sure the arithmetic is correct in all the edge cases).
1. General Division/Modulo functions
The primary question now is whether both flooring and Euclidean division/modulo are useful enough to warrant adding the functionality of both (as it will be simpler to devise a more flexible solution now than later, should it be decided useful later on).
Assuming this could be useful, my preference would be to add general division and modulo functions, implemented by each integer type, with an enum (in core::num) specifying the division mode:
pub enum DivisionMode {
Truncating,
Flooring,
Euclidean,
}
// Generalised division and modulo, to be implemented for all integer types
div_round(self, rhs: Self, mode: DivisionMode) -> Self
mod_round(self, rhs: Self, mode: DivisionMode) -> Self
These would then be implemented fairly simply in Rust, e.g.:
fn mod_round(self, rhs: Self, mode: DivisionMode) -> Self {
match mode {
DivisionMode::Truncating => self % rhs,
DivisionMode::Flooring => ((self % rhs) + rhs) % other,
DivisionMode::Euclidean => self.mod_round(rhs.abs(), DivisionMode::Flooring),
}
}
2. Single division/modulo functions
If it seems unlikely that both flooring modulo and Euclidean modulo would be useful independently, there’s little point in adding both. Unless there’s a good reason not to, I would lean towards flooring modulo which has the advantages that: (a) it requires one fewer (abs) operations; (b) can easily be used to implement Euclidean modulo if really needed.
There’s a slight annoyance here, as Rust names its operators inconsistently to other languages like Haskell. Rust’s truncating integer division is called div, as opposed to the more typical quot, so reusing this naming for flooring division and modulo could be confusing. I’d therefore suggest a more explicit naming scheme:
// Flooring division and modulo, to be implemented for all integer types
fn divf(self, rhs: Self) -> Self
fn modf(self, rhs: Self) -> Self
Other points
- Whichever method we go with, they’re probably going to need overflowing, checked and wrapping versions (leading to another 6 functions), as the edge cases are different to that of truncating division and remainder. However, this should probably be it: I can’t see any other places new functions or traits should need to be added.
- I don’t think sweating over the assembly generated for these functions is important at this stage — for the most part, the factor of 2 or less (https://stackoverflow.com/questions/4102423/efficiently-implementing-floored-euclidean-integer-division) is very unlikely to be important – in such cases, it is likely the remainder operator would suffice.
Personally, I think the Euclidean variants are probably unnecessary, and prefer the second option. Once I’ve heard the feedback you have, I’ll write up the RFC proper!