in python
-1 % 200 ===> 199
but in rust
-1 % 200 ===> -1
???
and how can i get the same result with python?
in python
-1 % 200 ===> 199
but in rust
-1 % 200 ===> -1
???
and how can i get the same result with python?
It's possible to use rem_euclid
method of integer types (which computes least nonnegative remainder) to have the same behavior as in Python, for example:
(-1i32).rem_euclid(200)
Will provide 199 as an answer.
Python does provide math.remainder
which computes truncated remainder like %
operator in Rust does, however this particular function takes floating point numbers, and so won't work well with large integers.
I cannot answer to “why” cuz I’m not some kinda Python expert, but I can tell you “how”. You can use PyO3 with maturin
to build something like this:
use pyo3::prelude::*;
#[pyfunction]
fn rem(x: i32, y: i32) -> PyResult<i32> {
Ok(x % y)
}
#[pymodule]
fn remainder(_py: Python<'_>, m: &PyModule) -> PyResult<()> {
m.add_function(wrap_pyfunction!(rem, m)?)?;
Ok(())
}
then install your package / extract a pyd
and use it like this
from remainder import rem
print(f'{rem(-1, 200)}')
This probably is not the best way and maybe there are some mistakes in my examples, but I hope you got the point
thanks !
I did some research. Python’s %
is actually a modulo operator, while Rust’s %
is just a remainder. So, as @xfix said, you need rem_euclid
method.
There are three common variants of this:
Truncating division.
a / b
computes round_towards_0(a / b)
.
a % b
has the same sign as a
.
This is what Rust and C use.
Flooring division.
a / b
computes floor(a / b)
.
a % b
has the same sign as b
.
This is what Python uses.
Euclidean division.
a / b = round_down(a) / b
a % b
is always nonnegative.
This is what Rust uses with a.div_euclid(b)
, a.rem_euclid(b)
.
#3 has the nicest mathematical properties, #2 second-nicest, #1 is more-less unusable for negative numbers if you care about the remainder.
I think Rust just copied the #1 behavior from C. And C copied it from the hardware division instruction on many CPUs (idiv
). I think this is a design mistake, because:
idiv
is slow and fixing its output doesn't cost many cyclesidiv
doesn't have to be usedIf you divide by 200, both %
and rem_euclid
use imul
twice rather than idiv
, with rem_euclid
using a few additional instructions. godbolt
If you divide by 16, both use and
, with rem_euclid
using a few fewer instructions. The latter improved in Rust 1.65, probably thanks to this LLVM improvement.