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.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With