Python-style integer division & modulus in C

后端 未结 6 1385
轻奢々
轻奢々 2020-12-05 17:55

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

>>>         


        
6条回答
  •  夕颜
    夕颜 (楼主)
    2020-12-05 18:21

    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 
    #include 
    #include 
    
    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 
    #include 
    #include 
    
    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.

提交回复
热议问题