Search code examples
pythongmpy

Do I loose precision when converting from MPZ to long?


I wrote the following modulo exponentiation. But I am not sure if I will loose precision when converting from MPZ type to long.

def mypowmod(base, power, modulus):
    base = gmpy.mpz(base)
    power = gmpy.mpz(power)
    modulus = gmpy.mpz(modulus)
    result = pow(base, power, modulus)
    return long(result)

Solution

  • Disclaimer: I am the maintainer of gmpy and gmpy2.

    The Python long type is arbitrary precision. Conversion to/from long and mpz are always exact.

    Since long is arbitrary precision, the built-in pow() function will calculate the correct result without requiring the use of gmpy or gmpy2. However, using the mpz type will be much faster. A quick test shows that it is faster even for number of only 10 digits.

    $ python -m timeit -s "import gmpy;a=10;b=gmpy.mpz('1'*a);p=gmpy.mpz('2'*a)-7;m=gmpy.mpz('3'*a)+11" "pow(b,p,m)"
    1000000 loops, best of 3: 1.41 usec per loop
    $ python -m timeit -s "a=10;b=long('1'*a);p=long('2'*a)-7;m=long('3'*a)+11" "pow(b,p,m)"
    100000 loops, best of 3: 8.89 usec per loop
    

    gmpy does not have a powmod() function. That function was introduced in gmpy2. gmpy2.powmod will automatically convert the arguments to mpz and return an mpz result. Your function could be written as:

    def mypowmod(base, power, modulus):
        return long(gmpy2.powmod(base, power modulus)
    

    Even including the conversion between long and mpz, it is still much faster than using the built-in long type.

    python -m timeit -s "import gmpy2;a=10;b=long('1'*a);p=long('2'*a)-7;m=long('3'*a)+11" "long(gmpy2.powmod(b,p,m))"
    1000000 loops, best of 3: 1.72 usec per loop