Why % works differently between rust and python

in python

-1 % 200  ===> 199 

but in rust

-1 % 200  ===> -1 


and how can i get the same result with python? :slight_smile:

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:


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::*;

fn rem(x: i32, y: i32) -> PyResult<i32> {
    Ok(x % y)

fn remainder(_py: Python<'_>, m: &PyModule) -> PyResult<()> {
    m.add_function(wrap_pyfunction!(rem, m)?)?;

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 :wink:

1 Like

thanks ! :slight_smile:

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:

  1. 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.

  2. Flooring division.
    a / b computes floor(a / b).
    a % b has the same sign as b.
    This is what Python uses.

  3. 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 cycles
  • often idiv doesn't have to be used

If 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.