29

In Python and Ruby, signed integer division truncates towards negative infinity, and signed integer modulus has the same sign the second operand:

>>> (-41) / 3
-14
>>> (-41) % 3
1

However, in C and Java, signed integer division truncates towards 0, and signed integer modulus has the same sign as the first operand:

printf("%d\n", (-41) / 3); /* prints "-13" */
printf("%d\n", (-41) % 3); /* prints "-2" */

What is the simplest and most efficient way in C to perform the same kind of division and modulus as in Python and Ruby?

user102008
  • 30,736
  • 10
  • 83
  • 104

6 Answers6

11

The direction for rounding with signed integer division is not specified in older C standards. However, in C99 it is specified to round towards zero.

Here's portable code which works with all versions of the C standards and CPU architectures:

int py_div(int a, int b)
{
  if (a < 0)
    if (b < 0)
      return -a / -b;
    else
      return -(-a / b) - (-a % b != 0 ? 1 : 0);
  else if (b < 0)
      return -(a / -b) - (a % -b != 0 ? 1 : 0);
    else
      return a / b;
}

int py_mod(int a, int b)
{
  if (a < 0)
    if (b < 0)
      return -(-a % -b);
    else
      return -a % b - (-a % -b != 0 ? 1 : 0);
  else if (b < 0)
      return -(a % -b) + (-a % -b != 0 ? 1 : 0);
    else
      return a % b;
}

I did some superficial tests and it appears to give the same results as Python. This code may not be maximally efficient, but a good C compiler can probably optimize it adequately, especially if you put the code in a header as static functions.

You may also want to take a look at this closely related question: Integer division rounding with negatives in C++.

Community
  • 1
  • 1
Ville Laurikari
  • 28,380
  • 7
  • 60
  • 55
  • 1
    If you want efficient use a lookup table. If this code is an efficiency problem, the only real alternative would be to use the regular / and % operators and live with their rounding. – Chris Lutz May 06 '09 at 22:17
  • 3
    This is pretty neat. It'd be helpful to have some braces in this code (with that much conditional nesting, it's hard to tell what is happening where…) – Jonathan Sterling Mar 17 '11 at 15:01
  • Maybe this is a matter of taste, but I don't agree that adding braces would make this easier to read. When reading code, I look at the indentation instead of counting braces in my head. – Ville Laurikari Mar 17 '11 at 19:00
  • 2
    This code does not produce the correct modulo when either the dividend or the divisor is negative. – Rufflewind Sep 02 '14 at 00:20
  • 1
    @VilleLaurikari: Shouldn't that be `b : 0`, not `1 : 0`? This appears to work for me: ` int py_mod(int a, int b) { if ((a >= 0) == (b >= 0)) return a % b; else return (a % -b) + ((a % -b) != 0 ? b : 0); }` – Dwayne Robinson Feb 25 '20 at 05:06
  • 1
    Attention! `py_mod` gives wrong answer for `a = -1611640551, b = 2`. Python returns `1` while the snippet in answer gives `0`. – kelin Mar 05 '20 at 06:06
  • **CAUTION!** This answer does **not** produce the expected modulo result. The answer by @josch below, however, does. Use that instead (and don't waste time debugging, like I did). (Other answers may be right as well, I just didn't test them) – sodiumnitrate Aug 05 '20 at 01:00
7

For modulo, I find the following simplest. It doesn't matter what the implementation's sign convention is, we just coerce the result to the sign we want:

r = n % a;
if (r < 0) r += a;

Obviously that's for positive a. For negative a you need:

r = n % a;
if (r > 0) r += a;

Which (perhaps a little confusingly) combines to give the following (in C++. In C do the same thing with int, and then tediously write a duplicate for long long):

template<typename T> T sign(T t) { return t > T(0) ? T(1) : T(-1); }

template<typename T> T py_mod(T n, T a) {
    T r = n % a;
    if (r * sign(a) < T(0)) r += a;
    return r;
}

We can use a cheapskate two-valued "sign" function because we already know a!=0, or the % would be undefined.

Applying the same principle to division (look at the output rather than the input):

q = n / a;
// assuming round-toward-zero
if ((q < 0) && (q * a != n)) --q;

The multiplications arguably could be more expensive than necessary, but can be micro-optimised later on a per-architecture basis if need be. For instance if you have a division op that gives you quotient and remainder, then you're sorted for division.

[Edit: there might be some edge cases where this goes wrong, for instance if the quotient or the remainder is INT_MAX or INT_MIN. But emulating python maths for large values is a whole other question anyway ;-)]

[Another edit: isn't the standard python implementation written in C? You could trawl the source for what they do]

Steve Jessop
  • 273,490
  • 39
  • 460
  • 699
4

There is a solution to this question that is much shorter (in code) than the already presented ones. I will use the format of Ville Laurikari's answer for mine:

int py_div(int a, int b)
{
    return (a - (((a % b) + b) % b)) / b);
}

