Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python 3 integer division. How to make math operators consistant with C

Tags:

python-3.x

I need to port quite a few formulas from C to Python and vice versa. What is the best way to make sure that nothing breaks in the process?

I am primarily worried about automatic int/int = float conversions.

like image 450
pic11 Avatar asked Mar 19 '11 23:03

pic11


3 Answers

You could use the // operator. It performs an integer division, but it's not quite what you'd expect from C:

A quote from here:

The // operator performs a quirky kind of integer division. When the result is positive, you can think of it as truncating (not rounding) to 0 decimal places, but be careful with that.

When integer-dividing negative numbers, the // operator rounds “up” to the nearest integer. Mathematically speaking, it’s rounding “down” since −6 is less than −5, but it could trip you up if you were expecting it to truncate to −5.

For example, -11 // 2 in Python returns -6, where -11 / 2 in C returns -5. I'd suggest writing and thoroughly unit-testing a custom integer division function that "emulates" C behaviour.

The page I linked above also has a link to PEP 238 which has some interesting background information about division and the changes from Python 2 to 3. There are some suggestions about what to use for integer division, like divmod(x, y)[0] and int(x/y) for positive numbers, perhaps you'll find more useful things there.

like image 190
schnaader Avatar answered Oct 03 '22 17:10

schnaader


In C:

-11/2 = -5

In Python:

-11/2 = -5.5

And also in Python:

-11//2 = -6

To achieve C-like behaviour, write int(-11/2) in Python. This will evaluate to -5.

like image 22
Salman Farooq Avatar answered Oct 03 '22 18:10

Salman Farooq


Some ways to compute integer division with C semantics are as follows:

def div_c0(a, b):
    if (a >= 0) != (b >= 0) and a % b:
        return a // b + 1
    else:
        return a // b
def div_c1(a, b):
    q, r = a // b, a % b
    if (a >= 0) != (b >= 0) and r:
        return q + 1
    else:
        return q
def div_c2(a, b):
    q, r = divmod(a, b)
    if (a >= 0) != (b >= 0) and r:
        return q + 1
    else:
        return q
def mod_c(a, b):
    return (a % b if b >= 0 else a % -b) if a >= 0 else (-(-a % b) if b >= 0 else a % b)


def div_c3(a, b):
    r = mod_c(a, b)
    return (a - r) // b

With timings:

import itertools


n = 100
l = [x for x in range(-n, n + 1)]
ll = [(a, b) for a, b in itertools.product(l, repeat=2) if b]


funcs = div_c0, div_c1, div_c2, div_c3
for func in funcs:
    correct = all(func(a, b) == funcs[0](a, b) for a, b in ll)
    print(f"{func.__name__}  correct:{correct}  ", end="")
    %timeit [func(a, b) for a, b in ll]
# div_c0  correct:True  100 loops, best of 5: 10.3 ms per loop
# div_c1  correct:True  100 loops, best of 5: 11.5 ms per loop
# div_c2  correct:True  100 loops, best of 5: 13.2 ms per loop
# div_c3  correct:True  100 loops, best of 5: 15.4 ms per loop

Indicating the first approach to be the fastest.


For implementing C's % using Python, see here.

like image 21
norok2 Avatar answered Oct 03 '22 17:10

norok2