I help maintain the gmpy library and I've been experimenting with a
Cython-based wrapper for GMP. I've done simple performance tests with
an early version of the library and it is slower than the C-based gmpy
library. I compared object creation and addition times for Python
longs, gmpy, and gmpy3 (the experimental library). These are my
results, in seconds (code is below):

create times
long:   2.25385284424
gmpy:   1.70728683472
gmpy3:  2.3947558403

addition times
long:   3.03700900078
gmpy:   2.6448340416
gmpy3:  4.70184206963

Do you have any suggestions for improving the performance?

Thanks,

Case

--------------------------------------------

The test script:

import time
import gmpy
import gmpy3

def create_test(ctor, times):
    start = time.time()
    for i in range(times):
        a=ctor(i)
    return (time.time() - start)

def addition_test(ctor, times):
    b = ctor('12345678901234567890')
    start = time.time()
    for i in range(times):
        a=ctor(i) + b
    return (time.time() - start)

print "create times"
print "long:  ", create_test(long, 10000000)
print "gmpy:  ", create_test(gmpy.mpz, 10000000)
print "gmpy3: ", create_test(gmpy3.mpz, 10000000)
print
print "addition times"
print "long:  ", addition_test(long, 10000000)
print "gmpy:  ", addition_test(gmpy.mpz, 10000000)
print "gmpy3: ", addition_test(gmpy3.mpz, 10000000)

-----------------------------------------------------------------

Excerpts from gmpy3.pyx

cdef class mpz:
    """
    Wrapper for GMP multiple-precision integers.
    """

    cdef mpz_t z

    def __init__(self, val=None, base=10):
        """
        Initialize a variable of type mpz.
        """
        cdef _longobject *l

        if val is None:
            mpz_init(self.z)
        elif PyInt_CheckExact(val):
            mpz_init_set_si(self.z, val)
        elif PyString_CheckExact(val):
            if mpz_init_set_str(self.z, val, base):
                raise ValueError('Invalid literal for mpz() with base
' + str(base))
        elif PyLong_CheckExact(val):
            mpz_init(self.z)
            l = <_longobject *> val
            if l.ob_size < 0:
                negval = True
                length = - l.ob_size
            else:
                negval = False
                length = l.ob_size
            mpz_import(self.z, length, -1, sizeof(l.ob_digit[0]), 0,
sizeof(l.ob_digit[0])*8 - SHIFT, l.ob_digit)
            if negval:
                mpz_neg(self.z, self.z)
        elif PyFloat_CheckExact(val):
            mpz_init_set_d(self.z, val)
        elif isinstance(val, mpz):
            mpz_init_set(self.z, (<mpz>val).z)
        else:
            raise TypeError('mpz() argument must be string, int, long,
or float')

    def __dealloc__(self):
        mpz_clear(self.z)

    def __add__(self, other):
        cdef int temp
        result = mpz()
        cdef mpz Z

        if isinstance(self, mpz):
            if isinstance(other, mpz):
                mpz_add((<mpz>result).z, (<mpz>self).z, (<mpz>other).z)
            elif PyInt_CheckExact(other):
                if other >= 0:
                    mpz_add_ui((<mpz>result).z, (<mpz>self).z, other)
                else:
                    mpz_sub_ui((<mpz>result).z, (<mpz>self).z, abs(other))
            else:
                mpz_add((<mpz>result).z, (<mpz>self).z, (<mpz>mpz(other)).z)
            return result
        else:
            return mpz.__add__(other, self)
_______________________________________________
Cython-dev mailing list
[email protected]
http://codespeak.net/mailman/listinfo/cython-dev

Reply via email to