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.
This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.