Skip to content

Commit 1650689

Browse files
authored
Add floating-point Euclidean division and modulo
1 parent cb8bf0a commit 1650689

File tree

1 file changed

+21
-3
lines changed

1 file changed

+21
-3
lines changed

text/0000-euclidean-modulo.md

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,14 @@ The behaviour of division and modulo, as implemented by Rust's (truncated) divis
2424
(-8 / 3, -8 % 3) // (-2, -2)
2525
((-8).div_euc(3), (-8).mod_euc(3)) // (-3, 1)
2626
```
27-
Euclidean division & modulo for integers will be achieved using the `div_euc` and `mod_euc` methods. The `%` operator has identical behaviour to `mod_euc` for unsigned integers. However, when using signed integers, you should be careful to consider the behaviour you want: often Euclidean modulo will be more appropriate.
27+
Euclidean division & modulo for integers and floating-point numbers will be achieved using the `div_euc` and `mod_euc` methods. The `%` operator has identical behaviour to `mod_euc` for unsigned integers. However, when using signed integers or floating-point numbers, you should be careful to consider the behaviour you want: often Euclidean modulo will be more appropriate.
2828

2929
# Reference-level explanation
3030
[reference-level-explanation]: #reference-level-explanation
3131

3232
It is important to have both division and modulo methods, as the two operations are intrinsically linked[[8]](https://en.wikipedia.org/wiki/Modulo_operation), though it is often the modulo operator that is specifically requested.
3333

34-
A complete implementation of Euclidean modulo would involve adding 8 methods to the integer primitives in `libcore/num/mod.rs`:
34+
A complete implementation of Euclidean modulo would involve adding 8 methods to the integer primitives in `libcore/num/mod.rs` and 2 methods to the floating-point primitives in `libcore/num` and `libstd`:
3535
```rust
3636
// Implemented for all numeric primitives.
3737
fn div_euc(self, rhs: Self) -> Self;
@@ -66,6 +66,24 @@ fn mod_euc(self, rhs: Self) -> Self {
6666
r
6767
}
6868
```
69+
And on `f64` (analagous to the `f32` implementation):
70+
```rust
71+
fn div_euc(self, rhs: f64) -> f64 {
72+
let q = (self / rhs).trunc();
73+
if self % rhs < 0.0 {
74+
return if rhs > 0.0 { q - 1.0 } else { q + 1.0 }
75+
}
76+
q
77+
}
78+
79+
fn mod_euc(self, rhs: f64) -> f64 {
80+
let r = self % rhs;
81+
if r < 0.0 {
82+
return if rhs > 0.0 { r + rhs } else { r - rhs }
83+
}
84+
r
85+
}
86+
```
6987

7088
The unsigned implementations of these methods are trivial.
7189
The `checked_*`, `overflowing_*` and `wrapping_*` methods would operate analogously to their non-Euclidean `*_div` and `*_rem` counterparts that already exist. The edge cases are identical.
@@ -91,4 +109,4 @@ This functionality could instead reside in a separate crate, such as `num` (floo
91109
# Unresolved questions
92110
[unresolved]: #unresolved-questions
93111

94-
- Is it worth implementing `div_euc` and `mod_euc` for floating-point numbers? While it makes sense for completeness, it may be too rare a use case to be worth extending the core library to include.
112+
None.

0 commit comments

Comments
 (0)