int py_mod(int a, int b)
{
    return ((a % b) + b) % b;
}

Unfortunately, it seems that the above solutions are not performing well. When benchmarking this solution against the one of Ville Laurikari, it becomes apparent that this solution performs only half as fast.

The lesson is: While branching instructions make code slow, division instructions are much worse!

I thought I nevertheless post this solution if only for its elegance.

josch
  • 6,716
  • 3
  • 41
  • 49
  • Any pointers to *why* does it work, either proof or intuitive explanation? – Emilio M Bumachar Jun 26 '20 at 13:51
  • @EmilioMBumachar Try plugging in values into the expression, and you'll see. For instance, for `a=-1` and `b=3`, `((-1%3)+3)%3=2`, but for `a=1` and `b=3`, `((1%3)+3)%3=1`, as expected. – sodiumnitrate Aug 05 '20 at 01:13
2

Here is a simple implementation of floored division and modulus in C89:

#include <stdlib.h>

div_t div_floor(int x, int y)
{
    div_t r = div(x, y);
    if (r.rem && (x < 0) != (y < 0)) {
        r.quot -= 1;
        r.rem  += y;
    }
    return r;
}

Here, div is used because it has well-defined behavior.

If you're using C++11, here is a templated implementation of floored division and modulus:

#include <tuple>

template<class Integral>
std::tuple<Integral, Integral> div_floor(Integral x, Integral y)
{
    typedef std::tuple<Integral, Integral> result_type;
    const Integral quot = x / y;
    const Integral rem  = x % y;
    if (rem && (x < 0) != (y < 0))
        return result_type(quot - 1, rem + y);
    return result_type(quot, rem);
}

In C99 and C++11, you can avoid using div since the behavior of division and modulus in C are no longer depend on the implementation.

Community
  • 1
  • 1
Rufflewind
  • 8,545
  • 2
  • 35
  • 55
1

The question asked about how to emulate Python-style integer division and modulo. All of the answers given here assume the operands of this operation to be integers themselves but Python can also use floats for its modulo operation. Thus, I think the following answer solves the problem even better:

#include <stdlib.h>
#include <stdio.h>
#include <math.h>

int pydiv(double a, double b) {
    int q = a/b;
    double r = fmod(a,b);
    if ((r != 0) && ((r < 0) != (b < 0))) {
        q -= 1;
    }
    return q;
}

int main(int argc, char* argv[])
{
    double a = atof(argv[1]);
    double b = atof(argv[2]);
    printf("%d\n", pydiv(a, b));
}

And for the modulo:

#include <stdlib.h>
#include <stdio.h>
#include <math.h>

double pymod(double a, double b) {
    double r = fmod(a, b);
    if (r!=0 && ((r<0) != (b<0))) {
        r += b;
    }
    return r;
}

int main(int argc, char* argv[])
{
    double a = atof(argv[1]);
    double b = atof(argv[2]);
    printf("%f\n", pymod(a, b));
}

I tested the above two programs against how Python behaves using the following test code:

#!/usr/bin/python3
import subprocess
subprocess.call(["cc", "pydiv.c", "-lm", "-o", "cdiv"])
subprocess.call(["cc", "pymod.c", "-lm", "-o", "cmod"])
def frange(start, stop, step=1):
    for i in range(0, int((stop-start)/step)):
        yield start + step*i
for a in frange(-10.0, 10.0, 0.25):
    for b in frange(-10.0, 10.0, 0.25):
        if (b == 0.0):
            continue
        pydiv = a//b
        pymod = a%b
        cdiv = int(subprocess.check_output(["./cdiv", str(a), str(b)]))
        cmod = float(subprocess.check_output(["./cmod", str(a), str(b)]))
        if pydiv != cdiv:
            exit(1)
        if pymod != cmod:
            exit(1)

The above will compare the behaviour of Python division and modulo with the C implementations I presented on 6320 testcases. Since the comparison succeeded, I believe that my solution correctly implements Python's behaviour of the respective operations.

josch
  • 6,716
  • 3
  • 41
  • 49
-1

It delves into the ugly world of floats, but these give correct answers in Java:

public static int pythonDiv(int a, int b) {
    if (!((a < 0) ^ (b < 0))) {
        return a / b;
    }
    return (int)(Math.floor((double)a/(double)b));
}

public static int pythonMod(int a, int b) {
    return a - b * pythonDiv(a,b);
}

I make no assertions about their efficiency.

Ry4an Brase
  • 78,112
  • 7
  • 148
  • 169
  • While this particular instance will likely produce correct results for all possible inputs, I'd still avoid it for the fact that it uses a floating point function for integral operations. If you substitute `float` for `double` or `long` for `int`, it will produce wrong results for some inputs. Also, if you port this instance to C or C++ on a platform where `int` is 64 bits wide, it will likewise produce wrong results for certain inputs. – blubberdiblub Jan 21 '18 at 20:51