gmpy-1.17/0000755000000000000000000000000012543053022011110 5ustar rootrootgmpy-1.17/test3/0000755000000000000000000000000012543053022012152 5ustar rootrootgmpy-1.17/test3/timing3.py0000666000000000000000000000147012174774726014131 0ustar rootrootimport gmpy as _g import time print("Typical expected results would be:",""" D:\PySym>python timing.py Factorial of 10000 took 0.0619989238859 (35660 digits) Fibonacci of 10000 took 0.000744228458022 (2090 digits) Factorial of 100000 took 4.44311764676 (456574 digits) Fibonacci of 100000 took 0.022344453738 (20899 digits) Factorial of 1000000 took 152.151135367 (5565709 digits) Fibonacci of 1000000 took 0.670207059778 (208988 digits) """) print("Actual timings and results...:") for i in (10000,100000,1000000): start=time.time() x=_g.fac(i) stend=time.time() print("Factorial of %d took %s (%d digits)" % ( i, stend-start, x.numdigits())) start=time.time() x=_g.fib(i) stend=time.time() print("Fibonacci of %d took %s (%d digits)" % ( i, stend-start, x.numdigits())) gmpy-1.17/test3/timing2.py0000666000000000000000000000127512174774726014133 0ustar rootrootimport gmpy, time def timedfib(n, zero): start=time.clock() a=zero; b=a+1 for i in range(n): a,b=b,a+b stend=time.clock() return type(zero), stend-start, a def timedfibsp(n, one): start=time.clock() result=gmpy.fib(n) stend=time.clock() return type(one), stend-start, result def test(n=100*1000): print("%dth Fibonacci number of various types:" % n) for z in 0, gmpy.mpz(0), gmpy.mpf(0): tip, tim, tot = timedfib(n, z) print(" %5.3f %s %s" % (tim, gmpy.fdigits(tot,10,6), tip)) tip, tim, tot = timedfibsp(n, 1) print(" %5.3f %s %s" % (tim, gmpy.fdigits(tot,10,6), "gmpy.fib")) if __name__=='__main__': test() gmpy-1.17/test3/timing1.py0000666000000000000000000000231712174774726014130 0ustar rootrootimport gmpy, time try: sum except NameError: def sum(x, z): for item in x: z += item return z def timedsum(n, zero): start=time.clock() tot=zero for i in range(n): tot+=i stend=time.clock() return type(zero), stend-start, tot def timedsum1(n, zero): start=time.clock() tot=sum(range(n), zero) stend=time.clock() return type(zero), stend-start, tot def timedmul(n, one): start=time.clock() tot=one for i in range(n): tot*=(i+1) stend=time.clock() return type(one), stend-start, tot def test(n=100*1000): print("Sum of %d items of various types:" % n) for z in 0, 0.0, gmpy.mpz(0), gmpy.mpf(0): tip, tim, tot = timedsum(n, z) print(" %5.3f %.0f %s" % (tim, float(tot), tip)) print("Sum of %d items of various types w/2.3 sum builtin:" % n) for z in 0, 0.0, gmpy.mpz(0), gmpy.mpf(0): tip, tim, tot = timedsum1(n, z) print(" %5.3f %.0f %s" % (tim, float(tot), tip)) print("Mul of %d items of various types:" % (n//5)) for z in 1, 1.0, gmpy.mpz(1), gmpy.mpf(1): tip, tim, tot = timedmul(n//5, z) print(" %5.3f %s" % (tim, tip)) if __name__=='__main__': test() gmpy-1.17/test3/test_mpz_args.py0000666000000000000000000000361712174774726015445 0ustar rootroot# Test a wide variety of input values to the commonly used mpz operations. # This test should be run whenever optimizations are made to the handling of # arguments. import sys import gmpy if sys.version.startswith('3'): intTypes = (int,) else: intTypes = (int, long) def writeln(s): sys.stdout.write(s+'\n') valueList = [0, 1, 2, 3, 4, 5] for power in (15, 16, 30, 32, 45, 48, 60, 64, 75, 90, 96, 105, 120, 128): for i in (-2, -1, 0, 1, 2): valueList.append(2**power + i) valueList.append('123456789012345678901234567890') valueList.append('10000000000000000000000000000000000000000000000000000000000000000') testValues = [] mpzValues = [] for i in valueList: for t in intTypes: testValues.append(t(i)) testValues.append(-t(i)) mpzValues.append(gmpy.mpz(i)) mpzValues.append(-gmpy.mpz(i)) testValues.extend(mpzValues) for i in testValues: for z in mpzValues: # Test all permutations of addition assert int(i)+int(z) == i+z, (repr(i),repr(z)) assert int(z)+int(i) == z+i, (repr(i),repr(z)) # Test all permutations of subtraction assert int(i)-int(z) == i-z, (repr(i),repr(z)) assert int(z)-int(i) == z-i, (repr(i),repr(z)) # Test all permutations of multiplication assert int(i)*int(z) == i*z, (repr(i),repr(z)) assert int(z)*int(i) == z*i, (repr(i),repr(z)) # Test all permutations of division if z!=0: temp = int(i)//int(z) assert int(i)//int(z) == i//z, (repr(i),repr(z)) assert int(i)%int(z) == i%z, (repr(i),repr(z)) assert divmod(int(i),int(z)) == divmod(i,z), (repr(i),repr(z)) if i!=0: temp = int(z)//int(i) assert int(z)//int(i) == z//i, (repr(i),repr(z)) assert int(z)%int(i) == z%i, (repr(i),repr(z)) assert divmod(int(z),int(i)) == divmod(z,i), (repr(i),repr(z)) gmpy-1.17/test3/test_large.py0000666000000000000000000000156612174774726014716 0ustar rootrootfrom gmpy import * from math import log from time import time # This test is designed to detect issues when allocating memory for large # numbers. If it crashes and you need to work with very large numbers, # you will need to compile GMP from scratch and try a different memory # allocation option. def pi(N): print("Computing pi to %s decimal places." % N) start = time() N = int(round(log(10,2)*N)) sq2 = fsqrt(mpf(2, N)) a = mpz(6) - 4*sq2 y = sq2-1 for k in range(0, 10000): xx = fsqrt(fsqrt(1-y**4)) y = (1-xx)/(1+xx) anew = a*(1+y)**4 - 2**(2*k+3)*y*(1+y+y**2) if anew == a: break a = anew print("Computation took %5.2f seconds." % (time() - start)) return 1/a if __name__ == '__main__': print("Testing operations with large numbers.") pi(1000000) gmpy-1.17/test3/test_hash.py0000666000000000000000000000214012174774726014534 0ustar rootroot# Hash test for Python 3.2. import gmpy import fractions import sys try: m = sys.hash_info.modulus except NameError: print("new-style hash is not supported") sys.exit(0) for s in [0, m//2, m, m*2, m*m]: for i in range(-10,10): for k in [-1, 1, 7, 11, -(2**15), 2**16, 2**30, 2**31, 2**32, 2**33, 2**61, -(2**62), 2**63, 2**64]: val = k*(s + i) assert hash(val) == hash(gmpy.mpz(val)) print("hash tests for integer values passed") for d in [1, -2, 3, -47, m, m*2]: for s in [0, m//2, m, m*2, m*m]: for i in range(-10,10): for k in [-1, 1, 7, 11, -(2**15), 2**16, 2**30, 2**31, 2**32, 2**33, 2**61, -(2**62), 2**63, 2**64]: val = k*(s + i) if val: assert hash(fractions.Fraction(d,val)) == hash(gmpy.mpq(d,val)), (d,val,hash(fractions.Fraction(d,val)),hash(gmpy.mpq(d,val))) if d: assert hash(fractions.Fraction(val,d)) == hash(gmpy.mpq(val,d)), (val,d,hash(fractions.Fraction(val,d)),hash(gmpy.mpq(val,d))) print("hash tests for rational values passed") gmpy-1.17/test3/gmpy_truediv.py0000666000000000000000000000017612174774726015277 0ustar rootroot''' make a "true division" function available for testing ''' from __future__ import division def truediv(a, b): return a/b gmpy-1.17/test3/gmpy_test_thr.py0000666000000000000000000000702012174774726015444 0ustar rootroot# partial unit test for gmpy threaded mpz functionality # relies on Tim Peters' "doctest.py" test-driver import gmpy as _g, doctest, sys, operator, gc, queue, threading from functools import reduce __test__={} def _tf(N=2, _K=1234**5678): """Takes about 100ms on a first-generation Macbook Pro""" for i in range(N): assert (_g.mpz(1234)**5678)==_K a=_g.mpz(123) b=_g.mpz(456) c=_g.mpz(123456789123456789) def factorize(x=c): r''' (Takes about 25ms, on c, on a first-generation Macbook Pro) >>> factorize(a) [3, 41] >>> factorize(b) [2, 2, 2, 3, 19] >>> ''' import gmpy as _g savex=x prime=2 x=_g.mpz(x) factors=[] while x>=prime: newx,mult=x.remove(prime) if mult: factors.extend([int(prime)]*mult) x=newx prime=_g.next_prime(prime) for factor in factors: assert _g.is_prime(factor) from operator import mul assert reduce(mul, factors)==savex return factors def elemop(N=1000): r''' (Takes about 40ms on a first-generation Macbook Pro) ''' for i in range(N): assert a+b == 579 assert a-b == -333 assert b*a == a*b == 56088 assert b%a == 87 assert divmod(a, b) == (0, 123) assert divmod(b, a) == (3, 87) assert -a == -123 assert pow(a, 10) == 792594609605189126649 assert pow(a, 7, b) == 99 assert cmp(a, b) == -1 assert '7' in str(c) assert '0' not in str(c) assert a.sqrt() == 11 assert _g.lcm(a, b) == 18696 assert _g.fac(7) == 5040 assert _g.fib(17) == 1597 assert _g.divm(b, a, 20) == 12 assert _g.divm(4, 8, 20) == 3 assert _g.divm(4, 8, 20) == 3 assert _g.mpz(20) == 20 assert _g.mpz(8) == 8 assert _g.mpz(4) == 4 assert a.invert(100) == 87 def _test(chat=None): if chat: print("Unit tests for gmpy 1.17 (threading)") print(" running on Python", sys.version) print() if _g.gmp_version(): print("Testing gmpy %s (GMP %s) with default caching (%s, %s)" % ( (_g.version(), _g.gmp_version(), _g.get_cache()[0], _g.get_cache()[1]))) else: print("Testing gmpy %s (MPIR %s) with default caching (%s, %s)" % ( (_g.version(), _g.mpir_version(), _g.get_cache()[0], _g.get_cache()[1]))) thismod = sys.modules.get(__name__) doctest.testmod(thismod, report=0) if chat: print("Repeating tests, with caching disabled") _g.set_cache(0,128) sav = sys.stdout class _Dummy: def write(self,*whatever): pass try: sys.stdout = _Dummy() doctest.testmod(thismod, report=0) finally: sys.stdout = sav if chat: print() print("Overall results for thr:") return doctest.master.summarize(chat) class DoOne(threading.Thread): def __init__(self, q): threading.Thread.__init__(self) self.q = q def run(self): while True: task = self.q.get() if task is None: break task() def _test_thr(Ntasks=5, Nthreads=1): q = queue.Queue() funcs = (_tf, 1), (factorize, 4), (elemop, 2) for i in range(Ntasks): for f, n in funcs: for x in range(n): q.put(f) for i in range(Nthreads): q.put(None) thrs = [DoOne(q) for i in range(Nthreads)] for t in thrs: t.start() for t in thrs: t.join() if __name__=='__main__': _test(1) gmpy-1.17/test3/gmpy_test_rnd.py0000666000000000000000000000562212174774726015440 0ustar rootroot# partial unit test for gmpy rand functionality # relies on Tim Peters' "doctest.py" test-driver r''' >>> r >>> ''' import gmpy as _g, doctest,sys __test__={} r = _g.rand __test__['rand']=\ r''' >>> r('error',1,2,3) Traceback (most recent call last): ... TypeError: function takes exactly 2 arguments (4 given) >>> r('save') Traceback (most recent call last): ... RuntimeError: can't save before init >>> r('init',20) >>> r('unkn',99) Traceback (most recent call last): ... ValueError: unknown option 'unkn' >>> r('seed',1234) >>> for i in range(5): ... print(r('next',100)) ... 21 75 63 28 27 >>> alis=list("proktelnu") >>> for i in range(10): ... r('shuf',alis) ... print(''.join(alis)) ... rtoulpnke eoturlknp plnuetokr ekoprulnt kpoutnrel rutoneklp ukeptnorl onkrlpteu lknteropu enrkutlpo >>> sav=r('save') >>> print(sav) 774447212137 >>> for i in range(5): ... r('shuf',alis) ... print(''.join(alis)) ... elnuortpk enutolpkr eropulntk plroutenk ekonrtplu >>> r('seed',sav) >>> for i in range(5): ... r('shuf',alis) ... print(''.join(alis)) ... epkruotln ekrtuplno eoulrpktn lpourtekn enukotlpr >>> r('seed',sav) >>> for i in range(3): ... print("%.12f" % float(r('floa'))) ... 0.448332786560 0.547296524048 0.895370483398 >>> r('seed',sav) >>> for i in range(3): ... print(float(r('floa',6))) ... 0.484375 0.90625 0.75 >>> r('seed',sav) >>> for i in range(3): ... print(_g.f2q(r('floa',6),-6)) ... 15/31 9/10 3/4 >>> r('seed',sav) >>> for i in range(3): ... print(_g.f2q(r('floa',6))) ... 31/64 29/32 3/4 >>> r('seed',sav) >>> for i in range(5): ... r('shuf',alis) ... print(''.join(alis)) ... elnorutpk enotrlpku eurpolntk plurotenk ekrnutplo >>> try: r('shuf','astring') ... except TypeError as e: print(int("does not support item assignment" in str(e))) 1 >>> r('shuf',23) Traceback (most recent call last): ... TypeError: 'shuf' needs mutable sequence >>> ''' # adapt to python 2.3's slightly different error message in an exception import sys if sys.version<'2.4': __test__['rand'] = __test__['rand'].replace("does not", "doesn't") def _test(chat=None): if chat: print("Unit tests for gmpy 1.17 (rand functionality)") print(" running on Python %s" % sys.version) print("") if _g.gmp_version(): print("Testing gmpy %s (GMP %s) with default caching (%s, %s)" % ( (_g.version(), _g.gmp_version(), _g.get_cache()[0], _g.get_cache()[1]))) else: print("Testing gmpy %s (MPIR %s) with default caching (%s, %s)" % ( (_g.version(), _g.mpir_version(), _g.get_cache()[0], _g.get_cache()[1]))) thismod = sys.modules.get(__name__) doctest.testmod(thismod, report=0) if chat: print("") print("Overall results for rnd:") return doctest.master.summarize(chat) if __name__=='__main__': _test(1) gmpy-1.17/test3/gmpy_test_mpz.py0000666000000000000000000004551512174774726015470 0ustar rootroot# partial unit test for gmpy mpz functionality # relies on Tim Peters' "doctest.py" test-driver r''' >>> list(filter(lambda x: not x.startswith('_'), dir(_g))) ['binary', 'bincoef', 'bit_length', 'cdivmod', 'ceil', 'comb', 'denom', 'digits', 'divexact', 'divm', 'f2q', 'fac', 'fbinary', 'fdigits', 'fdivmod', 'fib', 'floor', 'fround', 'fsign', 'fsqrt', 'gcd', 'gcdext', 'get_cache', 'getbit', 'getprec', 'getrprec', 'gmp_limbsize', 'gmp_version', 'hamdist', 'invert', 'is_power', 'is_prime', 'is_square', 'jacobi', 'kronecker', 'lcm', 'legendre', 'license', 'lowbits', 'mpf', 'mpir_version', 'mpq', 'mpz', 'next_prime', 'numdigits', 'numer', 'pi', 'popcount', 'qbinary', 'qdigits', 'qdiv', 'qsign', 'rand', 'reldiff', 'remove', 'root', 'scan0', 'scan1', 'set_cache', 'set_debug', 'set_fcoform', 'set_minprec', 'set_tagoff', 'setbit', 'sign', 'sqrt', 'sqrtrem', 'tdivmod', 'trunc', 'version'] >>> list([x for x in dir(a) if x != '__dir__']) ['__abs__', '__add__', '__and__', '__bool__', '__class__', '__delattr__', '__divmod__', '__doc__', '__eq__', '__float__', '__floordiv__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__iadd__', '__ifloordiv__', '__ilshift__', '__imod__', '__imul__', '__index__', '__init__', '__int__', '__invert__', '__ipow__', '__irshift__', '__isub__', '__le__', '__lshift__', '__lt__', '__mod__', '__mul__', '__ne__', '__neg__', '__new__', '__or__', '__pos__', '__pow__', '__radd__', '__rand__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', '__rlshift__', '__rmod__', '__rmul__', '__ror__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__', '__rtruediv__', '__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__truediv__', '__xor__', '_copy', 'binary', 'bincoef', 'bit_length', 'comb', 'digits', 'getbit', 'hamdist', 'invert', 'is_power', 'is_prime', 'is_square', 'jacobi', 'kronecker', 'legendre', 'lowbits', 'next_prime', 'numdigits', 'popcount', 'qdiv', 'remove', 'root', 'scan0', 'scan1', 'setbit', 'sign', 'sqrt', 'sqrtrem'] >>> ''' import warnings warnings.filterwarnings('ignore', 'setprec') import gmpy as _g, doctest, sys, operator, gc __test__={} a=_g.mpz(123) b=_g.mpz(456) # Disable tests since they are not reliable with Python 3.1 but left behind # in case it is needed in the future. if sys.platform in ('__DISABLE__linux2', '__DISABLE__darwin'): def _memsize(): """ this function tries to return a measurement of how much memory this process is consuming (if it doesn't manage to, it returns 0). """ import os try: x = int(os.popen('ps -p %d -o vsz|tail -1' % os.getpid()).read()) except: x = 0 return x else: def _memsize(): return 0 def factorize(x): r''' >>> factorize(a) [3, 41] >>> factorize(b) [2, 2, 2, 3, 19] >>> ''' savex=x prime=2 x=_g.mpz(x) factors=[] while x>=prime: newx,mult=x.remove(prime) if mult: factors.extend([int(prime)]*mult) x=newx prime=_g.next_prime(prime) for factor in factors: assert _g.is_prime(factor) from operator import mul from functools import reduce assert reduce(mul, factors)==savex return factors __test__['index']=\ r''' >>> range(333)[a] 123 >>> range(333)[b] Traceback (innermost last): ... IndexError: range object index out of range ''' __test__['elemop']=\ r''' >>> a+b mpz(579) >>> a-b mpz(-333) >>> a*b mpz(56088) >>> a//b mpz(0) >>> a/b mpf('2.69736842105263157895e-1') >>> b//a mpz(3) >>> b/a mpf('3.70731707317073170732e0') >>> a%b mpz(123) >>> 0%b mpz(0) >>> b+a mpz(579) >>> b-a mpz(333) >>> b*a mpz(56088) >>> b%a mpz(87) >>> divmod(a,b) (mpz(0), mpz(123)) >>> divmod(b,a) (mpz(3), mpz(87)) >>> divmod(0,b) (mpz(0), mpz(0)) >>> -a mpz(-123) >>> a+1 mpz(124) >>> a+(-1) mpz(122) >>> (-1)+a mpz(122) >>> 1+a mpz(124) >>> a-1 mpz(122) >>> a-(-1) mpz(124) >>> 1-a mpz(-122) >>> (-1)-a mpz(-124) >>> a+True mpz(124) >>> a+False mpz(123) >>> a*False mpz(0) >>> a//True mpz(123) >>> abs(-a)==a 1 >>> pow(a,10) mpz(792594609605189126649) >>> pow(a,7,b) mpz(99) >>> _g.sign(b-a) 1 >>> _g.sign(b-b) 0 >>> _g.sign(a-b) -1 >>> a.sign() 1 >>> (-a).sign() -1 >>> z=b-b; z.sign() 0 >>> import pickle >>> pickle.loads(pickle.dumps(_g.mpz(12346789))) mpz(12346789) >>> s='12345678901234567890123456789' >>> int(s) == _g.mpz(s) True >>> _g.mpz(s) == int(s) True >>> del s ''' __test__['special'] = \ r''' >>> a == float('Inf') False >>> a != float('Inf') True >>> a > float('Inf') False >>> a >= float('Inf') False >>> a < float('Inf') True >>> a <= float('Inf') True >>> a == float('-Inf') False >>> a != float('-Inf') True >>> a > float('-Inf') True >>> a >= float('-Inf') True >>> a < float('-Inf') False >>> a <= float('-Inf') False >>> a == float('nan') False >>> a != float('nan') True >>> a > float('nan') False >>> a >= float('nan') False >>> a < float('nan') False >>> a <= float('nan') False >>> float('Inf') == a False >>> float('Inf') != a True >>> float('Inf') > a True >>> float('Inf') >= a True >>> float('Inf') < a False >>> float('Inf') <= a False >>> float('-Inf') == a False >>> float('-Inf') != a True >>> float('-Inf') > a False >>> float('-Inf') >= a False >>> float('-Inf') < a True >>> float('-Inf') <= a True >>> float('nan') == a False >>> float('nan') != a True >>> float('nan') > a False >>> float('nan') >= a False >>> float('nan') < a False >>> float('nan') <= a False >>> a + float('Inf') inf >>> float('Inf') + a inf >>> a + float('-Inf') -inf >>> float('-Inf') + a -inf >>> a + float('nan') nan >>> float('nan') + a nan >>> a - float('Inf') -inf >>> float('Inf') - a inf >>> a - float('-Inf') inf >>> float('-Inf') - a -inf >>> a - float('nan') nan >>> float('nan') - a nan >>> a * float('Inf') inf >>> float('Inf') * a inf >>> a * float('-Inf') -inf >>> float('-Inf') * a -inf >>> -a * float('Inf') -inf >>> float('Inf') * -a -inf >>> -a * float('-Inf') inf >>> float('-Inf') * -a inf >>> a * float('nan') nan >>> float('nan') * a nan >>> _g.mpz(0) * float('Inf') nan >>> _g.mpz(0) * float('-Inf') nan >>> float('Inf') * _g.mpz(0) nan >>> float('-Inf') * _g.mpz(0) nan >>> a / float('Inf') mpf('0.e0') >>> -a / float('Inf') mpf('0.e0') >>> float('Inf') / a inf >>> float('Inf') / -a -inf >>> a / float('-Inf') mpf('0.e0') >>> -a / float('-Inf') mpf('0.e0') >>> float('-Inf') / a -inf >>> float('-Inf') / -a inf >>> a / float('nan') nan >>> float('nan') / a nan >>> float('nan') / _g.mpz(0) Traceback (most recent call last): ... ZeroDivisionError: mpz division by zero >>> divmod(a, float('Inf')) (mpf('0.e0'), mpf('1.23e2')) >>> divmod(a, float('-Inf')) (mpf('-1.e0'), -inf) >>> divmod(-a, float('Inf')) (mpf('-1.e0'), inf) >>> divmod(-a, float('-Inf')) (mpf('0.e0'), mpf('-1.23e2')) >>> divmod(a, float('nan')) (nan, nan) >>> divmod(-a, float('nan')) (nan, nan) >>> divmod(_g.mpz(0), float('Inf')) (mpf('0.e0'), mpf('0.e0')) >>> divmod(_g.mpz(0), float('-Inf')) (mpf('0.e0'), mpf('0.e0')) >>> divmod(_g.mpz(0), float('nan')) (nan, nan) >>> divmod(float('Inf'), a) (nan, nan) >>> divmod(float('-Inf'), a) (nan, nan) >>> divmod(float('Inf'), -a) (nan, nan) >>> divmod(float('-Inf'), -a) (nan, nan) >>> divmod(float('nan'), a) (nan, nan) >>> divmod(float('nan'), -a) (nan, nan) >>> divmod(float('Inf'), _g.mpz(0)) Traceback (most recent call last): ... ZeroDivisionError: mpz modulo by zero >>> divmod(float('-Inf'), _g.mpz(0)) Traceback (most recent call last): ... ZeroDivisionError: mpz modulo by zero >>> divmod(float('nan'), _g.mpz(0)) Traceback (most recent call last): ... ZeroDivisionError: mpz modulo by zero ''' __test__['divexact']=\ r''' >>> a=_g.mpz('1234567912345678912345679') >>> b=_g.mpz('789789789789789789789789') >>> c=a*b >>> _g.divexact(c,a) mpz(789789789789789789789789) >>> _g.divexact(10,0) Traceback (most recent call last): ... ZeroDivisionError: divexact() division by 0 >>> ''' __test__['divmod']=\ r''' >>> _g.cdivmod(17,5) (mpz(4), mpz(-3)) >>> _g.cdivmod(-17,5) (mpz(-3), mpz(-2)) >>> _g.cdivmod(17,-5) (mpz(-3), mpz(2)) >>> _g.cdivmod(-17,-5) (mpz(4), mpz(3)) >>> _g.fdivmod(17,5) (mpz(3), mpz(2)) >>> _g.fdivmod(-17,5) (mpz(-4), mpz(3)) >>> _g.fdivmod(17,-5) (mpz(-4), mpz(-3)) >>> _g.fdivmod(-17,-5) (mpz(3), mpz(-2)) >>> _g.tdivmod(17,5) (mpz(3), mpz(2)) >>> _g.tdivmod(-17,5) (mpz(-3), mpz(-2)) >>> _g.tdivmod(17,-5) (mpz(-3), mpz(2)) >>> _g.tdivmod(-17,-5) (mpz(3), mpz(-2)) >>> _g.cdivmod(10,0) Traceback (most recent call last): ... ZeroDivisionError: cdivmod() division by 0 >>> _g.fdivmod(10,0) Traceback (most recent call last): ... ZeroDivisionError: fdivmod() division by 0 >>> _g.tdivmod(10,0) Traceback (most recent call last): ... ZeroDivisionError: tdivmod() division by 0 ''' __test__['cmpr']=\ r''' >>> c=_g.mpz(a) >>> c is a 1 >>> c==a 1 >>> c>a 0 >>> c>> d=a._copy() >>> a is d 0 >>> a == d 1 >>> a>b 0 >>> a>> not _g.mpz(0) 1 >>> not a 0 >>> _g.mpz(1) == None False >>> _g.mpz(1) == '1' False >>> _g.mpz(1) == 'abc' False >>> [_g.mpz(23), None].count(None) 1 >>> _g.mpz(3.14) mpz(3) >>> _g.mpz(_g.mpq(17,3)) mpz(5) >>> _g.mpz(23) mpz(23) >>> _g.mpz(-23) mpz(-23) >>> x=1000*1000*1000*1000*1000*1000*1000 >>> _g.mpz(x) mpz(1000000000000000000000) >>> a == float('Inf') False >>> a != float('Inf') True >>> a > float('Inf') False >>> a >= float('Inf') False >>> a < float('Inf') True >>> a <= float('Inf') True >>> a == float('-Inf') False >>> a != float('-Inf') True >>> a > float('-Inf') True >>> a >= float('-Inf') True >>> a < float('-Inf') False >>> a <= float('-Inf') False >>> a == float('nan') False >>> a != float('nan') True >>> a > float('nan') False >>> a >= float('nan') False >>> a < float('nan') False >>> a <= float('nan') False ''' __test__['bitops']=\ r''' >>> ~a mpz(-124) >>> a&b mpz(72) >>> a|b mpz(507) >>> a^b mpz(435) >>> a<<1 mpz(246) >>> a>>1 mpz(61) >>> a<<-1 Traceback (innermost last): ... ValueError: negative shift count >>> a>>-2 Traceback (innermost last): ... ValueError: negative shift count >>> a<<0 mpz(123) >>> a>>0 mpz(123) >>> a.popcount() 6 >>> _g.popcount(b) 4 >>> _g.popcount(-7) -1 >>> _g.popcount(0) 0 >>> a.hamdist(b) 6 >>> _g.hamdist(3) Traceback (innermost last): ... TypeError: hamdist() expects 'mpz','mpz' arguments >>> a.hamdist() Traceback (innermost last): ... TypeError: hamdist() expects 'mpz','mpz' arguments >>> a.hamdist(3, 4) Traceback (innermost last): ... TypeError: hamdist() expects 'mpz','mpz' arguments >>> a.lowbits(5) mpz(27) >>> b.lowbits(5) mpz(8) >>> b.lowbits(5)==(b%32) 1 >>> a.lowbits(5)==(a%32) 1 >>> a.setbit(20) mpz(1048699) >>> a.setbit(0,0) mpz(122) >>> for i in range(8): ... print(a.getbit(i)) ... 1 1 0 1 1 1 1 0 >>> for i in range(10): ... print(b.getbit(i)) ... 0 0 0 1 0 0 1 1 1 0 >>> [a.scan0(j) for j in range(33)] [2, 2, 2, 7, 7, 7, 7, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32] >>> [a.scan1(j) for j in range(10)] [0, 1, 3, 3, 4, 5, 6, None, None, None] >>> n=_g.mpz(-(7+6*16+5*256+7*4092)) >>> [n.scan0(j) for j in range(18)] [1, 1, 3, 3, 6, 6, 6, 8, 8, 10, 10, 12, 12, 13, 14, -1, None, None] >>> [n.scan1(j) for j in range(33)] [0, 2, 2, 4, 4, 5, 7, 7, 9, 9, 11, 11, 15, 15, 15, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32] >>> _g.mpz(0).bit_length() 0 >>> _g.mpz(12345).bit_length() 14 ''' __test__['format']=\ r''' >>> str(a) '123' >>> repr(a) 'mpz(123)' >>> hex(a) '0x7b' >>> oct(a) '0o173' >>> _g.mpz('123') mpz(123) >>> _g.mpz('1001001011',2) mpz(587) >>> _g.mpz('1001001011',2).digits(2) '1001001011' >>> for i in range(2,63): ... print(a.digits(i)) ... 1111011 11120 1323 443 323 234 173 146 123 102 a3 96 8b 83 7b 74 6f 69 63 5i 5d 58 53 4n 4j 4f 4b 47 43 3u 3r 3o 3l 3i 3f 3C 39 36 33 30 2d 2b 2Z 2X 2V 2T 2R 2P 2N 2L 2J 2H 2F 2D 2B 29 27 25 23 21 1z >>> print(a.digits(63)) Traceback (innermost last): File "", line 1, in ? print(a.digits(63)) ValueError: base must be either 0 or in the interval 2 ... 62 >>> _g.set_tagoff(0) 1 >>> a gmpy.mpz(123) >>> _g.set_tagoff(1) 0 >>> _g.mpz('43') mpz(43) >>> _g.mpz('043') mpz(43) >>> _g.mpz('43',0) mpz(43) >>> _g.mpz('043',0) mpz(35) >>> _g.mpz('0x43',0) mpz(67) >>> _g.mpz('0x43') Traceback (innermost last): File "", line 1, in ? _g.mpz('0x43') ValueError: invalid digits >>> ''' __test__['binio']=\ r''' >>> ba=a.binary() >>> ba b'{' >>> _g.mpz(ba,256) mpz(123) >>> _g.mpz(ba,256)==a 1 >>> _g.binary(123) b'{' >>> z=_g.mpz('melancholy',256) >>> z mpz(573406620562849222387053) >>> int(z) 573406620562849222387053 >>> divmod(z,a) (mpz(4661842443600400182008), mpz(69)) >>> for i in range(2,63): ... print(i,z.numdigits(i)) ... 2 79 3 50 4 40 5 35 6 31 7 29 8 27 9 25 10 24 11 23 12 23 13 22 14 21 15 21 16 20 17 20 18 19 19 19 20 19 21 18 22 18 23 18 24 18 25 18 26 17 27 17 28 17 29 17 30 17 31 16 32 16 33 16 34 16 35 16 36 16 37 16 38 16 39 15 40 15 41 15 42 15 43 15 44 15 45 15 46 15 47 15 48 15 49 15 50 14 51 14 52 14 53 14 54 14 55 14 56 14 57 14 58 14 59 14 60 14 61 14 62 14 >>> _g.numdigits(23) 2 >>> _g.numdigits(23,2) 5 >>> _g.numdigits(23,99) Traceback (most recent call last): File "", line 1, in ? ValueError: base must be either 0 or in the interval 2 ... 62 >>> hash(a) 123 >>> hash(b) 456 >>> hash(z) == hash(int(z)) True >>> _g.mpz(_g.binary(-123),256) mpz(-123) >>> int(_g.mpz(-3)) -3 ''' __test__['number']=\ r''' >>> print(a.sqrt()) 11 >>> print(b.sqrt()) 21 >>> print(a.sqrtrem()) (mpz(11), mpz(2)) >>> print(b.sqrtrem()) (mpz(21), mpz(15)) >>> for i in range(5): ... print(a.root(i+1),b.root(i+1)) ... (mpz(123), 1) (mpz(456), 1) (mpz(11), 0) (mpz(21), 0) (mpz(4), 0) (mpz(7), 0) (mpz(3), 0) (mpz(4), 0) (mpz(2), 0) (mpz(3), 0) >>> a.is_square() 0 >>> a.is_power() 0 >>> _g.is_square(99*99) 1 >>> _g.is_square(99*99*99) 0 >>> _g.is_square(0) 1 >>> _g.is_square(-1) 0 >>> _g.is_power(99*99*99) 1 >>> _g.gcd(a,b) mpz(3) >>> temp=_g.gcdext(a,b) >>> temp[0]==a*temp[1]+b*temp[2] True >>> _g.lcm(a,b) mpz(18696) >>> _g.fac(7) mpz(5040) >>> _g.fib(17) mpz(1597) >>> for i in range(10): ... print(_g.bincoef(10,i)) ... 1 10 45 120 210 252 210 120 45 10 >>> _g.divm(b,a,20) mpz(12) >>> _g.divm(a,b,100) Traceback (innermost last): File "", line 1, in ? _g.divm(a,b,100) ZeroDivisionError: not invertible >>> _g.divm(6,12,14) mpz(4) >>> _g.divm(0,1,2) mpz(0) >>> # guard against regression of an ancient gmpy bug: divm w/non-coprime parms >>> _g.divm(4,8,20) mpz(3) >>> _g.divm(4,8,20) mpz(3) >>> _g.mpz(20) mpz(20) >>> _g.mpz(8) mpz(8) >>> _g.mpz(4) mpz(4) >>> # guard against regression of a memory leak in divm >>> __ = gc.collect() >>> _siz = 87654 >>> _siz = _memsize() >>> for x in range(45678): ... _xx=_g.divm(b,a,20) >>> del _xx >>> __ = gc.collect() >>> (_memsize()-_siz) <= 32 True >>> a.invert(100) mpz(87) >>> b.invert(100) mpz(0) >>> _g.invert(3) Traceback (innermost last): ... TypeError: invert() expects 'mpz','mpz' arguments >>> a.invert() Traceback (innermost last): ... TypeError: invert() expects 'mpz','mpz' arguments >>> a.invert(3, 4) Traceback (innermost last): ... TypeError: invert() expects 'mpz','mpz' arguments >>> _g.comb(3,-1) Traceback (most recent call last): File "", line 1, in ? ValueError: binomial coefficient with negative k >>> _g.sqrt(-1) Traceback (most recent call last): File "", line 1, in ? ValueError: sqrt of negative number >>> _g.sqrtrem(-1) Traceback (most recent call last): File "", line 1, in ? ValueError: sqrt of negative number >>> _g.remove(3,-1) Traceback (most recent call last): File "", line 1, in ? ValueError: factor must be > 1 >>> _g.remove(3) Traceback (innermost last): ... TypeError: remove() expects 'mpz','mpz' arguments >>> a.remove() Traceback (innermost last): ... TypeError: remove() expects 'mpz','mpz' arguments >>> a.remove(3, 4) Traceback (innermost last): ... TypeError: remove() expects 'mpz','mpz' arguments >>> _g.is_prime(3,-3) Traceback (most recent call last): File "", line 1, in ? ValueError: repetition count for is_prime must be positive >>> _g.jacobi(10,3) 1 >>> _g.jacobi(10,-3) Traceback (most recent call last): File "", line 1, in ? ValueError: jacobi's y must be odd prime > 0 >>> _g.jacobi(3) Traceback (innermost last): ... TypeError: jacobi() expects 'mpz','mpz' arguments >>> a.jacobi() Traceback (innermost last): ... TypeError: jacobi() expects 'mpz','mpz' arguments >>> a.jacobi(3, 4) Traceback (innermost last): ... TypeError: jacobi() expects 'mpz','mpz' arguments >>> _g.legendre(10,3) 1 >>> _g.legendre(10,-3) Traceback (most recent call last): File "", line 1, in ? ValueError: legendre's y must be odd and > 0 >>> _g.legendre(3) Traceback (innermost last): ... TypeError: legendre() expects 'mpz','mpz' arguments >>> a.legendre() Traceback (innermost last): ... TypeError: legendre() expects 'mpz','mpz' arguments >>> a.legendre(3, 4) Traceback (innermost last): ... TypeError: legendre() expects 'mpz','mpz' arguments >>> _g.kronecker(10,3) 1 >>> _g.kronecker(10,-3) 1 >>> _g.kronecker(3) Traceback (innermost last): ... TypeError: kronecker() expects 'mpz','mpz' arguments >>> a.kronecker() Traceback (innermost last): ... TypeError: kronecker() expects 'mpz','mpz' arguments >>> a.kronecker(3, 4) Traceback (innermost last): ... TypeError: kronecker() expects 'mpz','mpz' arguments >>> a=10**20 >>> b=a+39 >>> _g.jacobi(a,b) 1 >>> _g.legendre(a,b) 1 >>> _g.kronecker(a,b) Traceback (most recent call last): File "", line 1, in ? ValueError: Either arg in Kronecker must fit in an int >>> f=_g.mpf(3.3) >>> f.setprec(-1) Traceback (most recent call last): File "", line 1, in ? ValueError: n must be >=0 >>> _g.rand('init',-1) >>> _g.rand('init',-7) Traceback (most recent call last): File "", line 1, in ? ValueError: size must be in 1..128 >>> _g.rand('init',200) Traceback (most recent call last): File "", line 1, in ? ValueError: size must be in 1..128 >>> _g.rand('qual') 32 >>> _g.rand('floa',-7) Traceback (most recent call last): File "", line 1, in ? ValueError: 'floa' needs arg>=0 ''' def _test(chat=None): if chat: print("Unit tests for gmpy 1.17 (mpz functionality)") print(" running on Python %s" % sys.version) print() if _g.gmp_version(): print("Testing gmpy %s (GMP %s), default caching (%s, %s)" % ( (_g.version(), _g.gmp_version(), _g.get_cache()[0], _g.get_cache()[1]))) else: print("Testing gmpy %s (MPIR %s), default caching (%s, %s)" % ( (_g.version(), _g.mpir_version(), _g.get_cache()[0], _g.get_cache()[1]))) thismod = sys.modules.get(__name__) doctest.testmod(thismod, report=0) if chat: print("Repeating tests, with caching disabled") _g.set_cache(0,128) sav = sys.stdout class _Dummy: encoding = None def write(self,*whatever): pass try: sys.stdout = _Dummy() doctest.testmod(thismod, report=0) finally: sys.stdout = sav if chat: print() print("Overall results for mpz:") return doctest.master.summarize(chat) if __name__=='__main__': _test(1) gmpy-1.17/test3/gmpy_test_mpq.py0000666000000000000000000001510612174774726015450 0ustar rootroot# partial unit test for gmpy mpq functionality # relies on Tim Peters' "doctest.py" test-driver # Hack to remove the '__dir__' attribute introduced in Python 3.3 r''' >>> list([x for x in dir(a) if x != '__dir__']) ['__abs__', '__add__', '__bool__', '__class__', '__delattr__', '__divmod__', '__doc__', '__eq__', '__float__', '__floordiv__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__int__', '__le__', '__lt__', '__mod__', '__mul__', '__ne__', '__neg__', '__new__', '__pos__', '__pow__', '__radd__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', '__rmod__', '__rmul__', '__rpow__', '__rsub__', '__rtruediv__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__truediv__', '_copy', 'binary', 'denom', 'denominator', 'digits', 'numer', 'numerator', 'qdiv', 'sign'] >>> ''' import gmpy as _g, doctest,sys import fractions F=fractions.Fraction __test__={} a=_g.mpq('123/456') b=_g.mpq('789/123') af=F(123,456) bf=F(789,123) __test__['compat']=\ r''' >>> a==af True >>> af==a True >>> a < af False >>> a <= af True >>> a > af False >>> a >= af True >>> af < a False >>> af <= a True >>> af > a False >>> af >= a True >>> a+bf mpq(41657,6232) >>> divmod(123*a, b) == divmod(123*af, bf) True >>> divmod(-23*a, b) == divmod(-23*af, bf) True >>> divmod(a+17, b-23) == divmod(af+17, bf-23) True >>> divmod(-a, -b) == divmod(-af, -bf) True ''' __test__['elemop']=\ r''' >>> a+b mpq(41657,6232) >>> a-b mpq(-38295,6232) >>> a*b mpq(263,152) >>> a/b mpq(1681,39976) >>> a//b mpz(0) >>> a//-b mpz(-1) >>> -a//b mpz(-1) >>> -a//-b mpz(0) >>> b+a mpq(41657,6232) >>> b-a mpq(38295,6232) >>> b*a mpq(263,152) >>> b/a mpq(39976,1681) >>> b//a mpz(23) >>> a+1 mpq(193,152) >>> 1+a mpq(193,152) >>> a-1 mpq(-111,152) >>> 1-a mpq(111,152) >>> a*1 mpq(41,152) >>> 1*a mpq(41,152) >>> a/1 mpq(41,152) >>> 1/a mpq(152,41) >>> a % b mpq(41,152) >>> a % -b mpq(-38295,6232) >>> 2*a % 7*b mpq(263,76) >>> -a mpq(-41,152) >>> abs(-a) mpq(41,152) >>> _g.qsign(b-a) 1 >>> _g.qsign(b-b) 0 >>> _g.qsign(a-b) -1 >>> a.sign() 1 >>> (-a).sign() -1 >>> z=b-b; z.sign() 0 >>> a.numer() == a.numerator True >>> a.denom() == a.denominator True >>> an=a.numer(); ad=a.denom(); >>> an==0 or 1==a*_g.mpq(ad,an) 1 >>> bn=b.numer(); bd=b.denom(); >>> bn==0 or 1==b*_g.mpq(bd,bn) 1 >>> zn=z.numer(); zd=z.denom(); >>> zn==0 or 1==z*_g.mpq(zd,zn) 1 >>> (a+b) == _g.mpq(an*bd+ad*bn,ad*bd) 1 >>> (a+z) == _g.mpq(an*zd+ad*zn,ad*zd) 1 >>> (a+a) == _g.mpq(an*ad+ad*an,ad*ad) 1 >>> import pickle >>> pickle.loads(pickle.dumps(_g.mpq(1234,6789))) mpq(1234,6789) >>> ''' __test__['cmpr']=\ r''' >>> c=_g.mpq(a) >>> c is a 1 >>> c==a 1 >>> c>a 0 >>> c>> d=a._copy() >>> a is d 0 >>> a == d 1 >>> a>b 0 >>> a>> not _g.mpq(0) 1 >>> not a 0 >>> a>1 0 >>> a>1.0 0 >>> a<1 1 >>> a<1.0 1 >>> a==1 0 >>> a==1.0 0 >>> int(1/a) 3 >>> int(-1/a) -3 >>> ''' __test__['format']=\ r''' >>> str(a) '41/152' >>> repr(a) 'mpq(41,152)' >>> a==eval(repr(a),_g.__dict__) 1 >>> str(-a) '-41/152' >>> repr(-a) 'mpq(-41,152)' >>> (-a)==eval(repr(-a),_g.__dict__) 1 >>> _g.set_tagoff(0) 1 >>> a gmpy.mpq(41,152) >>> _g.mpq('12.34') gmpy.mpq(617,50) >>> _g.set_tagoff(1) 0 >>> for i in range(1,7): ... for j in range(3,10): ... if _g.mpq(i,j) != _g.mpq("%d/%d"%(i,j)): ... print('er1:',i,j); break ... aa=_g.mpq(i,j); ai=aa.numer(); aj=aa.denom() ... if aj!=1 and str(aa) != ("%d/%d"%(ai,aj)): ... print('er2:',i,j,str(aa),("%d/%d"%(ai,aj))); break ... if aj==1 and str(aa) != ("%d"%ai): ... print('er3:',i,j,str(aa),"%d"%ai); break ... if aj!=1 and repr(aa) != ("mpq(%d,%d)"%(ai,aj)): ... print('er4:',i,j,repr(aa),("mpq(%d,%d)"%(ai,aj))); break ... if aj==1 and repr(aa) != ("mpq(%d,%d)"%(ai,aj)): ... print('er5:',i,j,repr(aa),"mpq(%d,%d)"%(ai,aj)); break >>> fmo='_g.mpq('+hex(a.numer())+','+hex(a.denom())+')' >>> fmo '_g.mpq(0x29,0x98)' >>> eval(fmo)==a 1 >>> fmo='_g.mpq("'+a.numer().digits(30)+'/'+a.denom().digits(30)+'",30)' >>> fmo '_g.mpq("1b/52",30)' >>> eval(fmo)==a 1 >>> _g.qdigits(a,30) '1b/52' >>> a.digits(30) '1b/52' >>> _g.mpq(1000*1000*1000*1000*1000*1000*1000,23) mpq(1000000000000000000000,23) >>> _g.mpq(23,1000*1000*1000*1000*1000*1000*1000) mpq(23,1000000000000000000000) >>> _g.mpq(23**15,1000**7) mpq(266635235464391245607,1000000000000000000000) >>> _g.qbinary('pep') Traceback (most recent call last): File "", line 1, in ? TypeError: argument can not be converted to mpq >>> x=_g.mpq('234/567') >>> del x >>> _g.mpq('7788') mpq(7788,1) >>> _g.mpq('12.34') mpq(617,50) ''' __test__['binio']=\ r''' >>> ba=a.binary() >>> len(ba) 6 >>> for i in range(len(ba)): ... print(ba[i]) ... 1 0 0 0 41 152 >>> _g.mpq(ba,256)==a 1 >>> ba == _g.qbinary(a) 1 >>> ba=(-a).binary() >>> len(ba) 6 >>> for i in range(len(ba)): ... print(ba[i]) ... 1 0 0 128 41 152 >>> _g.mpq(ba,256)==-a 1 >>> ''' __test__['power']=\ r''' >>> _g.mpq(2,3)**3 mpq(8,27) >>> _g.mpq(8,27)**_g.mpq('2/3') mpq(4,9) >>> _g.mpq(2,3)**-3 mpq(27,8) >>> _g.mpq(8,27)**_g.mpq('-2/3') mpq(9,4) >>> print(float("%.14f" % _g.mpf('0.2')**2)) 0.04 >>> print(float(_g.mpf('0.2')**-2)) 25.0 >>> _g.mpq(3)**3 == _g.mpz(3)**3 True >>> (a**-7) == 1/(a**7) True >>> (b**5) == 1/(b**-5) True >>> ''' __test__['qdiv']=\ r''' >>> _g.qdiv(12,2) mpz(6) >>> _g.qdiv(12,5) mpq(12,5) >>> a is a.qdiv() 1 >>> a is a.qdiv(1) 1 >>> a is a.qdiv(2) 0 >>> x=a.numer() >>> x is _g.qdiv(x) 1 >>> x is _g.qdiv(x,1) 1 >>> x is _g.qdiv(x,2) 0 >>> y=_g.mpq(4,1) >>> y is y.qdiv() 0 >>> y == y.qdiv() 1 >>> ''' def _test(chat=None): if chat: print("Unit tests for gmpy 1.17 (mpq functionality)") print(" running on Python",sys.version) print() if _g.gmp_version(): print("Testing gmpy %s (GMP %s), default caching (%s, %s)" % ( (_g.version(), _g.gmp_version(), _g.get_cache()[0], _g.get_cache()[1]))) else: print("Testing gmpy %s (MPIR %s), default caching (%s, %s)" % ( (_g.version(), _g.mpir_version(), _g.get_cache()[0], _g.get_cache()[1]))) thismod = sys.modules.get(__name__) doctest.testmod(thismod, report=0) if chat: print("Repeating tests, with caching disabled") _g.set_cache(0,128) sav = sys.stdout class _Dummy: encoding = None def write(self,*whatever): pass try: sys.stdout = _Dummy() doctest.testmod(thismod, report=0) finally: sys.stdout = sav if chat: print() print("Overall results for mpq:") return doctest.master.summarize(chat) if __name__=='__main__': _test(1) gmpy-1.17/test3/gmpy_test_mpf.py0000666000000000000000000002110112174774726015425 0ustar rootroot# partial unit test for gmpy mpf functionality # relies on Tim Peters' "doctest.py" test-driver # Hack to remove the '__dir__' attribute introduced in Python 3.3 r''' >>> list([x for x in dir(a) if x != '__dir__']) ['__abs__', '__add__', '__bool__', '__class__', '__delattr__', '__divmod__', '__doc__', '__eq__', '__float__', '__floordiv__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__int__', '__le__', '__lt__', '__mod__', '__mul__', '__ne__', '__neg__', '__new__', '__pos__', '__pow__', '__radd__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', '__rmod__', '__rmul__', '__rpow__', '__rsub__', '__rtruediv__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__truediv__', '_copy', 'binary', 'ceil', 'digits', 'f2q', 'floor', 'getprec', 'getrprec', 'qdiv', 'reldiff', 'round', 'setprec', 'sign', 'sqrt', 'trunc'] >>> ''' import warnings warnings.filterwarnings('ignore', 'setprec') import sys import gmpy as _g, doctest, sys __test__={} a=_g.mpf('123.456') b=_g.mpf('789.123') __test__['elemop']=\ r''' >>> str(a+b) '912.579' >>> str(a-b) '-665.667' >>> str(a*b) '97421.969088' >>> str(a/b) '0.156447093799065544915' >>> str(b+a) '912.579' >>> str(b-a) '665.667' >>> str(b*a) '97421.969088' >>> str(b/a) '6.39193720839813374807' >>> str(-a) '-123.456' >>> str(abs(-a)) '123.456' >>> _g.mpf(2,200) + 3 mpf('5.e0',200) >>> 3 + _g.mpf(2,200) mpf('5.e0',200) >>> _g.mpf(2,200) * 3 mpf('6.e0',200) >>> 3 * _g.mpf(2,200) mpf('6.e0',200) >>> _g.fsign(b-a) 1 >>> _g.fsign(b-b) 0 >>> _g.fsign(a-b) -1 >>> a.sign() 1 >>> (-a).sign() -1 >>> z=b-b; z.sign() 0 >>> import math >>> math.ceil(a) 124 >>> str(a.ceil()) '124.0' >>> str(_g.ceil(a)) '124.0' >>> math.floor(a) 123 >>> str(a.floor()) '123.0' >>> str(_g.floor(a)) '123.0' >>> str(a.trunc()) '123.0' >>> str(_g.trunc(a)) '123.0' >>> x=-a >>> math.floor(x) -124 >>> str(x.floor()) '-124.0' >>> str(_g.floor(x)) '-124.0' >>> str(x.ceil()) '-123.0' >>> math.ceil(x) -123 >>> str(_g.ceil(x)) '-123.0' >>> str(x.trunc()) '-123.0' >>> str(_g.trunc(x)) '-123.0' >>> _g.ceil(12.3)==math.ceil(12.3) 1 >>> _g.floor(12.3)==math.floor(12.3) 1 >>> _g.ceil(-12.3)==math.ceil(-12.3) 1 >>> _g.floor(-12.3)==math.floor(-12.3) 1 >>> (a**2).reldiff(float(a)**2) < 1.03 * (2.0**-(a.getrprec()-1)) 1 >>> (a**2).reldiff(a*a) < (2.0**-(a.getprec()-1)) 1 >>> (b**2).reldiff(float(b)**2) < 1.03 * (2.0**-(b.getrprec()-1)) 1 >>> (b**2).reldiff(b*b) < (2.0**-(b.getprec()-1)) 1 >>> _g.reldiff(3.4) Traceback (innermost last): File "", line 1, in ? _g.reldiff(3.4) TypeError: function takes exactly 2 arguments (1 given) >>> a.reldiff() Traceback (innermost last): File "", line 1, in ? _g.reldiff() TypeError: function takes exactly 1 argument (0 given) >>> a.reldiff(3, 4) Traceback (innermost last): File "", line 1, in ? _g.reldiff(3, 4) TypeError: function takes exactly 1 argument (2 given) >>> a.sqrt() mpf('1.11110755554986664846e1') >>> _g.fsqrt(a) mpf('1.11110755554986664846e1') >>> _g.fsqrt(-1) Traceback (most recent call last): File "", line 1, in ? File "a.py", line 9, in _er raise ValueError, what ValueError: sqrt of negative number >>> _g.pi(64) mpf('3.14159265358979323846e0',64) >>> import pickle >>> flt = _g.mpf(1234.6789) >>> flt == pickle.loads(pickle.dumps(flt)) True >>> flt = _g.mpf('1.1') >>> flt == pickle.loads(pickle.dumps(flt)) True ''' __test__['newdiv']=\ r''' >>> >>> a/b mpf('1.56447093799065544915e-1') >>> a//b mpf('0.e0') >>> b/a mpf('6.39193720839813374807e0') >>> b//a mpf('6.e0') >>> ''' __test__['cmpr']=\ r''' >>> c=_g.mpf(a) >>> c is a 1 >>> c==a 1 >>> c>a 0 >>> c>> d=a._copy() >>> a is d 0 >>> a == d 1 >>> a>b 0 >>> a>> not _g.mpf(0) 1 >>> not a 0 >>> a.f2q(0.1) mpz(123) >>> a.f2q(0.01) mpz(123) >>> a.f2q(0.001) mpq(247,2) >>> a.f2q(0.0001) mpq(1358,11) >>> a.f2q(0.00001) mpq(7037,57) >>> a.f2q(0.000001) mpq(15432,125) >>> a.f2q(0.0000001) mpq(15432,125) >>> a.f2q() mpq(15432,125) >>> print(_g.mpf(_g.mpz(1234))) 1234.0 >>> x=1000*1000*1000*1000 >>> _g.mpf(x) mpf('1.e12') >>> c=_g.mpf(a) >>> a is c 1 >>> c=_g.mpf(a,99) >>> a is c 0 >>> a==c 1 >>> _g.mpf('1.1') == _g.mpf('1.1') * _g.mpf(1) True >>> _g.mpf('1.1',64) == _g.mpf('1.1',128) False >>> _g.mpf('1.1',64) == _g.mpf(_g.mpf('1.1',128),64) True >>> a = _g.mpf('.123', 64) >>> b = _g.mpf('.123', 128) >>> c = _g.mpf('.123', 128) * _g.mpf(1, 128) >>> a == b False >>> a == c False >>> b == c True >>> a == b.round(64) True >>> a == _g.fround(b, 64) True >>> _g.mpf('ffffffffffffffffe8000000000000000', 256, 16).round(64).digits(16) 'f.fffffffffffffffe@32' >>> _g.mpf('fffffffffffffffff8000000000000000', 256, 16).round(64).digits(16) '1.@33' >>> b.round(64) mpf('1.23e-1',64) >>> ''' __test__['format']=\ r''' >>> str(a) '123.456' >>> repr(a) "mpf('1.23456e2')" >>> _g.set_tagoff(0) 1 >>> a gmpy.mpf('1.23456e2') >>> _g.set_tagoff(1) 0 >>> a.digits(10,0) '1.23456e2' >>> a.digits(10,1) '1.e2' >>> a.digits(10,2) '1.2e2' >>> a.digits(10,3) '1.23e2' >>> a.digits(10,4) '1.235e2' >>> a.digits(10,5) '1.2346e2' >>> a.digits(10,6) '1.23456e2' >>> a.digits(10,7) '1.23456e2' >>> a.digits(10,8) '1.23456e2' >>> for i in range(11,99): ... tempa='%.16f' % (i/10.0) ... tempb=_g.mpf(i/10.0).digits(10,17) ... assert tempb.startswith(tempa.rstrip('0')), (tempa, tempb) ... >>> junk=_g.set_fcoform(14) >>> frmt=_g.set_fcoform(14) >>> frmt '%.14e' >>> ofmt=_g.set_fcoform(frmt) >>> ofmt '%.14e' >>> _g.mpf(3.4) mpf('3.39999999999999999998e0') >>> print(_g.mpf(3.4)) 3.39999999999999999998 >>> _g.set_fcoform(junk) '%.14e' >>> a.digits(1) Traceback (most recent call last): File "", line 1, in ? ValueError: base must be either 0 or in the interval 2 ... 62 >>> a.digits(2,-1) Traceback (most recent call last): File "", line 1, in ? ValueError: digits must be >= 0 >>> a.digits(10,0,0,-1,2) ('123456', 3, 53) >>> saveprec=a.getrprec() >>> a.setprec(33) >>> a mpf('1.23456e2',33) >>> a.setprec(saveprec) >>> a.getrprec()==saveprec 1 >>> _g.fdigits(2.2e5, 0, 6, -10, 10) '220000.0' >>> _g.fdigits(2.2e-5, 0, 6, -10, 10) '0.000022' >>> _g.digits(_g.mpf(23.45)) Traceback (most recent call last): ... TypeError: digits() expects 'mpz',['int'] arguments >>> _g.fbinary('pep') Traceback (most recent call last): File "", line 1, in ? TypeError: argument can not be converted to mpf >>> ''' __test__['binio']=\ r''' >>> epsilon=_g.mpf(2)**-(a.getrprec()) >>> ba=a.binary() >>> a.reldiff(_g.mpf(ba,0,256)) <= epsilon 1 >>> len(ba) 18 >>> for i in range(len(ba)): ... print(ba[i]) ... 8 53 0 0 0 1 0 0 0 123 116 188 106 126 249 219 34 209 >>> na=(-a).binary() >>> (-a).reldiff(_g.mpf(na,0,256)) <= epsilon 1 >>> na[0] == ba[0]|1 1 >>> for bd,nd in zip(ba[1:],na[1:]): ... assert bd==nd >>> ia=(1/a).binary() >>> (1/a).reldiff(_g.mpf(ia,0,256)) <= epsilon 1 >>> _g.fbinary(0) b'\x04' >>> _g.mpf(_g.fbinary(0), 0, 256) == 0 1 >>> _g.fbinary(0.5) b'\x085\x00\x00\x00\x00\x00\x00\x00\x80' >>> _g.mpf(_g.fbinary(0.5), 0, 256) == 0.5 1 >>> _g.fbinary(-0.5) b'\t5\x00\x00\x00\x00\x00\x00\x00\x80' >>> _g.mpf(_g.fbinary(-0.5), 0, 256) == -0.5 1 >>> _g.fbinary(-2.0) b'\t5\x00\x00\x00\x01\x00\x00\x00\x02' >>> _g.mpf(_g.fbinary(-2.0), 0, 256) == -2.0 1 >>> _g.fbinary(2.0) b'\x085\x00\x00\x00\x01\x00\x00\x00\x02' >>> _g.mpf(_g.fbinary(2.0), 0, 256) == 2.0 1 >>> prec=_g.set_minprec(0) >>> junk=_g.set_minprec(prec) >>> a.getrprec()==prec 1 >>> b.getrprec()==prec 1 >>> _g.mpf(1.0).getrprec()==prec 1 >>> hash(_g.mpf(23.0))==hash(23) 1 >>> print(_g.mpf('\004',0,256)) 0.0 >>> int(a) 123 >>> int(-a) -123 >>> ''' def _test(chat=None): if chat: print("Unit tests for gmpy 1.17 (mpf functionality)") print(" running on Python %s" % sys.version) print() if _g.gmp_version(): print("Testing gmpy %s (GMP %s), default caching (%s, %s)" % ( (_g.version(), _g.gmp_version(), _g.get_cache()[0], _g.get_cache()[1]))) else: print("Testing gmpy %s (MPIR %s), default caching (%s, %s)" % ( (_g.version(), _g.mpir_version(), _g.get_cache()[0], _g.get_cache()[1]))) thismod = sys.modules.get(__name__) doctest.testmod(thismod, report=0) if chat: print("Repeating tests, with caching disabled") _g.set_cache(0,128) sav = sys.stdout class _Dummy: encoding=None def write(self,*whatever): pass try: sys.stdout = _Dummy() doctest.testmod(thismod, report=0) finally: sys.stdout = sav if chat: print() print("Overall results for mpf:") return doctest.master.summarize(chat) if __name__=='__main__': _test(1) gmpy-1.17/test3/gmpy_test_dec.py0000666000000000000000000000621012174774726015402 0ustar rootroot# partial unit test for gmpy/decimal interoperability # note: broken in Python 2.4.0 due to a 2.4.0 bug, please update to 2.4.1 # or better to allow decimal/most-anything-else interoperability!-) # relies on Tim Peters' "doctest.py" test-driver # Hack to remove the '__dir__' attribute introduced in Python 3.3 r''' >>> list([x for x in dir(f) if x != '__dir__']) ['__abs__', '__add__', '__bool__', '__class__', '__delattr__', '__divmod__', '__doc__', '__eq__', '__float__', '__floordiv__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__int__', '__le__', '__lt__', '__mod__', '__mul__', '__ne__', '__neg__', '__new__', '__pos__', '__pow__', '__radd__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', '__rmod__', '__rmul__', '__rpow__', '__rsub__', '__rtruediv__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__truediv__', '_copy', 'binary', 'ceil', 'digits', 'f2q', 'floor', 'getprec', 'getrprec', 'qdiv', 'reldiff', 'round', 'setprec', 'sign', 'sqrt', 'trunc'] >>> ''' try: import decimal as _d except ImportError: _d = None import gmpy as _g, doctest, sys __test__={} f=_g.mpf('123.456') q=_g.mpq('789123/1000') z=_g.mpz('234') if _d: d=_d.Decimal('12.34') fd=_d.Decimal('123.456') qd=_d.Decimal('789.123') zd=_d.Decimal('234') __test__['compat']=\ r''' >>> f == fd True >>> fd == f True >>> q == qd True >>> qd == q True >>> z == zd True >>> zd == z True >>> f > d True >>> d > f False ''' __test__['elemop']=\ r''' >>> print(_g.mpz(23) == _d.Decimal(23)) True >>> print(_g.mpz(d)) 12 >>> print(_g.mpq(d)) 617/50 >>> print(_g.mpf(d)) 12.34 >>> print(f+d) 135.796 >>> print(d+f) 135.796 >>> print(q+d) 801.463 >>> print(d+q) 801.463 >>> print(z+d) 246.34 >>> print(d+z) 246.34 >>> print(_g.ceil(d)) 13.0 >>> print(_g.floor(d)) 12.0 >>> print(_g.trunc(d)) 12.0 >>> _g.getrprec(d) 53 >>> _g.fsqrt(d)==_g.mpf(d).sqrt() 1 >>> ''' def _test(chat=None): python_version = sys.version_info[:3] if python_version == (2, 4, 0): print("You're using Python 2.4.0, which does not allow interoperability") print(" between decimal and other types (due to a bug fixed in 2.4.1)") print(" No point in testing, therefore -- please upgrade your Python!") return 0, 0 if chat: print("Unit tests for gmpy 1.17 (decimal interoperation)") print(" running on Python", sys.version) print() if _g.gmp_version(): print("Testing gmpy %s (GMP %s), default caching (%s, %s)" % ( (_g.version(), _g.gmp_version(), _g.get_cache()[0], _g.get_cache()[1]))) else: print("Testing gmpy %s (MPIR %s), default caching (%s, %s)" % ( (_g.version(), _g.mpir_version(), _g.get_cache()[0], _g.get_cache()[1]))) if not _d: if chat: print("Can't test, since can't import decimal") return 0, 0 thismod = sys.modules.get(__name__) doctest.testmod(thismod, report=0) if chat: print() print("Overall results for dec:") return doctest.master.summarize(chat) if __name__=='__main__': _test(1) gmpy-1.17/test3/gmpy_test_cvr.py0000666000000000000000000003621212174774726015446 0ustar rootroot# partial unit test for gmpy extra cover # relies on Tim Peters' "doctest.py" test-driver r''' >>> _g.gmp_version()[:3] in ('5.0', '4.3', '') True >>> _g.mpir_version()[:3] in ( '2.3', '2.4', '2.5', '') True >>> _g.version() '1.17' >>> int('gmpy.c' in _g._cvsid()) 1 ''' import gmpy as _g, doctest, sys __test__={} r = _g.rand __test__['misc_stuff']=\ r''' >>> junk=_g.set_debug(0) >>> knuj=_g.set_debug(junk) >>> junk==_g.set_debug(junk) 1 >>> _g.set_fcoform(None) >>> _g.set_fcoform() >>> print(_g.mpf(3.0)) 3.0 >>> _g.gmp_limbsize() in (32, 64) True ''' try: x = float('inf') except ValueError: pass else: __test__['infinity'] = \ r''' >>> x = float('inf') >>> n = float('nan') >>> _g.mpf(x) Traceback (most recent call last): ... ValueError: gmpy does not handle infinity >>> _g.mpf(-x) Traceback (most recent call last): ... ValueError: gmpy does not handle infinity >>> _g.mpq(x) Traceback (most recent call last): ... ValueError: gmpy does not handle infinity >>> _g.mpq(-x) Traceback (most recent call last): ... ValueError: gmpy does not handle infinity >>> _g.mpz(x) Traceback (most recent call last): ... ValueError: gmpy does not handle infinity >>> _g.mpz(-x) Traceback (most recent call last): ... ValueError: gmpy does not handle infinity >>> _g.mpf(n) Traceback (most recent call last): ... ValueError: gmpy does not handle nan >>> _g.mpf(n) Traceback (most recent call last): ... ValueError: gmpy does not handle nan >>> _g.mpf(n) Traceback (most recent call last): ... ValueError: gmpy does not handle nan ''' __test__['user_errors']=\ r''' >>> _g.version(23) Traceback (most recent call last): ... TypeError: version expects 0 arguments >>> _g.gmp_version(23) Traceback (most recent call last): ... TypeError: gmp_version expects 0 arguments >>> _g.get_cache(23) Traceback (most recent call last): ... TypeError: get_cache expects 0 arguments >>> _g.set_cache() Traceback (most recent call last): ... TypeError: function takes exactly 2 arguments (0 given) >>> _g.set_cache(200) Traceback (most recent call last): ... TypeError: function takes exactly 2 arguments (1 given) >>> _g.set_cache(200,-23) Traceback (most recent call last): ... ValueError: object size must between 0 and 16384 >>> _g.set_cache(2000,256) Traceback (most recent call last): ... ValueError: cache must between 0 and 1000 >>> _g.set_cache(-23,256) Traceback (most recent call last): ... ValueError: cache must between 0 and 1000 >>> _g.set_cache(200,256000) Traceback (most recent call last): ... ValueError: object size must between 0 and 16384 >>> _g.set_debug() Traceback (most recent call last): File "", line 1, in ? TypeError: function takes exactly 1 argument (0 given) >>> _g.set_debug(2,3) Traceback (most recent call last): File "", line 1, in ? TypeError: function takes exactly 1 argument (2 given) >>> _g.set_debug('boh') Traceback (most recent call last): File "", line 1, in ? TypeError: an integer is required >>> _g.set_minprec(-1) Traceback (most recent call last): File "", line 1, in ? ValueError: minimum precision must be >= 0 >>> _g.set_fcoform(33) Traceback (most recent call last): File "", line 1, in ? ValueError: number of digits n must be 0>> _g.set_fcoform([]) Traceback (most recent call last): File "", line 1, in ? TypeError: set_fcoform argument must be int, string, or None >>> _g.mpz('12'+chr(0)+'34') Traceback (most recent call last): File "", line 1, in ? ValueError: string without NULL characters expected >>> _g.mpf('12'+chr(0)+'34') Traceback (most recent call last): File "", line 1, in ? ValueError: string without NULL characters expected >>> _g.mpq('12'+chr(0)+'34') Traceback (most recent call last): File "", line 1, in ? ValueError: string without NULL characters expected >>> _g.mpq('bo',256) Traceback (most recent call last): File "", line 1, in ? ValueError: invalid mpq binary (too short) >>> _g.mpq('bologna',256) Traceback (most recent call last): File "", line 1, in ? ValueError: invalid mpq binary (num len) >>> _g.mpq(b'\001\000\000\000\003\002',256) mpq(3,2) >>> _g.mpq(b'\002\000\000\000\003\377\002',256) Traceback (most recent call last): File "", line 1, in ? ValueError: invalid mpq binary (num sgn) >>> _g.mpq(b'\001\000\000\000\003\002\377',256) Traceback (most recent call last): File "", line 1, in ? ValueError: invalid mpq binary (den sgn) >>> _g.mpq('ba/bo') Traceback (most recent call last): File "", line 1, in ? ValueError: invalid digits >>> print('ba/bo') ba/bo >>> _g.mpq('1/bo') Traceback (most recent call last): File "", line 1, in ? ValueError: invalid digits >>> print('1/bo') 1/bo >>> _g.mpq('1/0') Traceback (most recent call last): File "", line 1, in ? ZeroDivisionError: mpq: zero denominator >>> _g.mpf([]) Traceback (most recent call last): File "", line 1, in ? TypeError: gmpy.mpf() expects numeric or string argument >>> _g.mpf('bo',0,256) Traceback (most recent call last): File "", line 1, in ? ValueError: string too short to be a gmpy.mpf binary encoding >>> _g.mpf('bo') Traceback (most recent call last): File "", line 1, in ? ValueError: invalid digits >>> int(_g.mpz(1000*1000*1000*1000*1000*1000*1000)) 1000000000000000000000 >>> _g.scan0(12,-1) Traceback (most recent call last): File "", line 1, in ? ValueError: starting bit must be >= 0 >>> _g.scan1(12,-1) Traceback (most recent call last): File "", line 1, in ? ValueError: starting bit must be >= 0 >>> _g.lowbits(12,-1) Traceback (most recent call last): File "", line 1, in ? ValueError: nbits must be > 0 >>> _g.getbit(12,-1) Traceback (most recent call last): File "", line 1, in ? ValueError: bit_index must be >= 0 >>> _g.setbit(12,-1) Traceback (most recent call last): File "", line 1, in ? ValueError: bit_index must be >= 0 >>> _g.mpz(23).setbit(12,1,2,3) Traceback (most recent call last): ... TypeError: setbit() expects 'mpz','int'[,'int'] arguments >>> _g.setbit(12,1,2,3) Traceback (most recent call last): ... TypeError: setbit() expects 'mpz','int'[,'int'] arguments >>> _g.root(12,-1) Traceback (most recent call last): File "", line 1, in ? ValueError: n must be > 0 >>> _g.root(12,0) Traceback (most recent call last): File "", line 1, in ? ValueError: n must be > 0 >>> _g.root(-12,2) Traceback (most recent call last): File "", line 1, in ? ValueError: root of negative number >>> _g.digits(3,'peep') Traceback (most recent call last): ... TypeError: digits() expects 'mpz',['int'] arguments >>> _g.digits(3.14) Traceback (most recent call last): ... TypeError: digits() expects 'mpz',['int'] arguments >>> _g.fdigits(3.14,'peep') Traceback (most recent call last): File "", line 1, in ? TypeError: an integer is required >>> _g.qdigits(3.14) Traceback (most recent call last): File "", line 1, in ? TypeError: argument can not be converted to mpq >>> _g.qdigits(3,'peep') Traceback (most recent call last): File "", line 1, in ? TypeError: an integer is required >>> _g.mpz(3).digits('bu') Traceback (most recent call last): ... TypeError: digits() expects 'mpz',['int'] arguments >>> _g.mpf(3).digits('bu') Traceback (most recent call last): File "", line 1, in ? TypeError: an integer is required >>> _g.qdiv(3,_g.mpq(1)) mpz(3) >>> _g.qdiv(3,_g.mpz(1)) mpz(3) >>> _g.qdiv(3,_g.mpf(1)) mpz(3) >>> _g.qdiv(3,1.0) mpz(3) >>> _g.qdiv(3,1) mpz(3) >>> _g.qdiv(3) mpz(3) >>> _g.qdiv(3,'bu') Traceback (most recent call last): File "", line 1, in ? TypeError: second argument can not be converted to mpq >>> _g.mpq(2).qdiv(3,4) Traceback (most recent call last): File "", line 1, in ? TypeError: function takes at most 1 argument (2 given) >>> _g.qdiv(3,4,5) Traceback (most recent call last): File "", line 1, in ? TypeError: function takes at most 2 arguments (3 given) >>> _g.qdiv('bu') Traceback (most recent call last): File "", line 1, in ? TypeError: first argument can not be converted to mpq >>> _g.qdiv(1.0,1) Traceback (most recent call last): File "", line 1, in ? TypeError: first argument can not be converted to mpq >>> _g.qdiv(1,0) Traceback (most recent call last): File "", line 1, in ? ZeroDivisionError: qdiv: zero divisor >>> _g.f2q(-1.0) mpz(-1) >>> _g.mpz(1,2,3) Traceback (most recent call last): File "", line 1, in ? TypeError: gmpy.mpz() requires 1 or 2 arguments >>> _g.mpz('bi','bo') Traceback (most recent call last): File "", line 1, in ? TypeError: gmpy.mpz(): base must be an integer >>> _g.mpz('bi',99) Traceback (most recent call last): File "", line 1, in ? ValueError: base for gmpy.mpz must be 0, 256, or in the interval 2 ... 62 . >>> _g.mpz(1,2) Traceback (most recent call last): File "", line 1, in ? TypeError: gmpy.mpz() with numeric argument needs exactly 1 argument >>> _g.mpz(None) Traceback (most recent call last): File "", line 1, in ? TypeError: gmpy.mpz() expects numeric or string argument >>> _g.mpq(1,2,3) Traceback (most recent call last): File "", line 1, in ? TypeError: gmpy.mpq() requires 1 or 2 arguments >>> _g.mpq('bi','bo') Traceback (most recent call last): File "", line 1, in ? TypeError: gmpy.mpq(): base must be an integer >>> _g.mpq('bi',99) Traceback (most recent call last): File "", line 1, in ? ValueError: base for gmpy.mpq() must be 0, 256, or in the interval 2 ... 36 . >>> _g.mpq(None) Traceback (most recent call last): File "", line 1, in ? TypeError: gmpy.mpq() expects numeric or string argument >>> _g.mpq(1,None) Traceback (most recent call last): File "", line 1, in ? TypeError: argument can not be converted to mpq >>> _g.mpq(1,0) Traceback (most recent call last): File "", line 1, in ? ZeroDivisionError: mpq: zero denominator >>> _g.mpf() Traceback (most recent call last): File "", line 1, in ? TypeError: gmpy.mpf() requires 1 to 3 arguments >>> _g.mpf(1,'bo') Traceback (most recent call last): File "", line 1, in ? TypeError: gmpy.mpf(): bits must be an integer >>> _g.mpf(1,-1) Traceback (most recent call last): File "", line 1, in ? ValueError: bits for gmpy.mpf must be >= 0 >>> _g.mpf('ba',0,'bu') Traceback (most recent call last): File "", line 1, in ? TypeError: gmpy.mpf(): base must be an integer >>> _g.mpf('ba',0,99) Traceback (most recent call last): File "", line 1, in ? ValueError: base for gmpy.mpf must be 0, 256, or in the interval 2 ... 62 . >>> _g.mpf(1,2,3) Traceback (most recent call last): File "", line 1, in ? TypeError: gmpy.mpf() with numeric 1st argument needs 1 or 2 arguments >>> +_g.mpz(1) mpz(1) >>> +_g.mpf(1) mpf('1.e0') >>> +_g.mpq(1) mpq(1,1) >>> _g.mpz(2)**-2 Traceback (most recent call last): File "", line 1, in ? ValueError: mpz.pow with negative power >>> _g.mpz(2)**_g.mpz(1000000*10000000000000) Traceback (most recent call last): File "", line 1, in ? ValueError: mpz.pow outrageous exponent >>> pow(_g.mpz(2),3,0) Traceback (most recent call last): File "", line 1, in ? ValueError: mpz.pow divide by zero >>> pow(_g.mpz(2),3,-5) mpz(-2) >>> pow(_g.mpq(2),3,-5) Traceback (most recent call last): File "", line 1, in ? ValueError: mpq.pow no modulo allowed >>> a=10000000000**2 >>> _g.mpq(2)**a Traceback (most recent call last): File "", line 1, in ? ValueError: mpq.pow outrageous exp num >>> _g.mpq(2)**_g.mpq(1,a) Traceback (most recent call last): File "", line 1, in ? ValueError: mpq.pow outrageous exp den >>> _g.mpq(2)**0 mpq(1,1) >>> _g.mpq(2)**-1 mpq(1,2) >>> _g.mpq(2)**_g.mpq(1,2) Traceback (most recent call last): File "", line 1, in ? ValueError: mpq.pow fractional exponent, inexact-root >>> _g.mpq(-2)**_g.mpq(1,2) Traceback (most recent call last): File "", line 1, in ? ValueError: mpq.pow fractional exponent, nonreal-root >>> _g.mpq(0)**_g.mpq(1,2) mpq(0,1) >>> _g.mpq(0)**-1 Traceback (most recent call last): File "", line 1, in ? ZeroDivisionError: mpq.pow 0 base to <0 exponent >>> _g.mpq(-1)**-1 mpq(-1,1) >>> _g.mpf(9,100)**2 mpf('8.1e1',100) >>> _g.mpf(9,100)**0.5 mpf('3.e0',100) >>> _g.mpf(9,100)**_g.mpf(0.5) mpf('3.e0') >>> _g.mpf(0)**2 mpf('0.e0') >>> pow(_g.mpf(2),3,-5) Traceback (most recent call last): File "", line 1, in ? ValueError: mpf.pow no modulo allowed >>> _g.mpz(1)+'bu' Traceback (most recent call last): File "", line 1, in ? TypeError: unsupported operand type(s) for +: 'mpz' and 'str' >>> _g.mpz(1)+_g.mpf(1) mpf('2.e0') >>> _g.mpz(1)+_g.mpq(1) mpq(2,1) >>> _g.mpq(1)+'bu' Traceback (most recent call last): File "", line 1, in ? TypeError: unsupported operand type(s) for +: 'mpq' and 'str' >>> _g.mpf(1)+'bu' Traceback (most recent call last): File "", line 1, in ? TypeError: unsupported operand type(s) for +: 'mpf' and 'str' >>> _g.mpf(1)+_g.mpq(2) mpf('3.e0') >>> divmod(_g.mpz(3),0) Traceback (most recent call last): File "", line 1, in ? ZeroDivisionError: mpz divmod by zero >>> divmod(_g.mpz(0),3) (mpz(0), mpz(0)) >>> _g.divm(1,2,0) Traceback (most recent call last): File "", line 1, in ? ZeroDivisionError: not invertible >>> abs(_g.mpq(0)) mpq(0,1) >>> _g.mpz(0)**2 mpz(0) >>> _g.mpq(-2)**0 mpq(1,1) >>> _g.fac(-1) Traceback (most recent call last): File "", line 1, in ? ValueError: factorial of negative number >>> _g.fib(-1) Traceback (most recent call last): File "", line 1, in ? ValueError: Fibonacci of negative number >>> _g.comb(7,-3) Traceback (most recent call last): File "", line 1, in ? ValueError: binomial coefficient with negative k >>> _g.sqrt(-1) Traceback (most recent call last): File "", line 1, in ? ValueError: sqrt of negative number >>> _g.sqrtrem(-1) Traceback (most recent call last): File "", line 1, in ? ValueError: sqrt of negative number >>> _g.fsqrt(-1) Traceback (most recent call last): File "", line 1, in ? ValueError: sqrt of negative number >>> _g.jacobi(23, -34) Traceback (most recent call last): ... ValueError: jacobi's y must be odd prime > 0 >>> _g.legendre(23, -34) Traceback (most recent call last): ... ValueError: legendre's y must be odd and > 0 >>> # guard against conversion error on 64-bit systems >>> _g.mpz(2**32) != _g.mpz(0) True >>> # test hash properties on 64-bit systems >>> temp = 123456789012345678901234567890 >>> hash(temp) == hash(_g.mpz(temp)) True >>> del temp ''' def _test(chat=None): if chat: print("Unit tests for gmpy 1.17 (extra cover)") print(" running on Python", sys.version) print() if _g.gmp_version(): print("Testing gmpy %s (GMP %s), default caching (%s, %s)" % ( (_g.version(), _g.gmp_version(), _g.get_cache()[0], _g.get_cache()[1]))) else: print("Testing gmpy %s (MPIR %s), default caching (%s, %s)" % ( (_g.version(), _g.mpir_version(), _g.get_cache()[0], _g.get_cache()[1]))) print(__test__.keys()) thismod = sys.modules.get(__name__) doctest.testmod(thismod, report=0) if chat: print() print("Overall results for cvr:") return doctest.master.summarize(chat) if __name__=='__main__': _test(1) gmpy-1.17/test3/gmpy_test.py0000666000000000000000000000240412174774726014570 0ustar rootrootr''' >>> gmpy.version() '1.17' >>> ''' import sys import doctest import gmpy if sys.argv[-1] == 'debug': gmpy.set_debug(1) import gmpy_test_cvr import gmpy_test_rnd import gmpy_test_mpf import gmpy_test_mpq import gmpy_test_mpz import gmpy_test_dec test_modules = (gmpy_test_cvr, gmpy_test_rnd, gmpy_test_mpf, gmpy_test_mpq, gmpy_test_mpz, gmpy_test_dec) _g = gmpy print("Unit tests for gmpy 1.17") print(" on Python %s" % sys.version) if _g.gmp_version(): print("Testing gmpy %s (GMP %s), default caching (%s, %s)" % ( (_g.version(), _g.gmp_version(), _g.get_cache()[0], _g.get_cache()[1]))) else: print("Testing gmpy %s (MPIR %s), default caching (%s, %s)" % ( (_g.version(), _g.mpir_version(), _g.get_cache()[0], _g.get_cache()[1]))) pf, pt = 0, 0 for x in test_modules: testit = x._test() failures, tests = testit if tests == 0: continue print("%s %3d tests, %d failures" % (x.__name__, tests-pt, failures-pf)) pf, pt = failures, tests doctest.master.summarize(1) if sys.version_info < (3,1,1): print("There is a known bug with Fraction == mpq for versions of Python") print("less than 3.1.1. Please upgrade if you rely on comparisons between") print("Python's Fraction and gmpy's mpq.") gmpy-1.17/test/0000755000000000000000000000000012543053022012067 5ustar rootrootgmpy-1.17/test/timing3.py0000666000000000000000000000147012174774720014040 0ustar rootrootimport gmpy as _g import time print "Typical expected results would be:",""" D:\PySym>python timing.py Factorial of 10000 took 0.0619989238859 (35660 digits) Fibonacci of 10000 took 0.000744228458022 (2090 digits) Factorial of 100000 took 4.44311764676 (456574 digits) Fibonacci of 100000 took 0.022344453738 (20899 digits) Factorial of 1000000 took 152.151135367 (5565709 digits) Fibonacci of 1000000 took 0.670207059778 (208988 digits) """ print "Actual timings and results...:" for i in (10000,100000,1000000): start=time.clock() x=_g.fac(i) stend=time.clock() print "Factorial of %d took %s (%d digits)" % ( i, stend-start, x.numdigits()) start=time.clock() x=_g.fib(i) stend=time.clock() print "Fibonacci of %d took %s (%d digits)" % ( i, stend-start, x.numdigits()) gmpy-1.17/test/timing2.py0000666000000000000000000000127312174774720014040 0ustar rootrootimport gmpy, time def timedfib(n, zero): start=time.clock() a=zero; b=a+1 for i in range(n): a,b=b,a+b stend=time.clock() return type(zero), stend-start, a def timedfibsp(n, one): start=time.clock() result=gmpy.fib(n) stend=time.clock() return type(one), stend-start, result def test(n=100*1000): print "%dth Fibonacci number of various types:" % n for z in 0L, gmpy.mpz(0), gmpy.mpf(0): tip, tim, tot = timedfib(n, z) print " %5.3f %s %s" % (tim, gmpy.fdigits(tot,10,6), tip) tip, tim, tot = timedfibsp(n, 1) print " %5.3f %s %s" % (tim, gmpy.fdigits(tot,10,6), "gmpy.fib") if __name__=='__main__': test() gmpy-1.17/test/timing1.py0000666000000000000000000000231412174774720014034 0ustar rootrootimport gmpy, time try: sum except NameError: def sum(x, z): for item in x: z += item return z def timedsum(n, zero): start=time.clock() tot=zero for i in range(n): tot+=i stend=time.clock() return type(zero), stend-start, tot def timedsum1(n, zero): start=time.clock() tot=sum(range(n), zero) stend=time.clock() return type(zero), stend-start, tot def timedmul(n, one): start=time.clock() tot=one for i in range(n): tot*=(i+1) stend=time.clock() return type(one), stend-start, tot def test(n=100*1000): print "Sum of %d items of various types:" % n for z in 0L, 0.0, gmpy.mpz(0), gmpy.mpf(0): tip, tim, tot = timedsum(n, z) print " %5.3f %.0f %s" % (tim, float(tot), tip) print "Sum of %d items of various types w/2.3 sum builtin:" % n for z in 0L, 0.0, gmpy.mpz(0), gmpy.mpf(0): tip, tim, tot = timedsum1(n, z) print " %5.3f %.0f %s" % (tim, float(tot), tip) print "Mul of %d items of various types:" % (n//5) for z in 1L, 1.0, gmpy.mpz(1), gmpy.mpf(1): tip, tim, tot = timedmul(n//5, z) print " %5.3f %s" % (tim, tip) if __name__=='__main__': test() gmpy-1.17/test/test_mpz_args.py0000666000000000000000000000361712174774720015354 0ustar rootroot# Test a wide variety of input values to the commonly used mpz operations. # This test should be run whenever optimizations are made to the handling of # arguments. import sys import gmpy if sys.version.startswith('3'): intTypes = (int,) else: intTypes = (int, long) def writeln(s): sys.stdout.write(s+'\n') valueList = [0, 1, 2, 3, 4, 5] for power in (15, 16, 30, 32, 45, 48, 60, 64, 75, 90, 96, 105, 120, 128): for i in (-2, -1, 0, 1, 2): valueList.append(2**power + i) valueList.append('123456789012345678901234567890') valueList.append('10000000000000000000000000000000000000000000000000000000000000000') testValues = [] mpzValues = [] for i in valueList: for t in intTypes: testValues.append(t(i)) testValues.append(-t(i)) mpzValues.append(gmpy.mpz(i)) mpzValues.append(-gmpy.mpz(i)) testValues.extend(mpzValues) for i in testValues: for z in mpzValues: # Test all permutations of addition assert int(i)+int(z) == i+z, (repr(i),repr(z)) assert int(z)+int(i) == z+i, (repr(i),repr(z)) # Test all permutations of subtraction assert int(i)-int(z) == i-z, (repr(i),repr(z)) assert int(z)-int(i) == z-i, (repr(i),repr(z)) # Test all permutations of multiplication assert int(i)*int(z) == i*z, (repr(i),repr(z)) assert int(z)*int(i) == z*i, (repr(i),repr(z)) # Test all permutations of division if z!=0: temp = int(i)//int(z) assert int(i)//int(z) == i//z, (repr(i),repr(z)) assert int(i)%int(z) == i%z, (repr(i),repr(z)) assert divmod(int(i),int(z)) == divmod(i,z), (repr(i),repr(z)) if i!=0: temp = int(z)//int(i) assert int(z)//int(i) == z//i, (repr(i),repr(z)) assert int(z)%int(i) == z%i, (repr(i),repr(z)) assert divmod(int(z),int(i)) == divmod(z,i), (repr(i),repr(z)) gmpy-1.17/test/test_large.py0000666000000000000000000000156312174774720014622 0ustar rootrootfrom gmpy import * from math import log from time import time # This test is designed to detect issues when allocating memory for large # numbers. If it crashes and you need to work with very large numbers, # you will need to compile GMP from scratch and try a different memory # allocation option. def pi(N): print "Computing pi to %s decimal places." % N start = time() N = int(round(log(10,2)*N)) sq2 = fsqrt(mpf(2, N)) a = mpz(6) - 4*sq2 y = sq2-1 for k in range(0, 10000): xx = fsqrt(fsqrt(1-y**4)) y = (1-xx)/(1+xx) anew = a*(1+y)**4 - 2**(2*k+3)*y*(1+y+y**2) if anew == a: break a = anew print "Computation took %5.2f seconds." % (time() - start) return 1/a if __name__ == '__main__': print "Testing operations with large numbers." pi(1000000) gmpy-1.17/test/gmpy_truediv.py0000666000000000000000000000017612174774720015206 0ustar rootroot''' make a "true division" function available for testing ''' from __future__ import division def truediv(a, b): return a/b gmpy-1.17/test/gmpy_test_thr.py0000666000000000000000000000674712174774720015372 0ustar rootroot# partial unit test for gmpy threaded mpz functionality # relies on Tim Peters' "doctest.py" test-driver import gmpy as _g, doctest, sys, operator, gc, Queue, threading __test__={} def _tf(N=2, _K=1234**5678): """Takes about 100ms on a first-generation Macbook Pro""" for i in range(N): assert (_g.mpz(1234)**5678)==_K a=_g.mpz(123) b=_g.mpz(456) c=_g.mpz(123456789123456789) def factorize(x=c): r''' (Takes about 25ms, on c, on a first-generation Macbook Pro) >>> factorize(a) [3, 41] >>> factorize(b) [2, 2, 2, 3, 19] >>> ''' import gmpy as _g savex=x prime=2 x=_g.mpz(x) factors=[] while x>=prime: newx,mult=x.remove(prime) if mult: factors.extend([int(prime)]*mult) x=newx prime=_g.next_prime(prime) for factor in factors: assert _g.is_prime(factor) from operator import mul assert reduce(mul, factors)==savex return factors def elemop(N=1000): r''' (Takes about 40ms on a first-generation Macbook Pro) ''' for i in range(N): assert a+b == 579 assert a-b == -333 assert b*a == a*b == 56088 assert b%a == 87 assert divmod(a, b) == (0, 123) assert divmod(b, a) == (3, 87) assert -a == -123 assert pow(a, 10) == 792594609605189126649 assert pow(a, 7, b) == 99 assert cmp(a, b) == -1 assert '7' in str(c) assert '0' not in str(c) assert a.sqrt() == 11 assert _g.lcm(a, b) == 18696 assert _g.fac(7) == 5040 assert _g.fib(17) == 1597 assert _g.divm(b, a, 20) == 12 assert _g.divm(4, 8, 20) == 3 assert _g.divm(4, 8, 20) == 3 assert _g.mpz(20) == 20 assert _g.mpz(8) == 8 assert _g.mpz(4) == 4 assert a.invert(100) == 87 def _test(chat=None): if chat: print "Unit tests for gmpy 1.17 (threading)" print " running on Python", sys.version print if _g.gmp_version(): print "Testing gmpy %s (GMP %s) with default caching (%s, %s)" % ( (_g.version(), _g.gmp_version(), _g.get_cache()[0], _g.get_cache()[1])) else: print "Testing gmpy %s (MPIR %s) with default caching (%s, %s)" % ( (_g.version(), _g.mpir_version(), _g.get_cache()[0], _g.get_cache()[1])) thismod = sys.modules.get(__name__) doctest.testmod(thismod, report=0) if chat: print "Repeating tests, with caching disabled" _g.set_zcache(0) sav = sys.stdout class _Dummy: def write(self,*whatever): pass try: sys.stdout = _Dummy() doctest.testmod(thismod, report=0) finally: sys.stdout = sav if chat: print print "Overall results for thr:" return doctest.master.summarize(chat) class DoOne(threading.Thread): def __init__(self, q): threading.Thread.__init__(self) self.q = q def run(self): while True: task = self.q.get() if task is None: break task() def _test_thr(Ntasks=5, Nthreads=1): q = Queue.Queue() funcs = (_tf, 1), (factorize, 4), (elemop, 2) for i in range(Ntasks): for f, n in funcs: for x in range(n): q.put(f) for i in range(Nthreads): q.put(None) thrs = [DoOne(q) for i in range(Nthreads)] for t in thrs: t.start() for t in thrs: t.join() if __name__=='__main__': _test(1) gmpy-1.17/test/gmpy_test_rnd.py0000666000000000000000000000560412174774720015347 0ustar rootroot# partial unit test for gmpy rand functionality # relies on Tim Peters' "doctest.py" test-driver r''' >>> r >>> ''' import gmpy as _g, doctest,sys __test__={} r = _g.rand __test__['rand']=\ r''' >>> r('error',1,2,3) Traceback (most recent call last): ... TypeError: function takes exactly 2 arguments (4 given) >>> r('save') Traceback (most recent call last): ... RuntimeError: can't save before init >>> r('init',20) >>> r('unkn',99) Traceback (most recent call last): ... ValueError: unknown option 'unkn' >>> r('seed',1234) >>> for i in range(5): ... print r('next',100), ... if i==4: print ... 21 75 63 28 27 >>> alis=list("proktelnu") >>> for i in range(10): ... r('shuf',alis) ... print ''.join(alis) ... rtoulpnke eoturlknp plnuetokr ekoprulnt kpoutnrel rutoneklp ukeptnorl onkrlpteu lknteropu enrkutlpo >>> sav=r('save') >>> print sav 774447212137 >>> for i in range(5): ... r('shuf',alis) ... print ''.join(alis) ... elnuortpk enutolpkr eropulntk plroutenk ekonrtplu >>> r('seed',sav) >>> for i in range(5): ... r('shuf',alis) ... print ''.join(alis) ... epkruotln ekrtuplno eoulrpktn lpourtekn enukotlpr >>> r('seed',sav) >>> for i in range(3): ... print float(r('floa')) ... 0.44833278656 0.547296524048 0.895370483398 >>> r('seed',sav) >>> for i in range(3): ... print float(r('floa',6)) ... 0.484375 0.90625 0.75 >>> r('seed',sav) >>> for i in range(3): ... print _g.f2q(r('floa',6),-6) ... 15/31 9/10 3/4 >>> r('seed',sav) >>> for i in range(3): ... print _g.f2q(r('floa',6)) ... 31/64 29/32 3/4 >>> r('seed',sav) >>> for i in range(5): ... r('shuf',alis) ... print ''.join(alis) ... elnorutpk enotrlpku eurpolntk plurotenk ekrnutplo >>> try: r('shuf','astring') ... except TypeError, e: print int("does not support item assignment" in str(e)) 1 >>> r('shuf',23) Traceback (most recent call last): ... TypeError: 'shuf' needs mutable sequence >>> ''' # adapt to python 2.3's slightly different error message in an exception import sys if sys.version<'2.4': __test__['rand'] = __test__['rand'].replace("does not", "doesn't") def _test(chat=None): if chat: print "Unit tests for gmpy 1.17 (rnd functionality)" print " running on Python %s" % sys.version print if _g.gmp_version(): print "Testing gmpy %s (GMP %s) with default caching (%s, %s)" % ( (_g.version(), _g.gmp_version(), _g.get_cache()[0], _g.get_cache()[1])) else: print "Testing gmpy %s (MPIR %s) with default caching (%s, %s)" % ( (_g.version(), _g.mpir_version(), _g.get_cache()[0], _g.get_cache()[1])) thismod = sys.modules.get(__name__) doctest.testmod(thismod, report=0) if chat: print print "Overall results for rnd:" return doctest.master.summarize(chat) if __name__=='__main__': _test(1) gmpy-1.17/test/gmpy_test_mpz.py0000666000000000000000000004432612174774720015376 0ustar rootroot# partial unit test for gmpy mpz functionality # relies on Tim Peters' "doctest.py" test-driver r''' >>> filter(lambda x: not x.startswith('_'), dir(_g)) ['binary', 'bincoef', 'bit_length', 'cdivmod', 'ceil', 'comb', 'denom', 'digits', 'divexact', 'divm', 'f2q', 'fac', 'fbinary', 'fdigits', 'fdivmod', 'fib', 'floor', 'fround', 'fsign', 'fsqrt', 'gcd', 'gcdext', 'get_cache', 'getbit', 'getprec', 'getrprec', 'gmp_limbsize', 'gmp_version', 'hamdist', 'invert', 'is_power', 'is_prime', 'is_square', 'jacobi', 'kronecker', 'lcm', 'legendre', 'license', 'lowbits', 'mpf', 'mpir_version', 'mpq', 'mpz', 'next_prime', 'numdigits', 'numer', 'pi', 'popcount', 'qbinary', 'qdigits', 'qdiv', 'qsign', 'rand', 'reldiff', 'remove', 'root', 'scan0', 'scan1', 'set_cache', 'set_debug', 'set_fcoform', 'set_minprec', 'set_tagoff', 'setbit', 'sign', 'sqrt', 'sqrtrem', 'tdivmod', 'trunc', 'version'] >>> filter(lambda x: not x.startswith('__'), dir(a)) ['_copy', 'binary', 'bincoef', 'bit_length', 'comb', 'digits', 'getbit', 'hamdist', 'invert', 'is_power', 'is_prime', 'is_square', 'jacobi', 'kronecker', 'legendre', 'lowbits', 'next_prime', 'numdigits', 'popcount', 'qdiv', 'remove', 'root', 'scan0', 'scan1', 'setbit', 'sign', 'sqrt', 'sqrtrem'] >>> ''' import warnings warnings.filterwarnings('ignore', 'setprec') import gmpy as _g, doctest, sys, operator, gc __test__={} a=_g.mpz(123) b=_g.mpz(456) # Disable tests since they are not reliable with Python 3.1 but left behind # in case it is needed in the future. if sys.platform in ('__DISABLE__linux2', '__DISABLE__darwin'): def _memsize(): """ this function tries to return a measurement of how much memory this process is consuming (if it doesn't manage to, it returns 0). """ import os try: x = int(os.popen('ps -p %d -o vsz|tail -1' % os.getpid()).read()) except: x = 0 return x else: def _memsize(): return 0 def factorize(x): r''' >>> factorize(a) [3, 41] >>> factorize(b) [2, 2, 2, 3, 19] >>> ''' import gmpy as _g savex=x prime=2 x=_g.mpz(x) factors=[] while x>=prime: newx,mult=x.remove(prime) if mult: factors.extend([int(prime)]*mult) x=newx prime=_g.next_prime(prime) for factor in factors: assert _g.is_prime(factor) from operator import mul assert reduce(mul, factors)==savex return factors if sys.version[:3] >= '2.5': __test__['index']=\ r''' >>> range(333)[a] 123 >>> range(333)[b] Traceback (innermost last): ... IndexError: list index out of range >>> ix = operator.index >>> ix(_g.mpz(sys.maxint)) == sys.maxint True >>> type(ix(_g.mpz(sys.maxint))) is int True >>> ix(_g.mpz(sys.maxint+1)) == sys.maxint+1 True >>> type(ix(_g.mpz(sys.maxint+1))) is long True ''' __test__['elemop']=\ r''' >>> a+b mpz(579) >>> a-b mpz(-333) >>> a*b mpz(56088) >>> a/b mpz(0) >>> a%b mpz(123) >>> 0%b mpz(0) >>> b+a mpz(579) >>> b-a mpz(333) >>> b*a mpz(56088) >>> b%a mpz(87) >>> divmod(a,b) (mpz(0), mpz(123)) >>> divmod(b,a) (mpz(3), mpz(87)) >>> divmod(0,b) (mpz(0), mpz(0)) >>> -a mpz(-123) >>> a+1 mpz(124) >>> a+(-1) mpz(122) >>> (-1)+a mpz(122) >>> 1+a mpz(124) >>> a-1 mpz(122) >>> a-(-1) mpz(124) >>> 1-a mpz(-122) >>> (-1)-a mpz(-124) >>> a+True mpz(124) >>> a+False mpz(123) >>> a*False mpz(0) >>> a//True mpz(123) >>> abs(-a)==a 1 >>> pow(a,10) mpz(792594609605189126649L) >>> pow(a,7,b) mpz(99) >>> _g.sign(b-a) 1 >>> _g.sign(b-b) 0 >>> _g.sign(a-b) -1 >>> a.sign() 1 >>> (-a).sign() -1 >>> z=b-b; z.sign() 0 >>> _g.mpz(4)**(0.5) mpf('2.e0') >>> import pickle >>> pickle.loads(pickle.dumps(_g.mpz(12346789))) mpz(12346789) >>> s='12345678901234567890123456789' >>> int(s) == _g.mpz(s) True >>> _g.mpz(s) == int(s) True >>> del s ''' from gmpy_truediv import truediv __test__['newdiv']=\ r''' >>> a/b mpz(0) >>> a//b mpz(0) >>> truediv(a,b) mpf('2.69736842105263157895e-1') >>> b/a mpz(3) >>> b//a mpz(3) >>> truediv(b,a) mpf('3.70731707317073170732e0') >>> ''' __test__['divexact']=\ r''' >>> a=_g.mpz('1234567912345678912345679') >>> b=_g.mpz('789789789789789789789789') >>> c=a*b >>> _g.divexact(c,a) mpz(789789789789789789789789L) >>> _g.divexact(10,0) Traceback (most recent call last): ... ZeroDivisionError: divexact() division by 0 >>> ''' __test__['divmod']=\ r''' >>> _g.cdivmod(17,5) (mpz(4), mpz(-3)) >>> _g.cdivmod(-17,5) (mpz(-3), mpz(-2)) >>> _g.cdivmod(17,-5) (mpz(-3), mpz(2)) >>> _g.cdivmod(-17,-5) (mpz(4), mpz(3)) >>> _g.fdivmod(17,5) (mpz(3), mpz(2)) >>> _g.fdivmod(-17,5) (mpz(-4), mpz(3)) >>> _g.fdivmod(17,-5) (mpz(-4), mpz(-3)) >>> _g.fdivmod(-17,-5) (mpz(3), mpz(-2)) >>> _g.tdivmod(17,5) (mpz(3), mpz(2)) >>> _g.tdivmod(-17,5) (mpz(-3), mpz(-2)) >>> _g.tdivmod(17,-5) (mpz(-3), mpz(2)) >>> _g.tdivmod(-17,-5) (mpz(3), mpz(-2)) >>> _g.cdivmod(10,0) Traceback (most recent call last): ... ZeroDivisionError: cdivmod() division by 0 >>> _g.fdivmod(10,0) Traceback (most recent call last): ... ZeroDivisionError: fdivmod() division by 0 >>> _g.tdivmod(10,0) Traceback (most recent call last): ... ZeroDivisionError: tdivmod() division by 0 ''' __test__['cmpr']=\ r''' >>> c=_g.mpz(a) >>> c is a 1 >>> c==a 1 >>> c>a 0 >>> c>> d=a._copy() >>> a is d 0 >>> a == d 1 >>> cmp(a,c) 0 >>> cmp(a,b) -1 >>> a>b 0 >>> a>> not _g.mpz(0) 1 >>> not a 0 >>> _g.mpz(1) == None False >>> _g.mpz(1) == '1' False >>> _g.mpz(1) == 'abc' False >>> [_g.mpz(23), None].count(None) 1 >>> _g.mpz(3.14) mpz(3) >>> _g.mpz(_g.mpq(17,3)) mpz(5) >>> _g.mpz(23L) mpz(23) >>> _g.mpz(-23L) mpz(-23) >>> x=1000L*1000*1000*1000*1000*1000*1000 >>> _g.mpz(x) mpz(1000000000000000000000L) >>> try: print cmp(_g.mpz(1), _g.mpz(-1)) ... except: print 'ouch!' 1 ''' __test__['special'] = \ r''' >>> a == float('Inf') False >>> a != float('Inf') True >>> a > float('Inf') False >>> a >= float('Inf') False >>> a < float('Inf') True >>> a <= float('Inf') True >>> a == float('-Inf') False >>> a != float('-Inf') True >>> a > float('-Inf') True >>> a >= float('-Inf') True >>> a < float('-Inf') False >>> a <= float('-Inf') False >>> a == float('nan') False >>> a != float('nan') True >>> a > float('nan') False >>> a >= float('nan') False >>> a < float('nan') False >>> a <= float('nan') False >>> float('Inf') == a False >>> float('Inf') != a True >>> float('Inf') > a True >>> float('Inf') >= a True >>> float('Inf') < a False >>> float('Inf') <= a False >>> float('-Inf') == a False >>> float('-Inf') != a True >>> float('-Inf') > a False >>> float('-Inf') >= a False >>> float('-Inf') < a True >>> float('-Inf') <= a True >>> float('nan') == a False >>> float('nan') != a True >>> float('nan') > a False >>> float('nan') >= a False >>> float('nan') < a False >>> float('nan') <= a False >>> a + float('Inf') inf >>> float('Inf') + a inf >>> a + float('-Inf') -inf >>> float('-Inf') + a -inf >>> a + float('nan') nan >>> float('nan') + a nan >>> a - float('Inf') -inf >>> float('Inf') - a inf >>> a - float('-Inf') inf >>> float('-Inf') - a -inf >>> a - float('nan') nan >>> float('nan') - a nan >>> a * float('Inf') inf >>> float('Inf') * a inf >>> a * float('-Inf') -inf >>> float('-Inf') * a -inf >>> -a * float('Inf') -inf >>> float('Inf') * -a -inf >>> -a * float('-Inf') inf >>> float('-Inf') * -a inf >>> a * float('nan') nan >>> float('nan') * a nan >>> _g.mpz(0) * float('Inf') nan >>> _g.mpz(0) * float('-Inf') nan >>> float('Inf') * _g.mpz(0) nan >>> float('-Inf') * _g.mpz(0) nan >>> a / float('Inf') mpf('0.e0') >>> -a / float('Inf') mpf('0.e0') >>> float('Inf') / a inf >>> float('Inf') / -a -inf >>> a / float('-Inf') mpf('0.e0') >>> -a / float('-Inf') mpf('0.e0') >>> float('-Inf') / a -inf >>> float('-Inf') / -a inf >>> a / float('nan') nan >>> float('nan') / a nan >>> float('nan') / _g.mpz(0) Traceback (most recent call last): ... ZeroDivisionError: mpz division by zero >>> divmod(a, float('Inf')) (mpf('0.e0'), mpf('1.23e2')) >>> divmod(a, float('-Inf')) (mpf('-1.e0'), -inf) >>> divmod(-a, float('Inf')) (mpf('-1.e0'), inf) >>> divmod(-a, float('-Inf')) (mpf('0.e0'), mpf('-1.23e2')) >>> divmod(a, float('nan')) (nan, nan) >>> divmod(-a, float('nan')) (nan, nan) >>> divmod(_g.mpz(0), float('Inf')) (mpf('0.e0'), mpf('0.e0')) >>> divmod(_g.mpz(0), float('-Inf')) (mpf('0.e0'), mpf('0.e0')) >>> divmod(_g.mpz(0), float('nan')) (nan, nan) >>> divmod(float('Inf'), a) (nan, nan) >>> divmod(float('-Inf'), a) (nan, nan) >>> divmod(float('Inf'), -a) (nan, nan) >>> divmod(float('-Inf'), -a) (nan, nan) >>> divmod(float('nan'), a) (nan, nan) >>> divmod(float('nan'), -a) (nan, nan) >>> divmod(float('Inf'), _g.mpz(0)) Traceback (most recent call last): ... ZeroDivisionError: mpz modulo by zero >>> divmod(float('-Inf'), _g.mpz(0)) Traceback (most recent call last): ... ZeroDivisionError: mpz modulo by zero >>> divmod(float('nan'), _g.mpz(0)) Traceback (most recent call last): ... ZeroDivisionError: mpz modulo by zero ''' __test__['bitops']=\ r''' >>> ~a mpz(-124) >>> a&b mpz(72) >>> a|b mpz(507) >>> a^b mpz(435) >>> a<<1 mpz(246) >>> a>>1 mpz(61) >>> a<<-1 Traceback (innermost last): ... ValueError: negative shift count >>> a>>-2 Traceback (innermost last): ... ValueError: negative shift count >>> a<<0 mpz(123) >>> a>>0 mpz(123) >>> a.popcount() 6 >>> _g.popcount(b) 4 >>> _g.popcount(-7) -1 >>> _g.popcount(0) 0 >>> a.hamdist(b) 6 >>> _g.hamdist(3) Traceback (innermost last): ... TypeError: hamdist() expects 'mpz','mpz' arguments >>> a.hamdist() Traceback (innermost last): ... TypeError: hamdist() expects 'mpz','mpz' arguments >>> a.hamdist(3, 4) Traceback (innermost last): ... TypeError: hamdist() expects 'mpz','mpz' arguments >>> a.lowbits(5) mpz(27) >>> b.lowbits(5) mpz(8) >>> b.lowbits(5)==(b%32) 1 >>> a.lowbits(5)==(a%32) 1 >>> a.setbit(20) mpz(1048699) >>> a.setbit(0,0) mpz(122) >>> for i in range(8): ... print a.getbit(i), ... if i==7: print ... 1 1 0 1 1 1 1 0 >>> for i in range(10): ... print b.getbit(i), ... if i==9: print ... 0 0 0 1 0 0 1 1 1 0 >>> [a.scan0(j) for j in range(33)] [2, 2, 2, 7, 7, 7, 7, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32] >>> [a.scan1(j) for j in range(10)] [0, 1, 3, 3, 4, 5, 6, None, None, None] >>> n=_g.mpz(-(7+6*16+5*256+7*4092)) >>> [n.scan0(j) for j in range(18)] [1, 1, 3, 3, 6, 6, 6, 8, 8, 10, 10, 12, 12, 13, 14, -1, None, None] >>> [n.scan1(j) for j in range(33)] [0, 2, 2, 4, 4, 5, 7, 7, 9, 9, 11, 11, 15, 15, 15, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32] >>> _g.mpz(0).bit_length() 0 >>> _g.mpz(12345).bit_length() 14 ''' __test__['format']=\ r''' >>> str(a) '123' >>> repr(a) 'mpz(123)' >>> hex(a) '0x7b' >>> oct(a) '0173' >>> _g.mpz('123') mpz(123) >>> _g.mpz('1001001011',2) mpz(587) >>> _g.mpz('1001001011',2).digits(2) '1001001011' >>> for i in range(2,63): ... print a.digits(i), ... if i%6==0: print ... 1111011 11120 1323 443 323 234 173 146 123 102 a3 96 8b 83 7b 74 6f 69 63 5i 5d 58 53 4n 4j 4f 4b 47 43 3u 3r 3o 3l 3i 3f 3C 39 36 33 30 2d 2b 2Z 2X 2V 2T 2R 2P 2N 2L 2J 2H 2F 2D 2B 29 27 25 23 21 1z >>> print a.digits(63) Traceback (innermost last): File "", line 1, in ? print a.digits(37) ValueError: base must be either 0 or in the interval 2 ... 62 >>> _g.set_tagoff(0) 1 >>> a gmpy.mpz(123) >>> _g.set_tagoff(1) 0 >>> _g.mpz('43') mpz(43) >>> _g.mpz('043') mpz(43) >>> _g.mpz('43',0) mpz(43) >>> _g.mpz('043',0) mpz(35) >>> _g.mpz('0x43',0) mpz(67) >>> _g.mpz('0x43') Traceback (innermost last): File "", line 1, in ? _g.mpz('0x43') ValueError: invalid digits >>> ''' __test__['binio']=\ r''' >>> ba=a.binary() >>> ba '{' >>> _g.mpz(ba,256) mpz(123) >>> _g.mpz(ba,256)==a 1 >>> _g.binary(123) '{' >>> z=_g.mpz('melancholy',256) >>> z mpz(573406620562849222387053L) >>> long(z) 573406620562849222387053L >>> divmod(z,a) (mpz(4661842443600400182008L), mpz(69)) >>> for i in range(2,63): ... print i,z.numdigits(i), ... if i%6==0: print ... 2 79 3 50 4 40 5 35 6 31 7 29 8 27 9 25 10 24 11 23 12 23 13 22 14 21 15 21 16 20 17 20 18 19 19 19 20 19 21 18 22 18 23 18 24 18 25 18 26 17 27 17 28 17 29 17 30 17 31 16 32 16 33 16 34 16 35 16 36 16 37 16 38 16 39 15 40 15 41 15 42 15 43 15 44 15 45 15 46 15 47 15 48 15 49 15 50 14 51 14 52 14 53 14 54 14 55 14 56 14 57 14 58 14 59 14 60 14 61 14 62 14 >>> _g.numdigits(23) 2 >>> _g.numdigits(23,2) 5 >>> _g.numdigits(23,99) Traceback (most recent call last): File "", line 1, in ? ValueError: base must be either 0 or in the interval 2 ... 62 >>> hash(a) 123 >>> hash(b) 456 >>> hash(z) == hash(long(z)) True >>> _g.mpz(_g.binary(-123),256) mpz(-123) >>> long(_g.mpz(-3)) -3L >>> ''' __test__['number']=\ r''' >>> print a.sqrt(), b.sqrt() 11 21 >>> print a.sqrtrem(), b.sqrtrem() (mpz(11), mpz(2)) (mpz(21), mpz(15)) >>> for i in range(5): ... print a.root(i+1),b.root(i+1) ... (mpz(123), 1) (mpz(456), 1) (mpz(11), 0) (mpz(21), 0) (mpz(4), 0) (mpz(7), 0) (mpz(3), 0) (mpz(4), 0) (mpz(2), 0) (mpz(3), 0) >>> a.is_square() 0 >>> a.is_power() 0 >>> _g.is_square(99*99) 1 >>> _g.is_square(99*99*99) 0 >>> _g.is_square(0) 1 >>> _g.is_square(-1) 0 >>> _g.is_power(99*99*99) 1 >>> _g.gcd(a,b) mpz(3) >>> temp=_g.gcdext(a,b) >>> temp[0]==a*temp[1]+b*temp[2] True >>> _g.lcm(a,b) mpz(18696) >>> _g.fac(7) mpz(5040) >>> _g.fib(17) mpz(1597) >>> for i in range(10): ... print _g.bincoef(10,i) ... 1 10 45 120 210 252 210 120 45 10 >>> _g.divm(b,a,20) mpz(12) >>> _g.divm(a,b,100) Traceback (innermost last): File "", line 1, in ? _g.divm(a,b,100) ZeroDivisionError: not invertible >>> _g.divm(6,12,14) mpz(4) >>> _g.divm(0,1,2) mpz(0) >>> # guard against regression of an ancient gmpy bug: divm w/non-coprime parms >>> _g.divm(4,8,20) mpz(3) >>> _g.divm(4,8,20) mpz(3) >>> _g.mpz(20) mpz(20) >>> _g.mpz(8) mpz(8) >>> _g.mpz(4) mpz(4) >>> # guard against regression of a memory leak in divm >>> __ = gc.collect() >>> _siz = 87654 >>> _siz = _memsize() >>> for x in xrange(45678): ... _xx=_g.divm(b,a,20) >>> del _xx >>> __ = gc.collect() >>> (_memsize()-_siz) <= 16 True >>> a.invert(100) mpz(87) >>> b.invert(100) mpz(0) >>> _g.invert(3) Traceback (innermost last): ... TypeError: invert() expects 'mpz','mpz' arguments >>> a.invert() Traceback (innermost last): ... TypeError: invert() expects 'mpz','mpz' arguments >>> a.invert(3, 4) Traceback (innermost last): ... TypeError: invert() expects 'mpz','mpz' arguments >>> _g.comb(3,-1) Traceback (most recent call last): File "", line 1, in ? ValueError: binomial coefficient with negative k >>> _g.sqrt(-1) Traceback (most recent call last): File "", line 1, in ? ValueError: sqrt of negative number >>> _g.sqrtrem(-1) Traceback (most recent call last): File "", line 1, in ? ValueError: sqrt of negative number >>> _g.remove(3,-1) Traceback (most recent call last): File "", line 1, in ? ValueError: factor must be > 1 >>> _g.remove(3) Traceback (innermost last): ... TypeError: remove() expects 'mpz','mpz' arguments >>> a.remove() Traceback (innermost last): ... TypeError: remove() expects 'mpz','mpz' arguments >>> a.remove(3, 4) Traceback (innermost last): ... TypeError: remove() expects 'mpz','mpz' arguments >>> _g.is_prime(3,-3) Traceback (most recent call last): File "", line 1, in ? ValueError: repetition count for is_prime must be positive >>> _g.jacobi(10,3) 1 >>> _g.jacobi(10,-3) Traceback (most recent call last): File "", line 1, in ? ValueError: jacobi's y must be odd prime > 0 >>> _g.jacobi(3) Traceback (innermost last): ... TypeError: jacobi() expects 'mpz','mpz' arguments >>> a.jacobi() Traceback (innermost last): ... TypeError: jacobi() expects 'mpz','mpz' arguments >>> a.jacobi(3, 4) Traceback (innermost last): ... TypeError: jacobi() expects 'mpz','mpz' arguments >>> _g.legendre(10,3) 1 >>> _g.legendre(10,-3) Traceback (most recent call last): File "", line 1, in ? ValueError: legendre's y must be odd and > 0 >>> _g.legendre(3) Traceback (innermost last): ... TypeError: legendre() expects 'mpz','mpz' arguments >>> a.legendre() Traceback (innermost last): ... TypeError: legendre() expects 'mpz','mpz' arguments >>> a.legendre(3, 4) Traceback (innermost last): ... TypeError: legendre() expects 'mpz','mpz' arguments >>> _g.kronecker(10,3) 1 >>> _g.kronecker(10,-3) 1 >>> _g.kronecker(3) Traceback (innermost last): ... TypeError: kronecker() expects 'mpz','mpz' arguments >>> a.kronecker() Traceback (innermost last): ... TypeError: kronecker() expects 'mpz','mpz' arguments >>> a.kronecker(3, 4) Traceback (innermost last): ... TypeError: kronecker() expects 'mpz','mpz' arguments >>> a=10L**20 >>> b=a+39 >>> _g.jacobi(a,b) 1 >>> _g.legendre(a,b) 1 >>> _g.kronecker(a,b) Traceback (most recent call last): File "", line 1, in ? ValueError: Either arg in Kronecker must fit in an int >>> f=_g.mpf(3.3) >>> f.setprec(-1) Traceback (most recent call last): File "", line 1, in ? ValueError: n must be >=0 >>> _g.rand('init',-1) >>> _g.rand('init',-7) Traceback (most recent call last): File "", line 1, in ? ValueError: size must be in 1..128 >>> _g.rand('init',200) Traceback (most recent call last): File "", line 1, in ? ValueError: size must be in 1..128 >>> _g.rand('qual') 32 >>> _g.rand('floa',-7) Traceback (most recent call last): File "", line 1, in ? ValueError: 'floa' needs arg>=0 ''' def _test(chat=None): try: float('nan') except ValueError: if "special" in __test__: del(__test__["special"]) if chat: print "Unit tests for gmpy 1.17 (mpz functionality)" print " running on Python %s" % sys.version print if _g.gmp_version(): print "Testing gmpy %s (GMP %s) with default caching (%s, %s)" % ( (_g.version(), _g.gmp_version(), _g.get_cache()[0], _g.get_cache()[1])) else: print "Testing gmpy %s (MPIR %s) with default caching (%s, %s)" % ( (_g.version(), _g.mpir_version(), _g.get_cache()[0], _g.get_cache()[1])) thismod = sys.modules.get(__name__) doctest.testmod(thismod, report=0) if chat: print "Repeating tests, with caching disabled" _g.set_cache(0,128) sav = sys.stdout class _Dummy: def write(self,*whatever): pass try: sys.stdout = _Dummy() doctest.testmod(thismod, report=0) finally: sys.stdout = sav if chat: print print "Overall results for mpz:" return doctest.master.summarize(chat) if __name__=='__main__': _test(1) gmpy-1.17/test/gmpy_test_mpq.py0000666000000000000000000001357412174774720015366 0ustar rootroot# partial unit test for gmpy mpq functionality # relies on Tim Peters' "doctest.py" test-driver r''' >>> filter(lambda x: not x.startswith('__'), dir(a)) ['_copy', 'binary', 'denom', 'denominator', 'digits', 'numer', 'numerator', 'qdiv', 'sign'] >>> ''' import gmpy as _g, doctest,sys __test__={} a=_g.mpq('123/456') b=_g.mpq('789/123') __test__['elemop']=\ r''' >>> a+b mpq(41657,6232) >>> a-b mpq(-38295,6232) >>> a*b mpq(263,152) >>> a/b mpq(1681,39976) >>> b+a mpq(41657,6232) >>> b-a mpq(38295,6232) >>> b*a mpq(263,152) >>> b/a mpq(39976,1681) >>> a+1 mpq(193,152) >>> 1+a mpq(193,152) >>> a-1 mpq(-111,152) >>> 1-a mpq(111,152) >>> a*1 mpq(41,152) >>> 1*a mpq(41,152) >>> a/1 mpq(41,152) >>> 1/a mpq(152,41) >>> -a mpq(-41,152) >>> abs(-a) mpq(41,152) >>> _g.qsign(b-a) 1 >>> _g.qsign(b-b) 0 >>> _g.qsign(a-b) -1 >>> a.sign() 1 >>> (-a).sign() -1 >>> z=b-b; z.sign() 0 >>> a.numer() == a.numerator True >>> a.denom() == a.denominator True >>> an=a.numer(); ad=a.denom(); >>> an==0 or 1==a*_g.mpq(ad,an) 1 >>> bn=b.numer(); bd=b.denom(); >>> bn==0 or 1==b*_g.mpq(bd,bn) 1 >>> zn=z.numer(); zd=z.denom(); >>> zn==0 or 1==z*_g.mpq(zd,zn) 1 >>> (a+b) == _g.mpq(an*bd+ad*bn,ad*bd) 1 >>> (a+z) == _g.mpq(an*zd+ad*zn,ad*zd) 1 >>> (a+a) == _g.mpq(an*ad+ad*an,ad*ad) 1 >>> import pickle >>> pickle.loads(pickle.dumps(_g.mpq(1234,6789))) mpq(1234,6789) >>> ''' from gmpy_truediv import truediv __test__['newdiv']=\ r''' >>> a/b mpq(1681,39976) >>> a//b mpz(0) >>> truediv(a,b) mpq(1681,39976) >>> b/a mpq(39976,1681) >>> b//a mpz(23) >>> truediv(b,a) mpq(39976,1681) >>> ''' __test__['cmpr']=\ r''' >>> c=_g.mpq(a) >>> c is a 1 >>> c==a 1 >>> c>a 0 >>> c>> d=a._copy() >>> a is d 0 >>> a == d 1 >>> cmp(a,c) 0 >>> cmp(a,b) -1 >>> a>b 0 >>> a>> not _g.mpq(0) 1 >>> not a 0 >>> a>1 0 >>> a>1.0 0 >>> a<1 1 >>> a<1.0 1 >>> a==1 0 >>> a==1.0 0 >>> cmp(a,1) -1 >>> cmp(1.0,a) 1 >>> long(1/a) 3L >>> long(-1/a) -3L >>> int(1/a) 3 >>> int(-1/a) -3 >>> ''' __test__['format']=\ r''' >>> str(a) '41/152' >>> repr(a) 'mpq(41,152)' >>> a==eval(repr(a),_g.__dict__) 1 >>> str(-a) '-41/152' >>> repr(-a) 'mpq(-41,152)' >>> (-a)==eval(repr(-a),_g.__dict__) 1 >>> _g.set_tagoff(0) 1 >>> a gmpy.mpq(41,152) >>> _g.mpq('12.34') gmpy.mpq(617,50) >>> _g.set_tagoff(1) 0 >>> for i in range(1,7): ... for j in range(3,10): ... if _g.mpq(i,j) != _g.mpq("%d/%d"%(i,j)): ... print 'er1:',i,j; break ... aa=_g.mpq(i,j); ai=aa.numer(); aj=aa.denom() ... if aj!=1 and str(aa) != ("%d/%d"%(ai,aj)): ... print 'er2:',i,j,str(aa),("%d/%d"%(ai,aj)); break ... if aj==1 and str(aa) != ("%d"%ai): ... print 'er3:',i,j,str(aa),"%d"%ai; break ... if aj!=1 and repr(aa) != ("mpq(%d,%d)"%(ai,aj)): ... print 'er4:',i,j,repr(aa),("mpq(%d,%d)"%(ai,aj)); break ... if aj==1 and repr(aa) != ("mpq(%d,%d)"%(ai,aj)): ... print 'er5:',i,j,repr(aa),"mpq(%d,%d)"%(ai,aj); break >>> fmo='_g.mpq('+hex(a.numer())+','+hex(a.denom())+')' >>> fmo '_g.mpq(0x29,0x98)' >>> eval(fmo)==a 1 >>> fmo='_g.mpq("'+a.numer().digits(30)+'/'+a.denom().digits(30)+'",30)' >>> fmo '_g.mpq("1b/52",30)' >>> eval(fmo)==a 1 >>> _g.qdigits(a,30) '1b/52' >>> a.digits(30) '1b/52' >>> _g.mpq(1000L*1000*1000*1000*1000*1000*1000,23) mpq(1000000000000000000000L,23) >>> _g.mpq(23,1000L*1000*1000*1000*1000*1000*1000) mpq(23,1000000000000000000000L) >>> _g.mpq(23L**15L,1000L**7L) mpq(266635235464391245607L,1000000000000000000000L) >>> _g.qbinary('pep') Traceback (most recent call last): File "", line 1, in ? TypeError: argument can not be converted to mpq >>> x=_g.mpq('234/567') >>> del x >>> _g.mpq('7788') mpq(7788,1) >>> _g.mpq('12.34') mpq(617,50) ''' __test__['binio']=\ r''' >>> ba=a.binary() >>> len(ba) 6 >>> for i in range(len(ba)): ... print ord(ba[i]), ... if i==len(ba)-1: print ... 1 0 0 0 41 152 >>> _g.mpq(ba,256)==a 1 >>> ba == _g.qbinary(a) 1 >>> ba=(-a).binary() >>> len(ba) 6 >>> for i in range(len(ba)): ... print ord(ba[i]), ... if i==len(ba)-1: print ... 1 0 0 128 41 152 >>> _g.mpq(ba,256)==-a 1 >>> hash(a)==hash(_g.mpf(a))==hash(float(a)) 1 >>> hash(b)==hash(_g.mpf(b))==hash(float(b)) 1 >>> hash(-a)==hash(-_g.mpf(a))==hash(-float(a)) 1 >>> hash(-b)==hash(-_g.mpf(b))==hash(-float(b)) 1 >>> ''' __test__['power']=\ r''' >>> _g.mpq(2,3)**3 mpq(8,27) >>> _g.mpq(8,27)**_g.mpq('2/3') mpq(4,9) >>> _g.mpq(2,3)**-3 mpq(27,8) >>> _g.mpq(8,27)**_g.mpq('-2/3') mpq(9,4) >>> print float(_g.mpf('0.2')**2) 0.04 >>> print float(_g.mpf('0.2')**-2) 25.0 >>> _g.mpq(3)**3 == _g.mpz(3)**3 1 >>> (a**-7) == 1/(a**7) 1 >>> (b**5) == 1/(b**-5) 1 >>> ''' __test__['qdiv']=\ r''' >>> _g.qdiv(12,2) mpz(6) >>> _g.qdiv(12,5) mpq(12,5) >>> a is a.qdiv() 1 >>> a is a.qdiv(1) 1 >>> a is a.qdiv(2) 0 >>> x=a.numer() >>> x is _g.qdiv(x) 1 >>> x is _g.qdiv(x,1) 1 >>> x is _g.qdiv(x,2) 0 >>> y=_g.mpq(4,1) >>> y is y.qdiv() 0 >>> y == y.qdiv() 1 >>> ''' def _test(chat=None): if chat: print "Unit tests for gmpy 1.17 (mpq functionality)" print " running on Python",sys.version print if _g.gmp_version(): print "Testing gmpy %s (GMP %s) with default caching (%s, %s)" % ( (_g.version(), _g.gmp_version(), _g.get_cache()[0], _g.get_cache()[1])) else: print "Testing gmpy %s (MPIR %s) with default caching (%s, %s)" % ( (_g.version(), _g.mpir_version(), _g.get_cache()[0], _g.get_cache()[1])) thismod = sys.modules.get(__name__) doctest.testmod(thismod, report=0) if chat: print "Repeating tests, with caching disabled" _g.set_cache(0,128) sav = sys.stdout class _Dummy: def write(self,*whatever): pass try: sys.stdout = _Dummy() doctest.testmod(thismod, report=0) finally: sys.stdout = sav if chat: print print "Overall results for mpq:" return doctest.master.summarize(chat) if __name__=='__main__': _test(1) gmpy-1.17/test/gmpy_test_mpf.py0000666000000000000000000002027312174774720015345 0ustar rootroot# partial unit test for gmpy mpf functionality # relies on Tim Peters' "doctest.py" test-driver r''' >>> filter(lambda x: not x.startswith('__'), dir(a)) ['_copy', 'binary', 'ceil', 'digits', 'f2q', 'floor', 'getprec', 'getrprec', 'qdiv', 'reldiff', 'round', 'setprec', 'sign', 'sqrt', 'trunc'] >>> ''' import warnings warnings.filterwarnings('ignore', 'setprec') import sys import gmpy as _g, doctest, sys __test__={} a=_g.mpf('123.456') b=_g.mpf('789.123') __test__['elemop']=\ r''' >>> str(a+b) '912.579' >>> str(a-b) '-665.667' >>> str(a*b) '97421.969088' >>> str(a/b) '0.156447093799065544915' >>> str(b+a) '912.579' >>> str(b-a) '665.667' >>> str(b*a) '97421.969088' >>> str(b/a) '6.39193720839813374807' >>> str(-a) '-123.456' >>> _g.mpf(2,200) + 3 mpf('5.e0',200) >>> 3 + _g.mpf(2,200) mpf('5.e0',200) >>> _g.mpf(2,200) * 3 mpf('6.e0',200) >>> 3 * _g.mpf(2,200) mpf('6.e0',200) >>> str(abs(-a)) '123.456' >>> _g.fsign(b-a) 1 >>> _g.fsign(b-b) 0 >>> _g.fsign(a-b) -1 >>> a.sign() 1 >>> (-a).sign() -1 >>> z=b-b; z.sign() 0 >>> import math >>> math.ceil(a) 124.0 >>> str(a.ceil()) '124.0' >>> str(_g.ceil(a)) '124.0' >>> math.floor(a) 123.0 >>> str(a.floor()) '123.0' >>> str(_g.floor(a)) '123.0' >>> str(a.trunc()) '123.0' >>> str(_g.trunc(a)) '123.0' >>> x=-a >>> math.floor(x) -124.0 >>> str(x.floor()) '-124.0' >>> str(_g.floor(x)) '-124.0' >>> str(x.ceil()) '-123.0' >>> math.ceil(x) -123.0 >>> str(_g.ceil(x)) '-123.0' >>> str(x.trunc()) '-123.0' >>> str(_g.trunc(x)) '-123.0' >>> _g.ceil(12.3)==math.ceil(12.3) 1 >>> _g.floor(12.3)==math.floor(12.3) 1 >>> _g.ceil(-12.3)==math.ceil(-12.3) 1 >>> _g.floor(-12.3)==math.floor(-12.3) 1 >>> (a**2).reldiff(float(a)**2) < 1.03 * (2.0**-(a.getrprec()-1)) 1 >>> (a**2).reldiff(a*a) < (2.0**-(a.getprec()-1)) 1 >>> (b**2).reldiff(float(b)**2) < 1.03 * (2.0**-(b.getrprec()-1)) 1 >>> (b**2).reldiff(b*b) < (2.0**-(b.getprec()-1)) 1 >>> _g.reldiff(3.4) Traceback (innermost last): File "", line 1, in ? _g.reldiff(3.4) TypeError: function takes exactly 2 arguments (1 given) >>> a.reldiff() Traceback (innermost last): File "", line 1, in ? _g.reldiff() TypeError: function takes exactly 1 argument (0 given) >>> a.reldiff(3, 4) Traceback (innermost last): File "", line 1, in ? _g.reldiff(3, 4) TypeError: function takes exactly 1 argument (2 given) >>> a.sqrt() mpf('1.11110755554986664846e1') >>> _g.fsqrt(a) mpf('1.11110755554986664846e1') >>> _g.fsqrt(-1) Traceback (most recent call last): File "", line 1, in ? File "a.py", line 9, in _er raise ValueError, what ValueError: sqrt of negative number >>> _g.pi(64) mpf('3.14159265358979323846e0',64) >>> import pickle >>> flt = _g.mpf(1234.6789) >>> flt == pickle.loads(pickle.dumps(flt)) True >>> flt = _g.mpf('1.1') >>> flt == pickle.loads(pickle.dumps(flt)) True ''' from gmpy_truediv import truediv __test__['newdiv']=\ r''' >>> >>> a/b mpf('1.56447093799065544915e-1') >>> a//b mpf('0.e0') >>> truediv(a,b) mpf('1.56447093799065544915e-1') >>> b/a mpf('6.39193720839813374807e0') >>> b//a mpf('6.e0') >>> truediv(b,a) mpf('6.39193720839813374807e0') >>> ''' __test__['cmpr']=\ r''' >>> c=_g.mpf(a) >>> c is a 1 >>> c==a 1 >>> c>a 0 >>> c>> d=a._copy() >>> a is d 0 >>> a == d 1 >>> cmp(a,c) 0 >>> cmp(a,b) -1 >>> a>b 0 >>> a>> not _g.mpf(0) 1 >>> not a 0 >>> a.f2q(0.1) mpz(123) >>> a.f2q(0.01) mpz(123) >>> a.f2q(0.001) mpq(247,2) >>> a.f2q(0.0001) mpq(1358,11) >>> a.f2q(0.00001) mpq(7037,57) >>> a.f2q(0.000001) mpq(15432,125) >>> a.f2q(0.0000001) mpq(15432,125) >>> a.f2q() mpq(15432,125) >>> print _g.mpf(_g.mpz(1234)) 1234.0 >>> x=1000*1000*1000*1000L >>> _g.mpf(x) mpf('1.e12') >>> c=_g.mpf(a) >>> a is c 1 >>> c=_g.mpf(a,99) >>> a is c 0 >>> a==c 1 >>> _g.mpf('1.1') == _g.mpf('1.1') * _g.mpf(1) True >>> _g.mpf('1.1',64) == _g.mpf('1.1',128) False >>> _g.mpf('1.1',64) == _g.mpf(_g.mpf('1.1',128),64) True >>> a = _g.mpf('.123', 64) >>> b = _g.mpf('.123', 128) >>> c = _g.mpf('.123', 128) * _g.mpf(1, 128) >>> a == b False >>> a == c False >>> b == c True >>> a == b.round(64) True >>> a == _g.fround(b, 64) True >>> _g.mpf('ffffffffffffffffe8000000000000000', 256, 16).round(64).digits(16) 'f.fffffffffffffffe@32' >>> _g.mpf('fffffffffffffffff8000000000000000', 256, 16).round(64).digits(16) '1.@33' >>> b.round(64) mpf('1.23e-1',64) ''' __test__['format']=\ r''' >>> str(a) '123.456' >>> repr(a) "mpf('1.23456e2')" >>> _g.set_tagoff(0) 1 >>> a gmpy.mpf('1.23456e2') >>> _g.set_tagoff(1) 0 >>> a.digits(10,0) '1.23456e2' >>> a.digits(10,1) '1.e2' >>> a.digits(10,2) '1.2e2' >>> a.digits(10,3) '1.23e2' >>> a.digits(10,4) '1.235e2' >>> a.digits(10,5) '1.2346e2' >>> a.digits(10,6) '1.23456e2' >>> a.digits(10,7) '1.23456e2' >>> a.digits(10,8) '1.23456e2' >>> for i in range(11,99): ... tempa='%.16f' % (i/10.0) ... tempb=_g.mpf(i/10.0).digits(10,17) ... assert tempb.startswith(tempa.rstrip('0')), (tempa, tempb) ... >>> junk=_g.set_fcoform(14) >>> frmt=_g.set_fcoform(14) >>> frmt '%.14e' >>> ofmt=_g.set_fcoform(frmt) >>> ofmt '%.14e' >>> _g.mpf(3.4) mpf('3.39999999999999999998e0') >>> print _g.mpf(3.4) 3.39999999999999999998 >>> _g.set_fcoform(junk) '%.14e' >>> a.digits(1) Traceback (most recent call last): File "", line 1, in ? ValueError: base must be either 0 or in the interval 2 ... 62 >>> a.digits(2,-1) Traceback (most recent call last): File "", line 1, in ? ValueError: digits must be >= 0 >>> a.digits(10,0,0,-1,2) ('123456', 3, 53) >>> saveprec=a.getrprec() >>> a.setprec(33) >>> a mpf('1.23456e2',33) >>> a.setprec(saveprec) >>> a.getrprec()==saveprec 1 >>> _g.fdigits(2.2e5, 0, 6, -10, 10) '220000.0' >>> _g.fdigits(2.2e-5, 0, 6, -10, 10) '0.000022' >>> _g.digits(_g.mpf(23.45)) Traceback (most recent call last): ... TypeError: digits() expects 'mpz',['int'] arguments >>> _g.fbinary('pep') Traceback (most recent call last): File "", line 1, in ? TypeError: argument can not be converted to mpf >>> ''' __test__['binio']=\ r''' >>> epsilon=_g.mpf(2)**-(a.getrprec()) >>> ba=a.binary() >>> a.reldiff(_g.mpf(ba,0,256)) <= epsilon 1 >>> len(ba) 18 >>> for i in range(len(ba)): ... print ord(ba[i]), ... if i==len(ba)-1: print ... 8 53 0 0 0 1 0 0 0 123 116 188 106 126 249 219 34 209 >>> na=(-a).binary() >>> (-a).reldiff(_g.mpf(na,0,256)) <= epsilon 1 >>> na[0] == chr(ord(ba[0])|1) 1 >>> for bd,nd in zip(ba[1:],na[1:]): ... assert bd==nd >>> ia=(1/a).binary() >>> (1/a).reldiff(_g.mpf(ia,0,256)) <= epsilon 1 >>> _g.fbinary(0) '\x04' >>> _g.mpf(_g.fbinary(0), 0, 256) == 0 1 >>> _g.fbinary(0.5) '\x085\x00\x00\x00\x00\x00\x00\x00\x80' >>> _g.mpf(_g.fbinary(0.5), 0, 256) == 0.5 1 >>> _g.fbinary(-0.5) '\t5\x00\x00\x00\x00\x00\x00\x00\x80' >>> _g.mpf(_g.fbinary(-0.5), 0, 256) == -0.5 1 >>> _g.fbinary(-2.0) '\t5\x00\x00\x00\x01\x00\x00\x00\x02' >>> _g.mpf(_g.fbinary(-2.0), 0, 256) == -2.0 1 >>> _g.fbinary(2.0) '\x085\x00\x00\x00\x01\x00\x00\x00\x02' >>> _g.mpf(_g.fbinary(2.0), 0, 256) == 2.0 1 >>> prec=_g.set_minprec(0) >>> junk=_g.set_minprec(prec) >>> a.getrprec()==prec 1 >>> b.getrprec()==prec 1 >>> _g.mpf(1.0).getrprec()==prec 1 >>> hash(_g.mpf(23.0))==hash(23) 1 >>> print _g.mpf('\004',0,256) 0.0 >>> long(a) 123L >>> long(-a) -123L >>> int(a) 123 >>> int(-a) -123 >>> ''' def _test(chat=None): if chat: print "Unit tests for gmpy 1.17 (mpf functionality)" print " running on Python %s" % sys.version print if _g.gmp_version(): print "Testing gmpy %s (GMP %s) with default caching (%s, %s)" % ( (_g.version(), _g.gmp_version(), _g.get_cache()[0], _g.get_cache()[1])) else: print "Testing gmpy %s (MPIR %s) with default caching (%s, %s)" % ( (_g.version(), _g.mpir_version(), _g.get_cache()[0], _g.get_cache()[1])) thismod = sys.modules.get(__name__) doctest.testmod(thismod, report=0) if chat: print "Repeating tests, with caching disabled" _g.set_cache(0,128) sav = sys.stdout class _Dummy: def write(self,*whatever): pass try: sys.stdout = _Dummy() doctest.testmod(thismod, report=0) finally: sys.stdout = sav if chat: print print "Overall results for mpf:" return doctest.master.summarize(chat) if __name__=='__main__': _test(1) gmpy-1.17/test/gmpy_test_dec.py0000666000000000000000000000443212174774720015315 0ustar rootroot# partial unit test for gmpy/decimal interoperability # note: broken in Python 2.4.0 due to a 2.4.0 bug, please update to 2.4.1 # or better to allow decimal/most-anything-else interoperability!-) # relies on Tim Peters' "doctest.py" test-driver r''' >>> filter(lambda x: not x.startswith('__'), dir(f)) ['_copy', 'binary', 'ceil', 'digits', 'f2q', 'floor', 'getprec', 'getrprec', 'qdiv', 'reldiff', 'round', 'setprec', 'sign', 'sqrt', 'trunc'] >>> ''' try: import decimal as _d except ImportError: _d = None import gmpy as _g, doctest, sys __test__={} f=_g.mpf('123.456') q=_g.mpq('789123/1000') z=_g.mpz('234') if _d: d=_d.Decimal('12.34') __test__['elemop']=\ r''' >>> print _g.mpz(23) == _d.Decimal(23) True >>> print _g.mpz(d) 12 >>> print _g.mpq(d) 617/50 >>> print _g.mpf(d) 12.34 >>> print f+d 135.796 >>> print d+f 135.796 >>> print q+d 801.463 >>> print d+q 801.463 >>> print z+d 246.34 >>> print d+z 246.34 >>> print _g.ceil(d) 13.0 >>> print _g.floor(d) 12.0 >>> print _g.trunc(d) 12.0 >>> _g.getrprec(d) 53 >>> _g.fsqrt(d)==_g.mpf(d).sqrt() 1 >>> ''' def _test(chat=None): python_version = sys.version_info[:3] if python_version == (2, 4, 0): print "You're using Python 2.4.0, which does not allow interoperability" print " between decimal and other types (due to a bug fixed in 2.4.1)" print " No point in testing, therefore -- please upgrade your Python!" return 0, 0 if chat: print "Unit tests for gmpy 1.17 (decimal interoperation)" print " running on Python", sys.version print if _g.gmp_version(): print "Testing gmpy %s (GMP %s) with default caching (%s, %s)" % ( (_g.version(), _g.gmp_version(), _g.get_cache()[0], _g.get_cache()[1])) else: print "Testing gmpy %s (MPIR %s) with default caching (%s, %s)" % ( (_g.version(), _g.mpir_version(), _g.get_cache()[0], _g.get_cache()[1])) if not _d: if chat: print "Can't test, since can't import decimal" return 0, 0 thismod = sys.modules.get(__name__) doctest.testmod(thismod, report=0) if chat: print print "Overall results for dec:" return doctest.master.summarize(chat) if __name__=='__main__': _test(1) gmpy-1.17/test/gmpy_test_cvr.py0000666000000000000000000003633412174774720015362 0ustar rootroot# partial unit test for gmpy extra cover # relies on Tim Peters' "doctest.py" test-driver r''' >>> print int(_g.gmp_version()[:3] in ('5.0', '4.3', '')) 1 >>> print int(_g.mpir_version()[:3] in ('2.3', '2.4', '2.5', '')) 1 >>> _g.version() '1.17' >>> int('gmpy.c' in _g._cvsid()) 1 ''' import gmpy as _g, doctest, sys __test__={} r = _g.rand __test__['misc_stuff']=\ r''' >>> junk=_g.set_debug(0) >>> knuj=_g.set_debug(junk) >>> junk==_g.set_debug(junk) 1 >>> _g.set_fcoform(None) >>> _g.set_fcoform() >>> print _g.mpf(3.0) 3.0 >>> _g.gmp_limbsize() in (32, 64) True >>> _g.mpz(u"123") mpz(123) >>> _g.mpq(u"12/37") mpq(12,37) >>> _g.mpf(u"123") mpf('1.23e2') ''' try: x = float('inf') except ValueError: pass else: __test__['infinity'] = \ r''' >>> x = float('inf') >>> n = float('nan') >>> _g.mpf(x) Traceback (most recent call last): ... ValueError: gmpy does not handle infinity >>> _g.mpf(-x) Traceback (most recent call last): ... ValueError: gmpy does not handle infinity >>> _g.mpq(x) Traceback (most recent call last): ... ValueError: gmpy does not handle infinity >>> _g.mpq(-x) Traceback (most recent call last): ... ValueError: gmpy does not handle infinity >>> _g.mpz(x) Traceback (most recent call last): ... ValueError: gmpy does not handle infinity >>> _g.mpz(-x) Traceback (most recent call last): ... ValueError: gmpy does not handle infinity >>> _g.mpf(n) Traceback (most recent call last): ... ValueError: gmpy does not handle nan >>> _g.mpf(n) Traceback (most recent call last): ... ValueError: gmpy does not handle nan >>> _g.mpf(n) Traceback (most recent call last): ... ValueError: gmpy does not handle nan ''' __test__['user_errors']=\ r''' >>> _g.version(23) Traceback (most recent call last): ... TypeError: version expects 0 arguments >>> _g.gmp_version(23) Traceback (most recent call last): ... TypeError: gmp_version expects 0 arguments >>> _g.get_cache(23) Traceback (most recent call last): ... TypeError: get_cache expects 0 arguments >>> _g.set_cache() Traceback (most recent call last): ... TypeError: function takes exactly 2 arguments (0 given) >>> _g.set_cache(200) Traceback (most recent call last): ... TypeError: function takes exactly 2 arguments (1 given) >>> _g.set_cache(200,-23) Traceback (most recent call last): ... ValueError: object size must between 0 and 16384 >>> _g.set_cache(2000,256) Traceback (most recent call last): ... ValueError: cache must between 0 and 1000 >>> _g.set_cache(-23,256) Traceback (most recent call last): ... ValueError: cache must between 0 and 1000 >>> _g.set_cache(200,256000) Traceback (most recent call last): ... ValueError: object size must between 0 and 16384 >>> _g.set_debug() Traceback (most recent call last): File "", line 1, in ? TypeError: function takes exactly 1 argument (0 given) >>> _g.set_debug(2,3) Traceback (most recent call last): File "", line 1, in ? TypeError: function takes exactly 1 argument (2 given) >>> _g.set_debug('boh') Traceback (most recent call last): File "", line 1, in ? TypeError: an integer is required >>> _g.set_minprec(-1) Traceback (most recent call last): File "", line 1, in ? ValueError: minimum precision must be >= 0 >>> _g.set_fcoform(33) Traceback (most recent call last): File "", line 1, in ? ValueError: number of digits n must be 0>> _g.set_fcoform([]) Traceback (most recent call last): File "", line 1, in ? TypeError: set_fcoform argument must be int, string, or None >>> _g.mpz('12'+chr(0)+'34') Traceback (most recent call last): File "", line 1, in ? ValueError: string without NULL characters expected >>> _g.mpf('12'+chr(0)+'34') Traceback (most recent call last): File "", line 1, in ? ValueError: string without NULL characters expected >>> _g.mpq('12'+chr(0)+'34') Traceback (most recent call last): File "", line 1, in ? ValueError: string without NULL characters expected >>> _g.mpq('bo',256) Traceback (most recent call last): File "", line 1, in ? ValueError: invalid mpq binary (too short) >>> _g.mpq('bologna',256) Traceback (most recent call last): File "", line 1, in ? ValueError: invalid mpq binary (num len) >>> _g.mpq('\001\000\000\000\003\002',256) mpq(3,2) >>> _g.mpq('\002\000\000\000\003\377\002',256) Traceback (most recent call last): File "", line 1, in ? ValueError: invalid mpq binary (num sgn) >>> _g.mpq('\001\000\000\000\003\002\377',256) Traceback (most recent call last): File "", line 1, in ? ValueError: invalid mpq binary (den sgn) >>> _g.mpq('ba/bo') Traceback (most recent call last): File "", line 1, in ? ValueError: invalid digits >>> print 'ba/bo' ba/bo >>> _g.mpq('1/bo') Traceback (most recent call last): File "", line 1, in ? ValueError: invalid digits >>> print '1/bo' 1/bo >>> _g.mpq('1/0') Traceback (most recent call last): File "", line 1, in ? ZeroDivisionError: mpq: zero denominator >>> _g.mpf([]) Traceback (most recent call last): File "", line 1, in ? TypeError: gmpy.mpf() expects numeric or string argument >>> _g.mpf('bo',0,256) Traceback (most recent call last): File "", line 1, in ? ValueError: string too short to be a gmpy.mpf binary encoding >>> _g.mpf('bo') Traceback (most recent call last): File "", line 1, in ? ValueError: invalid digits >>> int(_g.mpz(1000L*1000*1000*1000*1000*1000*1000)) 1000000000000000000000L >>> _g.scan0(12,-1) Traceback (most recent call last): File "", line 1, in ? ValueError: starting bit must be >= 0 >>> _g.scan1(12,-1) Traceback (most recent call last): File "", line 1, in ? ValueError: starting bit must be >= 0 >>> _g.lowbits(12,-1) Traceback (most recent call last): File "", line 1, in ? ValueError: nbits must be > 0 >>> _g.getbit(12,-1) Traceback (most recent call last): File "", line 1, in ? ValueError: bit_index must be >= 0 >>> _g.setbit(12,-1) Traceback (most recent call last): File "", line 1, in ? ValueError: bit_index must be >= 0 >>> _g.mpz(23).setbit(12,1,2,3) Traceback (most recent call last): ... TypeError: setbit() expects 'mpz','int'[,'int'] arguments >>> _g.setbit(12,1,2,3) Traceback (most recent call last): ... TypeError: setbit() expects 'mpz','int'[,'int'] arguments >>> _g.root(12,-1) Traceback (most recent call last): File "", line 1, in ? ValueError: n must be > 0 >>> _g.root(12,0) Traceback (most recent call last): File "", line 1, in ? ValueError: n must be > 0 >>> _g.root(-12,2) Traceback (most recent call last): File "", line 1, in ? ValueError: root of negative number >>> _g.digits(3.14) Traceback (most recent call last): ... TypeError: digits() expects 'mpz',['int'] arguments >>> _g.digits(3,'peep') Traceback (most recent call last): ... TypeError: digits() expects 'mpz',['int'] arguments >>> _g.fdigits(3.14,'peep') Traceback (most recent call last): File "", line 1, in ? TypeError: an integer is required >>> _g.qdigits(3.14,'peep') Traceback (most recent call last): File "", line 1, in ? TypeError: argument can not be converted to mpq >>> _g.qdigits(3,'peep') Traceback (most recent call last): File "", line 1, in ? TypeError: an integer is required >>> _g.mpz(3).digits('bu') Traceback (most recent call last): ... TypeError: digits() expects 'mpz',['int'] arguments >>> _g.mpf(3).digits('bu') Traceback (most recent call last): File "", line 1, in ? TypeError: an integer is required >>> _g.qdiv(3,_g.mpq(1)) mpz(3) >>> _g.qdiv(3,_g.mpz(1)) mpz(3) >>> _g.qdiv(3,_g.mpf(1)) mpz(3) >>> _g.qdiv(3,1.0) mpz(3) >>> _g.qdiv(3,1L) mpz(3) >>> _g.qdiv(3) mpz(3) >>> _g.qdiv(3,'bu') Traceback (most recent call last): File "", line 1, in ? TypeError: second argument can not be converted to mpq >>> _g.mpq(2).qdiv(3,4) Traceback (most recent call last): File "", line 1, in ? TypeError: function takes at most 1 argument (2 given) >>> _g.qdiv(3,4,5) Traceback (most recent call last): File "", line 1, in ? TypeError: function takes at most 2 arguments (3 given) >>> _g.qdiv('bu') Traceback (most recent call last): File "", line 1, in ? TypeError: first argument can not be converted to mpq >>> _g.qdiv(1.0,1) Traceback (most recent call last): File "", line 1, in ? TypeError: first argument can not be converted to mpq >>> _g.qdiv(1,0) Traceback (most recent call last): File "", line 1, in ? ZeroDivisionError: qdiv: zero divisor >>> _g.f2q(-1.0) mpz(-1) >>> _g.mpz(1,2,3) Traceback (most recent call last): File "", line 1, in ? TypeError: gmpy.mpz() requires 1 or 2 arguments >>> _g.mpz('bi','bo') Traceback (most recent call last): File "", line 1, in ? TypeError: gmpy.mpz(): base must be an integer >>> _g.mpz('bi',99) Traceback (most recent call last): File "", line 1, in ? ValueError: base for gmpy.mpz must be 0, 256, or in the interval 2 ... 62 . >>> _g.mpz(1,2) Traceback (most recent call last): File "", line 1, in ? TypeError: gmpy.mpz() with numeric argument needs exactly 1 argument >>> _g.mpz(None) Traceback (most recent call last): File "", line 1, in ? TypeError: gmpy.mpz() expects numeric or string argument >>> _g.mpq(1,2,3) Traceback (most recent call last): File "", line 1, in ? TypeError: gmpy.mpq() requires 1 or 2 arguments >>> _g.mpq('bi','bo') Traceback (most recent call last): File "", line 1, in ? TypeError: gmpy.mpq(): base must be an integer >>> _g.mpq('bi',99) Traceback (most recent call last): File "", line 1, in ? ValueError: base for gmpy.mpq() must be 0, 256, or in the interval 2 ... 36 . >>> _g.mpq(None) Traceback (most recent call last): File "", line 1, in ? TypeError: gmpy.mpq() expects numeric or string argument >>> _g.mpq(1,None) Traceback (most recent call last): File "", line 1, in ? TypeError: argument can not be converted to mpq >>> _g.mpq(1,0) Traceback (most recent call last): File "", line 1, in ? ZeroDivisionError: mpq: zero denominator >>> _g.mpf() Traceback (most recent call last): File "", line 1, in ? TypeError: gmpy.mpf() requires 1 to 3 arguments >>> _g.mpf(1,'bo') Traceback (most recent call last): File "", line 1, in ? TypeError: gmpy.mpf(): bits must be an integer >>> _g.mpf(1,-1) Traceback (most recent call last): File "", line 1, in ? ValueError: bits for gmpy.mpf must be >= 0 >>> _g.mpf('ba',0,'bu') Traceback (most recent call last): File "", line 1, in ? TypeError: gmpy.mpf(): base must be an integer >>> _g.mpf('ba',0,99) Traceback (most recent call last): File "", line 1, in ? ValueError: base for gmpy.mpf must be 0, 256, or in the interval 2 ... 62 . >>> _g.mpf(1,2,3) Traceback (most recent call last): File "", line 1, in ? TypeError: gmpy.mpf() with numeric 1st argument needs 1 or 2 arguments >>> +_g.mpz(1) mpz(1) >>> +_g.mpf(1) mpf('1.e0') >>> +_g.mpq(1) mpq(1,1) >>> _g.mpz(2)**-2 Traceback (most recent call last): File "", line 1, in ? ValueError: mpz.pow with negative power >>> _g.mpz(2)**_g.mpz(1000000*10000000000000L) Traceback (most recent call last): File "", line 1, in ? ValueError: mpz.pow outrageous exponent >>> pow(_g.mpz(2),3,0) Traceback (most recent call last): File "", line 1, in ? ValueError: mpz.pow divide by zero >>> pow(_g.mpz(2),3,-5) mpz(-2) >>> pow(_g.mpq(2),3,-5) Traceback (most recent call last): File "", line 1, in ? ValueError: mpq.pow no modulo allowed >>> a=10000000000L**2 >>> _g.mpq(2)**a Traceback (most recent call last): File "", line 1, in ? ValueError: mpq.pow outrageous exp num >>> _g.mpq(2)**_g.mpq(1,a) Traceback (most recent call last): File "", line 1, in ? ValueError: mpq.pow outrageous exp den >>> _g.mpq(2)**0 mpq(1,1) >>> _g.mpq(2)**-1 mpq(1,2) >>> _g.mpq(2)**_g.mpq(1,2) Traceback (most recent call last): File "", line 1, in ? ValueError: mpq.pow fractional exponent, inexact-root >>> _g.mpq(-2)**_g.mpq(1,2) Traceback (most recent call last): File "", line 1, in ? ValueError: mpq.pow fractional exponent, nonreal-root >>> _g.mpq(0)**_g.mpq(1,2) mpq(0,1) >>> _g.mpq(0)**-1 Traceback (most recent call last): File "", line 1, in ? ZeroDivisionError: mpq.pow 0 base to <0 exponent >>> _g.mpq(-1)**-1 mpq(-1,1) >>> _g.mpf(9,100)**2 mpf('8.1e1',100) >>> _g.mpf(9,100)**0.5 mpf('3.e0',100) >>> _g.mpf(9,100)**_g.mpf(0.5) mpf('3.e0') >>> _g.mpf(0)**2 mpf('0.e0') >>> pow(_g.mpf(2),3,-5) Traceback (most recent call last): File "", line 1, in ? ValueError: mpf.pow no modulo allowed >>> _g.mpz(1)+'bu' Traceback (most recent call last): File "", line 1, in ? TypeError: unsupported operand type(s) for +: 'mpz' and 'str' >>> _g.mpz(1)+_g.mpf(1) mpf('2.e0') >>> _g.mpz(1)+_g.mpq(1) mpq(2,1) >>> _g.mpq(1)+'bu' Traceback (most recent call last): File "", line 1, in ? TypeError: unsupported operand type(s) for +: 'mpq' and 'str' >>> _g.mpf(1)+'bu' Traceback (most recent call last): File "", line 1, in ? TypeError: unsupported operand type(s) for +: 'mpf' and 'str' >>> _g.mpf(1)+_g.mpq(2) mpf('3.e0') >>> divmod(_g.mpz(3),0) Traceback (most recent call last): File "", line 1, in ? ZeroDivisionError: mpz divmod by zero >>> divmod(_g.mpz(0),3) (mpz(0), mpz(0)) >>> _g.divm(1,2,0) Traceback (most recent call last): File "", line 1, in ? ZeroDivisionError: not invertible >>> abs(_g.mpq(0)) mpq(0,1) >>> _g.mpz(0)**2 mpz(0) >>> _g.mpq(-2)**0 mpq(1,1) >>> _g.fac(-1) Traceback (most recent call last): File "", line 1, in ? ValueError: factorial of negative number >>> _g.fib(-1) Traceback (most recent call last): File "", line 1, in ? ValueError: Fibonacci of negative number >>> _g.comb(7,-3) Traceback (most recent call last): File "", line 1, in ? ValueError: binomial coefficient with negative k >>> _g.sqrt(-1) Traceback (most recent call last): File "", line 1, in ? ValueError: sqrt of negative number >>> _g.sqrtrem(-1) Traceback (most recent call last): File "", line 1, in ? ValueError: sqrt of negative number >>> _g.fsqrt(-1) Traceback (most recent call last): File "", line 1, in ? ValueError: sqrt of negative number >>> _g.jacobi(23, -34) Traceback (most recent call last): ... ValueError: jacobi's y must be odd prime > 0 >>> _g.legendre(23, -34) Traceback (most recent call last): ... ValueError: legendre's y must be odd and > 0 >>> # guard against conversion error on 64-bit systems >>> _g.mpz(2**32) != _g.mpz(0) True >>> # test hash properties on 64-bit systems >>> temp = 123456789012345678901234567890 >>> hash(temp) == hash(_g.mpz(temp)) True >>> del temp ''' def _test(chat=None): if chat: print "Unit tests for gmpy 1.17 (extra cover)" print " running on Python", sys.version print if _g.gmp_version(): print "Testing gmpy %s (GMP %s) with default caching (%s, %s)" % ( (_g.version(), _g.gmp_version(), _g.get_cache()[0], _g.get_cache()[1])) else: print "Testing gmpy %s (MPIR %s) with default caching (%s, %s)" % ( (_g.version(), _g.mpir_version(), _g.get_cache()[0], _g.get_cache()[1])) thismod = sys.modules.get(__name__) doctest.testmod(thismod, report=0) if chat: print print "Overall results for cvr:" return doctest.master.summarize(chat) if __name__=='__main__': _test(1) gmpy-1.17/test/gmpy_test.py0000666000000000000000000000232612174774720014502 0ustar rootrootr''' >>> gmpy.version() '1.17' >>> ''' import sys import doctest import gmpy def writeln(s): sys.stdout.write(s+'\n') if sys.version_info[0] == 3: writeln("Please use 'test3/gmpy_test.py' to test with Python 3.x.") sys.exit(0) if sys.argv[-1] == 'debug': gmpy.set_debug(1) import gmpy_test_cvr import gmpy_test_rnd import gmpy_test_mpf import gmpy_test_mpq import gmpy_test_mpz import gmpy_test_dec test_modules = (gmpy_test_cvr, gmpy_test_rnd, gmpy_test_mpf, gmpy_test_mpq, gmpy_test_mpz, gmpy_test_dec) _g = gmpy writeln("Unit tests for gmpy 1.17") writeln(" on Python %s" % sys.version) if _g.gmp_version(): writeln("Testing gmpy %s (GMP %s), default caching (%s, %s)" % ( (_g.version(), _g.gmp_version(), _g.get_cache()[0], _g.get_cache()[1]))) else: writeln("Testing gmpy %s (MPIR %s), default caching (%s, %s)" % ( (_g.version(), _g.mpir_version(), _g.get_cache()[0], _g.get_cache()[1]))) pf, pt = 0, 0 for x in test_modules: testit = x._test() failures, tests = testit if tests == 0: continue writeln("%s %3d tests, %d failures" % (x.__name__, tests-pt, failures-pf)) pf, pt = failures, tests doctest.master.summarize(1) gmpy-1.17/src/0000755000000000000000000000000012543053022011677 5ustar rootrootgmpy-1.17/src/pysymbolicext.c0000666000000000000000000002300712174774730015004 0ustar rootroot/* PySymbolic GMP extensions (in connection with gmpy). 1) Factoring with Pollard's rho method. Copied relevant functions from demos/factorice.c of the GMP distribution, and modified them to be used in Python. Copyright 2000 Pearu Peterson all rights reserved, Pearu Peterson Permission to use, modify, and distribute this software is given under the terms of the LGPL. See http://www.fsf.org NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. $Revision: 1.2 $ $Date: 2003/08/08 08:57:05 $ Pearu Peterson Bug fix for more than 32 iterations in pollard_rho method. (Patch courtesy rel...@osagesoftware.com) */ #include "Python.h" #include #include #include #include #include "gmpy.h" static unsigned add[] = {4, 2, 4, 2, 4, 6, 2, 6}; #if defined (__hpux) || defined (__alpha) || defined (__svr4__) || defined (__SVR4) /* HPUX lacks random(). DEC OSF/1 1.2 random() returns a double. */ long mrand48 (); static long random () { return mrand48 (); } #else /* Glibc stdlib.h has "int32_t random();" which, on i386 at least, conflicts with a redeclaration as "long". */ #if defined(_MSC_VER) long random() { return rand(); } #endif #ifndef __GLIBC__ long random (); #endif #endif static void res_append_si(PyObject *res,signed long int f,unsigned long int c) { if (c) { PyObject *pair = (PyObject *)PyTuple_New(2); { PyObject *z = (PyObject *)Pympz_new(); mpz_set_si(Pympz_AS_MPZ(z),f); PyTuple_SetItem(pair,0,z); } { PyObject *z = (PyObject *)Pympz_new(); mpz_set_ui(Pympz_AS_MPZ(z),c); PyTuple_SetItem(pair,1,z); } PyList_Append(res,pair); Py_DECREF(pair); } } static void res_append(PyObject *res,unsigned long int f,unsigned long int c) { if (c) { PyObject *pair = (PyObject *)PyTuple_New(2); { PyObject *z = (PyObject *)Pympz_new(); mpz_set_ui(Pympz_AS_MPZ(z),f); PyTuple_SetItem(pair,0,z); } { PyObject *z = (PyObject *)Pympz_new(); mpz_set_ui(Pympz_AS_MPZ(z),c); PyTuple_SetItem(pair,1,z); } PyList_Append(res,pair); Py_DECREF(pair); } } static void res_append_mpz(PyObject *res,mpz_t f,unsigned long int c) { if (c) { PyObject *pair = (PyObject *)PyTuple_New(2); { PyObject *z = (PyObject *)Pympz_new(); mpz_set(Pympz_AS_MPZ(z),f); PyTuple_SetItem(pair,0,z); } { PyObject *z = (PyObject *)Pympz_new(); mpz_set_ui(Pympz_AS_MPZ(z),c); PyTuple_SetItem(pair,1,z); } PyList_Append(res,pair); Py_DECREF(pair); } } static void factor_using_division (mpz_t t, unsigned int limit, PyObject *res) { mpz_t q, r; unsigned long int f; int ai; unsigned *addv = add; unsigned int failures; unsigned long int count; mpz_init (q); mpz_init (r); count = 0; f = mpz_scan1 (t, 0); mpz_fdiv_q_2exp (t, t, f); res_append(res,2,f); count = 0; for (;;) { mpz_tdiv_qr_ui (q, r, t, 3); if (mpz_cmp_ui (r, 0) != 0) break; mpz_set (t, q); count++; } res_append(res,3,count); count = 0; for (;;) { mpz_tdiv_qr_ui (q, r, t, 5); if (mpz_cmp_ui (r, 0) != 0) break; mpz_set (t, q); count++; } res_append(res,5,count); failures = 0; f = 7; ai = 0; count = 0; while (mpz_cmp_ui (t, 1) != 0) { mpz_tdiv_qr_ui (q, r, t, f); if (mpz_cmp_ui (r, 0) != 0) { res_append(res,f,count); count = 0; f += addv[ai]; if (mpz_cmp_ui (q, f) < 0) break; ai = (ai + 1) & 7; failures++; if (failures > limit) break; } else { mpz_swap (t, q); failures = 0; count++; } } res_append(res,f,count); mpz_clear (q); mpz_clear (r); } static void factor_using_division_2kp (mpz_t t, unsigned int limit, unsigned long p, PyObject *res) { mpz_t r; mpz_t f; unsigned int k; unsigned long int count; mpz_init (r); mpz_init_set_ui (f, 2 * p); mpz_add_ui (f, f, 1); for (k = 1; k < limit; k++) { mpz_tdiv_r (r, t, f); count = 0; while (mpz_cmp_ui (r, 0) == 0) { mpz_tdiv_q (t, t, f); mpz_tdiv_r (r, t, f); count++; } res_append_mpz(res,f,count); mpz_add_ui (f, f, 2 * p); } mpz_clear (f); mpz_clear (r); } static void factor_using_pollard_rho (mpz_t n, int a_int, unsigned long p,PyObject *res) { mpz_t x, x1, y, P; mpz_t a; mpz_t g; mpz_t t1, t2; mpz_t kz, lz, iz; int c; unsigned long int count; mpz_init (g); mpz_init (t1); mpz_init (t2); mpz_init_set_si (a, a_int); mpz_init_set_si (y, 2); mpz_init_set_si (x, 2); mpz_init_set_si (x1, 2); mpz_init (iz); mpz_init_set_si (kz, 1); mpz_init_set_si (lz, 1); mpz_init_set_ui (P, 1); c = 0; count = 0; while (mpz_cmp_ui (n, 1) != 0) { S2: if (p != 0) { mpz_powm_ui (x, x, p, n); mpz_add (x, x, a); } else { mpz_mul (x, x, x); mpz_add (x, x, a); mpz_mod (x, x, n); } mpz_sub (t1, x1, x); mpz_mul (t2, P, t1); mpz_mod (P, t2, n); c++; if (c == 20) { c = 0; mpz_gcd (g, P, n); if (mpz_cmp_ui (g, 1) != 0) goto S4; mpz_set (y, x); } /* S3: */ mpz_sub_ui (kz, kz, 1); if (mpz_cmp_ui(kz,0) > 0) goto S2; mpz_gcd (g, P, n); if (mpz_cmp_ui (g, 1) != 0) goto S4; mpz_set (x1, x); mpz_set (kz, lz); mpz_mul_ui (lz, lz, 2); // for loop with integer index works fine for k < 2**31 // using mpz_t allows unlimited range for ( mpz_set (iz, kz); mpz_cmp_ui(iz,0) > 0; mpz_sub_ui (iz, iz, 1) ) { if (p != 0) { mpz_powm_ui (x, x, p, n); mpz_add (x, x, a); } else { mpz_mul (x, x, x); mpz_add (x, x, a); mpz_mod (x, x, n); } } mpz_set (y, x); c = 0; goto S2; S4: do { if (p != 0) { mpz_powm_ui (y, y, p, n); mpz_add (y, y, a); } else { mpz_mul (y, y, y); mpz_add (y, y, a); mpz_mod (y, y, n); } mpz_sub (t1, x1, y); mpz_gcd (g, t1, n); } while (mpz_cmp_ui (g, 1) == 0); if (!mpz_probab_prime_p (g, 3)) { do a_int = random (); while (a_int == -2 || a_int == 0); factor_using_pollard_rho (g, a_int, p, res); break; } else count ++; res_append_mpz(res,g,count); count = 0; mpz_fdiv_q (n, n, g); mpz_mod (x, x, n); mpz_mod (x1, x1, n); mpz_mod (y, y, n); if (mpz_probab_prime_p (n, 3)) { count++; break; } } res_append_mpz(res,n,count); mpz_clear (iz); mpz_clear (kz); mpz_clear (lz); mpz_clear (g); mpz_clear (P); mpz_clear (t2); mpz_clear (t1); mpz_clear (a); mpz_clear (x1); mpz_clear (x); mpz_clear (y); } static void factor (mpz_t t, unsigned long p,PyObject *res) { unsigned int division_limit; /* Set the trial division limit according the size of t. */ division_limit = mpz_sizeinbase (t, 2); if (division_limit > 1000) division_limit = 1000 * 1000; else division_limit = division_limit * division_limit; if (p != 0) factor_using_division_2kp (t, division_limit / 10, p, res); else factor_using_division (t, division_limit, res); if (mpz_cmp_ui (t, 1) != 0) { if (mpz_probab_prime_p (t, 3)) res_append_mpz(res,t,1); else factor_using_pollard_rho (t, 1, p, res); } } static char doc_factor[] = "factor(t,m=0) -> prime factors of t (modulo m)\n\ \n\ Prime decomposition of t (modulo m).\n\ factor(t,m) returns a list of tuples (f,p) where p is the number\n\ of prime factors f in term t. p is always positive.\n\ t can be also zero or negative.\n\ For m=0 the following condition holds\n\ t == reduce(lambda r,pm:r*pm[0]**pm[1],factor(t),1L)."; static PyObject * Pysym_factor(PyObject *self, PyObject *args) { mpz_t t; unsigned long p; PyObject *t_py = NULL; PyObject *p_py = NULL; PyObject *res = NULL; if (!PyArg_ParseTuple(args, "O&|O&",\ Pympz_convert_arg,&t_py,\ Pympz_convert_arg,&p_py)) return NULL; res = PyList_New(0); if (p_py==NULL) p = 0; else p = mpz_get_ui(Pympz_AS_MPZ(p_py)); mpz_init_set(t,Pympz_AS_MPZ(t_py)); if (mpz_sgn(t)==0) { res_append(res,0,1); return res; } if (mpz_sgn(t)==-1) { res_append_si(res,-1,1); mpz_neg(t,t); } factor(t,p,res); if (PyList_Size(res)==0) res_append(res,1,1); return res; } static PyMethodDef Pysym_methods [] = { { "factor", Pysym_factor, METH_VARARGS, doc_factor }, { NULL, NULL} }; #if PY_MAJOR_VERSION >= 3 #define INITERROR return NULL static struct PyModuleDef Pysym_module = { PyModuleDef_HEAD_INIT, "pysymbolicext", NULL, -1, Pysym_methods, NULL, NULL, NULL, NULL }; #ifdef _MSC_VER __declspec(dllexport) #endif PyObject * PyInit_pysymbolicext(void) #else #define INITERROR return DL_EXPORT(void) initpysymbolicext(void) #endif { #if PY_MAJOR_VERSION >= 3 PyObject *pysymbolicext_module = NULL; pysymbolicext_module = PyModule_Create(&Pysym_module); #else Py_InitModule("pysymbolicext", Pysym_methods); #endif import_gmpy(); #if PY_MAJOR_VERSION >= 3 return pysymbolicext_module; #endif } gmpy-1.17/src/mp_lib.vsprops0000666000000000000000000000045212174774730014624 0ustar rootroot gmpy-1.17/src/mpz_pylong.c0000666000000000000000000001575512174774730014302 0ustar rootroot/* mpz <-> pylong conversion and "pythonhash" for mpz * * Originally written for sage (http://sagemath.org) by Gonzalo Tornari­a * . If you improve on these functions, please * contribute them back to sage by posting to sage-devel@googlegroups.com * or by sending an email to the original author. * * Integration with gmpy by Case Van Horsen . * * License: LGPL v2 or later * */ /* This file created by merging mpn_pylong and mpz_pylong. Permission * was granted by the original author to make this code available under * the LGPLv2+ license. */ /* This code assumes that SHIFT < GMP_NUMB_BITS */ #if PyLong_SHIFT >= GMP_NUMB_BITS #error "Python limb larger than GMP limb !!!" #endif #ifndef ABS #define ABS(a) (((a) < 0) ? -(a) : (a)) #endif /* Use these "portable" (I hope) sizebits functions. * We could implement this in terms of count_leading_zeros from GMP, * but it is not exported! */ static const unsigned char __sizebits_tab[128] = { 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 }; #if GMP_LIMB_BITS > 64 #error "word size > 64 unsupported" #endif static inline size_t mpn_sizebits(mp_ptr up, size_t un) { size_t cnt; mp_limb_t x; if (un==0) return 0; cnt = (un - 1) * GMP_NUMB_BITS; x = up[un - 1]; #if GMP_LIMB_BITS > 32 if ((x >> 32) != 0) { x >>= 32; cnt += 32; } #endif #if GMP_LIMB_BITS > 16 if ((x >> 16) != 0) { x >>= 16; cnt += 16; } #endif #if GMP_LIMB_BITS > 8 if ((x >> 8) != 0) { x >>= 8; cnt += 8; } #endif return cnt + ((x & 0x80) ? 8 : __sizebits_tab[x]); } static inline size_t pylong_sizebits(digit *digits, size_t size) { size_t cnt; digit x; if (size==0) return 0; cnt = (size - 1) * PyLong_SHIFT; x = digits[size - 1]; #if PyLong_SHIFT > 32 if ((x >> 32) != 0) { x >>= 32; cnt += 32; } #endif #if PyLong_SHIFT > 16 if ((x >> 16) != 0) { x >>= 16; cnt += 16; } #endif #if PyLong_SHIFT > 8 if ((x >> 8) != 0) { x >>= 8; cnt += 8; } #endif return cnt + ((x & 0x80) ? 8 : __sizebits_tab[x]); } /* mpn -> pylong conversion */ size_t mpn_pylong_size (mp_ptr up, size_t un) { return (mpn_sizebits(up, un) + PyLong_SHIFT - 1) / PyLong_SHIFT; } /* this is based from GMP code in mpn/get_str.c */ /* Assume digits points to a chunk of size size * where size >= mpn_pylong_size(up, un) */ void mpn_get_pylong (digit *digits, size_t size, mp_ptr up, size_t un) { mp_limb_t n1, n0; size_t i; ssize_t bit_pos; /* point past the allocated chunk */ digit * s = digits + size; /* input length 0 is special ! */ if (un == 0) { while (size) digits[--size]=0; return; } i = un - 1; n1 = up[i]; bit_pos = size * PyLong_SHIFT - i * GMP_NUMB_BITS; for (;;) { bit_pos -= PyLong_SHIFT; while (bit_pos >= 0) { *--s = (n1 >> bit_pos) & PyLong_MASK; bit_pos -= PyLong_SHIFT; } if (i == 0) break; n0 = (n1 << -bit_pos) & PyLong_MASK; n1 = up[--i]; bit_pos += GMP_NUMB_BITS; *--s = (digit)(n0 | (n1 >> bit_pos)); } } /* pylong -> mpn conversion */ size_t mpn_size_from_pylong (digit *digits, size_t size) { return (pylong_sizebits(digits, size) + GMP_NUMB_BITS - 1) / GMP_NUMB_BITS; } void mpn_set_pylong (mp_ptr up, size_t un, digit *digits, size_t size) { mp_limb_t n1, d; size_t i; ssize_t bit_pos; /* point past the allocated chunk */ digit * s = digits + size; /* input length 0 is special ! */ if (size == 0) { while (un) up[--un]=0; return; } i = un - 1; n1 = 0; bit_pos = size * PyLong_SHIFT - i * GMP_NUMB_BITS; for (;;) { bit_pos -= PyLong_SHIFT; while (bit_pos >= 0) { d = (mp_limb_t) *--s; n1 |= (d << bit_pos) & GMP_NUMB_MASK; bit_pos -= PyLong_SHIFT; } if (i == 0) break; d = (mp_limb_t) *--s; /* add some high bits of d; maybe none if bit_pos=-SHIFT */ up[i--] = n1 | (d & PyLong_MASK) >> -bit_pos; bit_pos += GMP_NUMB_BITS; n1 = (d << bit_pos) & GMP_NUMB_MASK; } up[0] = n1; } /************************************************************/ /* Hashing functions */ #define LONG_BIT_SHIFT (8*sizeof(long) - PyLong_SHIFT) /* * for an mpz, this number has to be multiplied by the sign * also remember to catch -1 and map it to -2 ! */ long mpn_pythonhash (mp_ptr up, mp_size_t un) { mp_limb_t n1, n0; mp_size_t i; ssize_t bit_pos; long x = 0; /* input length 0 is special ! */ if (un == 0) return 0; i = un - 1; n1 = up[i]; { size_t bits; bits = mpn_sizebits(up, un) + PyLong_SHIFT - 1; bits -= bits % PyLong_SHIFT; /* position of the MSW in base 2^SHIFT, counted from the MSW in * the GMP representation (in base 2^GMP_NUMB_BITS) */ bit_pos = bits - i * GMP_NUMB_BITS; } for (;;) { while (bit_pos >= 0) { /* Force a native long #-bits (32 or 64) circular shift */ x = ((x << PyLong_SHIFT) & ~(long)PyLong_MASK) | ((x >> LONG_BIT_SHIFT) & (long)PyLong_MASK); /* Shifting to the right by more than wordsize bits actually shifts by (wordsize % 32) bits -- which is *not* the intended behavior here. */ if (bit_pos <= 8*sizeof(mp_limb_t)) x += (n1 >> bit_pos) & (long)PyLong_MASK; bit_pos -= PyLong_SHIFT; } i--; if (i < 0) break; n0 = (n1 << -bit_pos) & (long)PyLong_MASK; n1 = up[i]; bit_pos += GMP_NUMB_BITS; /* Force a native long #-bits (32 or 64) circular shift */ x = ((x << PyLong_SHIFT) & ~(long)PyLong_MASK) | ((x >> LONG_BIT_SHIFT) & (long)PyLong_MASK); x += (long)(n0 | (n1 >> bit_pos)); bit_pos -= PyLong_SHIFT; } return x; } /* mpz python hash */ long mpz_pythonhash(mpz_srcptr z) { long x = mpn_pythonhash(z->_mp_d, ABS(z->_mp_size)); if (z->_mp_size < 0) x = -x; if (x == -1) x = -2; return x; } /* mpz -> pylong conversion */ PyObject * mpz_get_PyLong(mpz_srcptr z) { size_t size = mpn_pylong_size(z->_mp_d, ABS(z->_mp_size)); PyLongObject *lptr = PyObject_NEW_VAR(PyLongObject, &PyLong_Type, size); if (lptr != NULL) { mpn_get_pylong(lptr->ob_digit, size, z->_mp_d, ABS(z->_mp_size)); if (z->_mp_size < 0) Py_SIZE(lptr) = -(Py_SIZE(lptr)); } return (PyObject *) lptr; } /* pylong -> mpz conversion */ int mpz_set_PyLong(mpz_ptr z, PyObject * lsrc) { register PyLongObject * lptr = (PyLongObject *) lsrc; ssize_t size; if (lptr==NULL || !PyLong_Check(lptr)) { PyErr_BadInternalCall(); return -1; } size = (ssize_t)mpn_size_from_pylong(lptr->ob_digit, ABS(Py_SIZE(lptr))); if (z->_mp_alloc < size) _mpz_realloc (z, (mp_size_t)size); mpn_set_pylong(z->_mp_d, size, lptr->ob_digit, ABS(Py_SIZE(lptr))); z->_mp_size = (int)(Py_SIZE(lptr) < 0 ? -size : size); return (int)size; } gmpy-1.17/src/gmpy_utility.c0000666000000000000000000000554112174774730014633 0ustar rootroot/* Low-level utility routines. * * The routines are: * mpz_set_PyInt(mpz_t, PyObject) Python 2.X only. * mpz_set_PyLong(mpz_t, PyObject) * mpf_normalize(mpf_t) * Pympz_FROM_MPZ(mpz_t) * Pympq_FROM_MPQ(mpq_t) * Pympf_FROM_MPF(mpf_t) * * This file should be considered part of gmpy.c. */ #ifdef FALSE #if PY_MAJOR_VERSION == 2 static void mpz_set_PyInt(mpz_t rop, PyObject *obj) { assert(PyInt_Check(obj)); mpz_set_si(rop, PyInt_AsLong(obj)); return; } #endif #endif /* * Normalize the internal representation of an mpf. GMP allocates 1 * or more additional limbs to store the mantissa of an mpf. The * additional limbs may or may not be used but when used, they can * confuse comparisions. We will normalize all mpf such that the additional * limbs, if used, are set to 0. */ static void mpf_normalize(mpf_t op) { Py_ssize_t size, prec, toclear, temp, i; mp_limb_t bit1, rem, carry; prec = mpf_get_prec(op); size = mpf_size(op); toclear = size - ((prec / GMP_NUMB_BITS) + 1); if(toclear>0) { bit1 = (op->_mp_d[toclear-1] & ((mp_limb_t)1 << (GMP_NUMB_BITS - 1))) ? 1 : 0; rem = (op->_mp_d[toclear-1] & (((mp_limb_t)1 << (GMP_NUMB_BITS - 1)) - 1)) ? 1 : 0; carry = bit1 && ((op->_mp_d[toclear] & 1) || rem); } else { carry = 0; } if(options.debug) { fprintf(stderr, "prec %ld size %ld toclear %ld carry %ld\n", prec, size, toclear, carry); for(i=0; i_mp_d[i]); } temp = toclear; if(temp>0) { op->_mp_d[--temp] = 0; } if(carry) { if(options.debug) { fprintf(stderr, "adding carry bit\n"); } carry = mpn_add_1(op->_mp_d + toclear, op->_mp_d + toclear, size-toclear, carry); if(carry) { if(options.debug) { fprintf(stderr, "carry bit extended\n"); } op->_mp_d[size-1] = 1; op->_mp_exp++; } } if(options.debug) { for(i=0; i_mp_d[i]); } } static PympzObject * Pympz_FROM_MPZ(mpz_t z) { PympzObject *self; if(!(self = PyObject_New(PympzObject, &Pympz_Type))) return NULL; self->z[0] = z[0]; return self; } #ifdef FALSE static PympqObject * Pympq_FROM_MPQ(mpq_t q) { PympqObject *self; if(!(self = PyObject_New(PympqObject, &Pympq_Type))) return NULL; self->q[0] = q[0]; return self; } static PympfObject * Pympf_FROM_MPF(mpf_t f, unsigned int bits) { PympfObject *self; if(!(self = PyObject_New(PympfObject, &Pympf_Type))) return NULL; if(bits < options.minprec) bits = options.minprec; self->f[0] = f[0]; self->rebits = bits; return self; } #endif /* End of low-level utility routines. */ gmpy-1.17/src/gmpy_mpz_mutate.c0000666000000000000000000003671612174774730015325 0ustar rootroot/* gmpy_mpz_mutate.c * * Provides inplace mutating operations for mpz * * NOTE: The inplace functions in this file will change the value of an mpz * without creating a new object. When this file is used instead of * gmpy_mpz_mutate (by passing the argument -DMUTATE to build_ext) * hashing must also be disabled. The gmpy test suite will fail if * MUTATE is enabled; no attempt will be made to fix the test suite. * * This file should be considered part of gmpy.c. */ #include #define Py_RETURN_NOTIMPLEMENTED\ return Py_INCREF(Py_NotImplemented), Py_NotImplemented /* Inplace mpz addition. Does NOT mutate! */ static PyObject * Pympz_inplace_add(PyObject *a, PyObject *b) { mpz_t tempz; long temp; #if PY_MAJOR_VERSION == 3 int overflow; #endif /* Try to make mpz + small_int faster */ if(Pympz_Check(a)) { #if PY_MAJOR_VERSION == 2 if(PyInt_Check(b)) { if(options.debug) fprintf(stderr, "Adding (mpz,small_int)\n"); if((temp = PyInt_AS_LONG(b)) >= 0) { mpz_add_ui(Pympz_AS_MPZ(a), Pympz_AS_MPZ(a), temp); } else { mpz_sub_ui(Pympz_AS_MPZ(a), Pympz_AS_MPZ(a), -temp); } Py_INCREF(a); return a; } #endif if(PyLong_Check(b)) { if(options.debug) fprintf(stderr, "Adding (mpz,long)\n"); #if PY_MAJOR_VERSION == 3 temp = PyLong_AsLongAndOverflow(b, &overflow); if(overflow) { #else temp = PyLong_AsLong(b); if(PyErr_Occurred()) { PyErr_Clear(); #endif mpz_inoc(tempz); mpz_set_PyLong(tempz, b); mpz_add(Pympz_AS_MPZ(a), Pympz_AS_MPZ(a), tempz); mpz_cloc(tempz); } else if(temp >= 0) { mpz_add_ui(Pympz_AS_MPZ(a), Pympz_AS_MPZ(a), temp); } else { mpz_sub_ui(Pympz_AS_MPZ(a), Pympz_AS_MPZ(a), -temp); } Py_INCREF(a); return a; } if(Pympz_Check(b)) { mpz_add(Pympz_AS_MPZ(a), Pympz_AS_MPZ(a), Pympz_AS_MPZ(b)); Py_INCREF(a); return a; } } if(options.debug) fprintf(stderr, "Pympz_inplace_add returned NotImplemented\n"); Py_RETURN_NOTIMPLEMENTED; } /* Inplace mpz subtraction. Does NOT mutate! */ static PyObject * Pympz_inplace_sub(PyObject *a, PyObject *b) { mpz_t tempz; long temp; #if PY_MAJOR_VERSION == 3 int overflow; #endif if(Pympz_Check(a)) { #if PY_MAJOR_VERSION == 2 if(PyInt_Check(b)) { if (options.debug) fprintf(stderr, "Subtracting (mpz,small_int)\n"); if((temp = PyInt_AS_LONG(b)) >= 0) { mpz_sub_ui(Pympz_AS_MPZ(a), Pympz_AS_MPZ(a), temp); } else { mpz_add_ui(Pympz_AS_MPZ(a), Pympz_AS_MPZ(a), -temp); } Py_INCREF(a); return a; } #endif if(PyLong_Check(b)) { if (options.debug) fprintf(stderr, "Subtracting (mpz,long)\n"); #if PY_MAJOR_VERSION == 3 temp = PyLong_AsLongAndOverflow(b, &overflow); if(overflow) { #else temp = PyLong_AsLong(b); if(PyErr_Occurred()) { PyErr_Clear(); #endif mpz_inoc(tempz); mpz_set_PyLong(tempz, b); mpz_sub(Pympz_AS_MPZ(a), Pympz_AS_MPZ(a), tempz); mpz_cloc(tempz); } else if(temp >= 0) { mpz_sub_ui(Pympz_AS_MPZ(a), Pympz_AS_MPZ(a), temp); } else { mpz_add_ui(Pympz_AS_MPZ(a), Pympz_AS_MPZ(a), -temp); } Py_INCREF(a); return a; } if(Pympz_Check(b)) { mpz_sub(Pympz_AS_MPZ(a), Pympz_AS_MPZ(a), Pympz_AS_MPZ(b)); Py_INCREF(a); return a; } } if(!options.debug) fprintf(stderr, "Pympz_inplace_sub returned NotImplemented\n"); Py_RETURN_NOTIMPLEMENTED; } /* Inplace mpz multiplication. Does NOT mutate! */ static PyObject * Pympz_inplace_mul(PyObject *a, PyObject *b) { mpz_t tempz; long temp; #if PY_MAJOR_VERSION == 3 int overflow; #endif if(Pympz_Check(a)) { #if PY_MAJOR_VERSION == 2 if(PyInt_Check(b)) { if (options.debug) fprintf(stderr, "Multiplying (mpz,small_int)\n"); mpz_mul_si(Pympz_AS_MPZ(a), Pympz_AS_MPZ(a), PyInt_AS_LONG(b)); Py_INCREF(a); return a; } #endif if(PyLong_Check(b)) { if (options.debug) fprintf(stderr, "Multiplying (mpz,long)\n"); #if PY_MAJOR_VERSION == 3 temp = PyLong_AsLongAndOverflow(b, &overflow); if(overflow) { #else temp = PyLong_AsLong(b); if(PyErr_Occurred()) { PyErr_Clear(); #endif mpz_inoc(tempz); mpz_set_PyLong(tempz, b); mpz_mul(Pympz_AS_MPZ(a), Pympz_AS_MPZ(a), tempz); mpz_cloc(tempz); } else { mpz_mul_si(Pympz_AS_MPZ(a), Pympz_AS_MPZ(a), temp); } Py_INCREF(a); return a; } if(Pympz_Check(b)) { mpz_mul(Pympz_AS_MPZ(a), Pympz_AS_MPZ(a), Pympz_AS_MPZ(b)); Py_INCREF(a); return a; } } if(!options.debug) fprintf(stderr, "Pympz_inplace_mul returned NotImplemented\n"); Py_RETURN_NOTIMPLEMENTED; } /* Pympany_floordiv follows the // semantics from Python 3.x. The result is * an mpz when the arguments are mpz or mpq, but the result is an mpf when * the arguments are mpf. */ static PyObject * Pympz_inplace_floordiv(PyObject *a, PyObject *b) { mpz_t tempz; long temp; #if PY_MAJOR_VERSION == 3 int overflow; #endif if(Pympz_Check(a)) { #if PY_MAJOR_VERSION == 2 if(PyInt_Check(b)) { if (options.debug) fprintf(stderr, "Floor divide (mpz,small_int)\n"); if((temp=PyInt_AS_LONG(b)) > 0) { mpz_fdiv_q_ui(Pympz_AS_MPZ(a), Pympz_AS_MPZ(a), temp); } else if(temp == 0) { PyErr_SetString(PyExc_ZeroDivisionError, "mpz division by zero"); return NULL; } else { mpz_cdiv_q_ui(Pympz_AS_MPZ(a), Pympz_AS_MPZ(a), -temp); mpz_neg(Pympz_AS_MPZ(a), Pympz_AS_MPZ(a)); } Py_INCREF(a); return a; } #endif if(PyLong_Check(b)) { if (options.debug) fprintf(stderr, "Floor divide (mpz,long)\n"); #if PY_MAJOR_VERSION == 3 temp = PyLong_AsLongAndOverflow(b, &overflow); if(overflow) { #else temp = PyLong_AsLong(b); if(PyErr_Occurred()) { PyErr_Clear(); #endif mpz_inoc(tempz); mpz_set_PyLong(tempz, b); mpz_fdiv_q(Pympz_AS_MPZ(a), Pympz_AS_MPZ(a), tempz); mpz_cloc(tempz); } else if(temp == 0) { PyErr_SetString(PyExc_ZeroDivisionError, "mpz division by zero"); return NULL; } else if(temp > 0) { mpz_fdiv_q_ui(Pympz_AS_MPZ(a), Pympz_AS_MPZ(a), temp); } else { mpz_cdiv_q_ui(Pympz_AS_MPZ(a), Pympz_AS_MPZ(a), -temp); mpz_neg(Pympz_AS_MPZ(a), Pympz_AS_MPZ(a)); } Py_INCREF(a); return a; } if(Pympz_Check(b)) { if(mpz_sgn(Pympz_AS_MPZ(b)) == 0) { PyErr_SetString(PyExc_ZeroDivisionError, "mpz division by zero"); return NULL; } mpz_fdiv_q(Pympz_AS_MPZ(a), Pympz_AS_MPZ(a), Pympz_AS_MPZ(b)); Py_INCREF(a); return a; } } if(options.debug) fprintf(stderr, "Pympz_inplace_floordiv returned NotImplemented\n"); Py_RETURN_NOTIMPLEMENTED; } /* Inplace mpz remainder. Does NOT mutate! */ static PyObject * Pympz_inplace_rem(PyObject *a, PyObject *b) { mpz_t tempz; long temp; #if PY_MAJOR_VERSION == 3 int overflow; #endif if(Pympz_Check(a)) { #if PY_MAJOR_VERSION == 2 if(PyInt_Check(b)) { if (options.debug) fprintf(stderr, "Modulo (mpz,small_int)\n"); if((temp=PyInt_AS_LONG(b)) > 0) { mpz_fdiv_r_ui(Pympz_AS_MPZ(a), Pympz_AS_MPZ(a), temp); } else if(temp == 0) { PyErr_SetString(PyExc_ZeroDivisionError, "mpz modulo by zero"); return NULL; } else { mpz_cdiv_r_ui(Pympz_AS_MPZ(a), Pympz_AS_MPZ(a), -temp); } Py_INCREF(a); return a; } #endif if(PyLong_Check(b)) { if (options.debug) fprintf(stderr, "Modulo (mpz,long)\n"); #if PY_MAJOR_VERSION == 3 temp = PyLong_AsLongAndOverflow(b, &overflow); if(overflow) { #else temp = PyLong_AsLong(b); if(PyErr_Occurred()) { PyErr_Clear(); #endif mpz_inoc(tempz); mpz_set_PyLong(tempz, b); mpz_fdiv_r(Pympz_AS_MPZ(a), Pympz_AS_MPZ(a), tempz); mpz_cloc(tempz); } else if(temp > 0) { mpz_fdiv_r_ui(Pympz_AS_MPZ(a), Pympz_AS_MPZ(a), temp); } else if(temp == 0) { PyErr_SetString(PyExc_ZeroDivisionError, "mpz modulo by zero"); return NULL; } else { mpz_cdiv_r_ui(Pympz_AS_MPZ(a), Pympz_AS_MPZ(a), -temp); } Py_INCREF(a); return a; } if(Pympz_Check(b)) { if(options.debug) fprintf(stderr, "Modulo (integer,integer)\n"); if(mpz_sgn(Pympz_AS_MPZ(b)) == 0) { PyErr_SetString(PyExc_ZeroDivisionError, "mpz modulo by zero"); return NULL; } mpz_fdiv_r(Pympz_AS_MPZ(a), Pympz_AS_MPZ(a), Pympz_AS_MPZ(b)); Py_INCREF(a); return a; } } if(options.debug) fprintf(stderr, "Pympz_inplace_rem returned NotImplemented\n"); Py_RETURN_NOTIMPLEMENTED; } /* Inplace mpz rshift. Does NOT mutate! */ static PyObject * Pympz_inplace_rshift(PyObject *a, PyObject *b) { long temp; #if PY_MAJOR_VERSION == 3 int overflow; #endif /* Try to make mpz + small_int faster */ if(Pympz_Check(a)) { #if PY_MAJOR_VERSION == 2 if(PyInt_Check(b)) { if(options.debug) fprintf(stderr, "right shift\n"); if((temp = PyInt_AS_LONG(b)) >= 0) { mpz_fdiv_q_2exp(Pympz_AS_MPZ(a), Pympz_AS_MPZ(a), temp); Py_INCREF(a); return a; } else { PyErr_SetString(PyExc_ValueError, "negative shift count"); return NULL; } } #endif if(PyLong_Check(b)) { if(options.debug) fprintf(stderr, "right shift\n"); #if PY_MAJOR_VERSION == 3 temp = PyLong_AsLongAndOverflow(b, &overflow); if(overflow) { #else temp = PyLong_AsLong(b); if(PyErr_Occurred()) { #endif PyErr_SetString(PyExc_ValueError, "outrageous shift count"); return NULL; } else if(temp >= 0) { mpz_fdiv_q_2exp(Pympz_AS_MPZ(a), Pympz_AS_MPZ(a), temp); Py_INCREF(a); return a; } else { PyErr_SetString(PyExc_ValueError, "negative shift count"); return NULL; } } if(Pympz_Check(b)) { if(mpz_sgn(Pympz_AS_MPZ(b)) < 0) { PyErr_SetString(PyExc_ValueError, "negative shift count"); return NULL; } if(!mpz_fits_slong_p(Pympz_AS_MPZ(b))) { PyErr_SetString(PyExc_OverflowError, "outrageous shift count"); return NULL; } temp = mpz_get_si(Pympz_AS_MPZ(b)); mpz_fdiv_q_2exp(Pympz_AS_MPZ(a), Pympz_AS_MPZ(a), temp); Py_INCREF(a); return a; } } if(options.debug) fprintf(stderr, "Pympz_inplace_rshift returned NotImplemented\n"); Py_RETURN_NOTIMPLEMENTED; } /* Inplace mpz lshift. Does NOT mutate! */ static PyObject * Pympz_inplace_lshift(PyObject *a, PyObject *b) { long temp; #if PY_MAJOR_VERSION == 3 int overflow; #endif /* Try to make mpz + small_int faster */ if(Pympz_Check(a)) { #if PY_MAJOR_VERSION == 2 if(PyInt_Check(b)) { if(options.debug) fprintf(stderr, "left shift\n"); if((temp = PyInt_AS_LONG(b)) >= 0) { mpz_mul_2exp(Pympz_AS_MPZ(a), Pympz_AS_MPZ(a), temp); Py_INCREF(a); return a; } else { PyErr_SetString(PyExc_ValueError, "negative shift count"); return NULL; } } #endif if(PyLong_Check(b)) { if(options.debug) fprintf(stderr, "left shift\n"); #if PY_MAJOR_VERSION == 3 temp = PyLong_AsLongAndOverflow(b, &overflow); if(overflow) { #else temp = PyLong_AsLong(b); if(PyErr_Occurred()) { #endif PyErr_SetString(PyExc_ValueError, "outrageous shift count"); return NULL; } else if(temp >= 0) { mpz_mul_2exp(Pympz_AS_MPZ(a), Pympz_AS_MPZ(a), temp); } else { PyErr_SetString(PyExc_ValueError, "negative shift count"); return NULL; } } if(Pympz_Check(b)) { if(mpz_sgn(Pympz_AS_MPZ(b)) < 0) { PyErr_SetString(PyExc_ValueError, "negative shift count"); return NULL; } if(!mpz_fits_slong_p(Pympz_AS_MPZ(b))) { PyErr_SetString(PyExc_OverflowError, "outrageous shift count"); return NULL; } temp = mpz_get_si(Pympz_AS_MPZ(b)); mpz_mul_2exp(Pympz_AS_MPZ(a), Pympz_AS_MPZ(a), temp); Py_INCREF(a); return a; } } if(options.debug) fprintf(stderr, "Pympz_inplace_lshift returned NotImplemented\n"); Py_RETURN_NOTIMPLEMENTED; } /* Inplace mpz_pow. Does NOT mutate. */ static PyObject * Pympany_pow(PyObject *in_b, PyObject *in_e, PyObject *in_m); static PyObject * Pympz_inplace_pow(PyObject *in_b, PyObject *in_e, PyObject *in_m) { PympzObject *e = 0; unsigned long el; if(options.debug) fprintf(stderr, "Pympz_inplace_pow\n"); if(!Pympz_Check(in_b)) { PyErr_SetString(PyExc_TypeError, "bogus base type"); return NULL; } if(in_m != Py_None) { PyErr_SetString(PyExc_SystemError, "modulo not expected"); return NULL; } e = Pympz_From_Integer(in_e); if(!e) { PyErr_SetString(PyExc_TypeError, "expected an integer exponent"); return NULL; } if(mpz_sgn(e->z) < 0) { PyErr_SetString(PyExc_ValueError, "mpz.pow with negative power"); Py_DECREF((PyObject*)e); return NULL; } if(!mpz_fits_ulong_p(e->z)) { PyErr_SetString(PyExc_ValueError, "mpz.pow outrageous exponent"); Py_DECREF((PyObject*)e); return NULL; } el = mpz_get_ui(e->z); mpz_pow_ui(Pympz_AS_MPZ(in_b), Pympz_AS_MPZ(in_b), el); Py_DECREF((PyObject*)e); Py_INCREF((PyObject*)in_b); return (PyObject*)in_b; } gmpy-1.17/src/gmpy_mpz_inplace.c0000666000000000000000000003671012174774730015433 0ustar rootroot/* gmpy_mpz_inplace.c * * Provides inplace operations for mpz * * NOTE: These functions do NOT mutate the mpz. * * This file should be considered part of gmpy.c. */ #include #define Py_RETURN_NOTIMPLEMENTED\ return Py_INCREF(Py_NotImplemented), Py_NotImplemented /* Inplace mpz addition. Does NOT mutate! */ static PyObject * Pympz_inplace_add(PyObject *a, PyObject *b) { PympzObject *rz; mpz_t tempz; long temp; #if PY_MAJOR_VERSION == 3 int overflow; #endif /* Try to make mpz + small_int faster */ if(!(rz = Pympz_new())) return NULL; if(Pympz_Check(a)) { #if PY_MAJOR_VERSION == 2 if(PyInt_Check(b)) { if(options.debug) fprintf(stderr, "Adding (mpz,small_int)\n"); if((temp = PyInt_AS_LONG(b)) >= 0) { mpz_add_ui(rz->z, Pympz_AS_MPZ(a), temp); } else { mpz_sub_ui(rz->z, Pympz_AS_MPZ(a), -temp); } return (PyObject *)rz; } #endif if(PyLong_Check(b)) { if(options.debug) fprintf(stderr, "Adding (mpz,long)\n"); #if PY_MAJOR_VERSION == 3 temp = PyLong_AsLongAndOverflow(b, &overflow); if(overflow) { #else temp = PyLong_AsLong(b); if(PyErr_Occurred()) { PyErr_Clear(); #endif mpz_inoc(tempz); mpz_set_PyLong(tempz, b); mpz_add(rz->z, Pympz_AS_MPZ(a), tempz); mpz_cloc(tempz); } else if(temp >= 0) { mpz_add_ui(rz->z, Pympz_AS_MPZ(a), temp); } else { mpz_sub_ui(rz->z, Pympz_AS_MPZ(a), -temp); } return (PyObject*)rz; } if(Pympz_Check(b)) { mpz_add(rz->z, Pympz_AS_MPZ(a), Pympz_AS_MPZ(b)); return (PyObject*)rz; } } if(options.debug) fprintf(stderr, "Pympz_inplace_add returned NotImplemented\n"); Py_RETURN_NOTIMPLEMENTED; } /* Inplace mpz subtraction. Does NOT mutate! */ static PyObject * Pympz_inplace_sub(PyObject *a, PyObject *b) { PympzObject *rz; mpz_t tempz; long temp; #if PY_MAJOR_VERSION == 3 int overflow; #endif if(!(rz = Pympz_new())) return NULL; if(Pympz_Check(a)) { #if PY_MAJOR_VERSION == 2 if(PyInt_Check(b)) { if (options.debug) fprintf(stderr, "Subtracting (mpz,small_int)\n"); if((temp = PyInt_AS_LONG(b)) >= 0) { mpz_sub_ui(rz->z, Pympz_AS_MPZ(a), temp); } else { mpz_add_ui(rz->z, Pympz_AS_MPZ(a), -temp); } return (PyObject *)rz; } #endif if(PyLong_Check(b)) { if (options.debug) fprintf(stderr, "Subtracting (mpz,long)\n"); #if PY_MAJOR_VERSION == 3 temp = PyLong_AsLongAndOverflow(b, &overflow); if(overflow) { #else temp = PyLong_AsLong(b); if(PyErr_Occurred()) { PyErr_Clear(); #endif mpz_inoc(tempz); mpz_set_PyLong(tempz, b); mpz_sub(rz->z, Pympz_AS_MPZ(a), tempz); mpz_cloc(tempz); } else if(temp >= 0) { mpz_sub_ui(rz->z, Pympz_AS_MPZ(a), temp); } else { mpz_add_ui(rz->z, Pympz_AS_MPZ(a), -temp); } return (PyObject*)rz; } if(Pympz_Check(b)) { mpz_sub(rz->z, Pympz_AS_MPZ(a), Pympz_AS_MPZ(b)); return (PyObject*)rz; } } if(!options.debug) fprintf(stderr, "Pympz_inplace_sub returned NotImplemented\n"); Py_RETURN_NOTIMPLEMENTED; } /* Inplace mpz multiplication. Does NOT mutate! */ static PyObject * Pympz_inplace_mul(PyObject *a, PyObject *b) { PympzObject *rz; mpz_t tempz; long temp; #if PY_MAJOR_VERSION == 3 int overflow; #endif if(!(rz = Pympz_new())) return NULL; if(Pympz_Check(a)) { #if PY_MAJOR_VERSION == 2 if(PyInt_Check(b)) { if (options.debug) fprintf(stderr, "Multiplying (mpz,small_int)\n"); mpz_mul_si(rz->z, Pympz_AS_MPZ(a), PyInt_AS_LONG(b)); return (PyObject *)rz; } #endif if(PyLong_Check(b)) { if (options.debug) fprintf(stderr, "Multiplying (mpz,long)\n"); #if PY_MAJOR_VERSION == 3 temp = PyLong_AsLongAndOverflow(b, &overflow); if(overflow) { #else temp = PyLong_AsLong(b); if(PyErr_Occurred()) { PyErr_Clear(); #endif mpz_inoc(tempz); mpz_set_PyLong(tempz, b); mpz_mul(rz->z, Pympz_AS_MPZ(a), tempz); mpz_cloc(tempz); } else { mpz_mul_si(rz->z, Pympz_AS_MPZ(a), temp); } return (PyObject*)rz; } if(Pympz_Check(b)) { mpz_mul(rz->z, Pympz_AS_MPZ(a), Pympz_AS_MPZ(b)); return (PyObject*)rz; } } if(!options.debug) fprintf(stderr, "Pympz_inplace_mul returned NotImplemented\n"); Py_RETURN_NOTIMPLEMENTED; } /* Pympany_floordiv follows the // semantics from Python 3.x. The result is * an mpz when the arguments are mpz or mpq, but the result is an mpf when * the arguments are mpf. */ static PyObject * Pympz_inplace_floordiv(PyObject *a, PyObject *b) { PympzObject *rz; mpz_t tempz; long temp; #if PY_MAJOR_VERSION == 3 int overflow; #endif if(!(rz = Pympz_new())) return NULL; if(Pympz_Check(a)) { #if PY_MAJOR_VERSION == 2 if(PyInt_Check(b)) { if (options.debug) fprintf(stderr, "Floor divide (mpz,small_int)\n"); if((temp=PyInt_AS_LONG(b)) > 0) { mpz_fdiv_q_ui(rz->z, Pympz_AS_MPZ(a), temp); } else if(temp == 0) { PyErr_SetString(PyExc_ZeroDivisionError, "mpz division by zero"); Py_DECREF((PyObject *)rz); return NULL; } else { mpz_cdiv_q_ui(rz->z, Pympz_AS_MPZ(a), -temp); mpz_neg(rz->z, rz->z); } return (PyObject *)rz; } #endif if(PyLong_Check(b)) { if (options.debug) fprintf(stderr, "Floor divide (mpz,long)\n"); #if PY_MAJOR_VERSION == 3 temp = PyLong_AsLongAndOverflow(b, &overflow); if(overflow) { #else temp = PyLong_AsLong(b); if(PyErr_Occurred()) { PyErr_Clear(); #endif mpz_inoc(tempz); mpz_set_PyLong(tempz, b); mpz_fdiv_q(rz->z, Pympz_AS_MPZ(a), tempz); mpz_cloc(tempz); } else if(temp == 0) { PyErr_SetString(PyExc_ZeroDivisionError, "mpz division by zero"); return NULL; } else if(temp > 0) { mpz_fdiv_q_ui(rz->z, Pympz_AS_MPZ(a), temp); } else { mpz_cdiv_q_ui(rz->z, Pympz_AS_MPZ(a), -temp); mpz_neg(rz->z, rz->z); } return (PyObject*)rz; } if(Pympz_Check(b)) { if(mpz_sgn(Pympz_AS_MPZ(b)) == 0) { PyErr_SetString(PyExc_ZeroDivisionError, "mpz division by zero"); return NULL; } mpz_fdiv_q(rz->z, Pympz_AS_MPZ(a), Pympz_AS_MPZ(b)); return (PyObject*)rz; } } if(options.debug) fprintf(stderr, "Pympz_inplace_floordiv returned NotImplemented\n"); Py_RETURN_NOTIMPLEMENTED; } /* Inplace mpz remainder. Does NOT mutate! */ static PyObject * Pympz_inplace_rem(PyObject *a, PyObject *b) { PympzObject *rz; mpz_t tempz; long temp; #if PY_MAJOR_VERSION == 3 int overflow; #endif if(!(rz = Pympz_new())) return NULL; if(Pympz_Check(a)) { #if PY_MAJOR_VERSION == 2 if(PyInt_Check(b)) { if (options.debug) fprintf(stderr, "Modulo (mpz,small_int)\n"); if((temp=PyInt_AS_LONG(b)) > 0) { mpz_fdiv_r_ui(rz->z, Pympz_AS_MPZ(a), temp); } else if(temp == 0) { PyErr_SetString(PyExc_ZeroDivisionError, "mpz modulo by zero"); Py_DECREF((PyObject *)rz); return NULL; } else { mpz_cdiv_r_ui(rz->z, Pympz_AS_MPZ(a), -temp); } return (PyObject *)rz; } #endif if(PyLong_Check(b)) { if (options.debug) fprintf(stderr, "Modulo (mpz,long)\n"); #if PY_MAJOR_VERSION == 3 temp = PyLong_AsLongAndOverflow(b, &overflow); if(overflow) { #else temp = PyLong_AsLong(b); if(PyErr_Occurred()) { PyErr_Clear(); #endif mpz_inoc(tempz); mpz_set_PyLong(tempz, b); mpz_fdiv_r(rz->z, Pympz_AS_MPZ(a), tempz); mpz_cloc(tempz); } else if(temp > 0) { mpz_fdiv_r_ui(rz->z, Pympz_AS_MPZ(a), temp); } else if(temp == 0) { PyErr_SetString(PyExc_ZeroDivisionError, "mpz modulo by zero"); return NULL; } else { mpz_cdiv_r_ui(rz->z, Pympz_AS_MPZ(a), -temp); } return (PyObject*)rz; } if(Pympz_Check(b)) { if(options.debug) fprintf(stderr, "Modulo (integer,integer)\n"); if(mpz_sgn(Pympz_AS_MPZ(b)) == 0) { PyErr_SetString(PyExc_ZeroDivisionError, "mpz modulo by zero"); return NULL; } mpz_fdiv_r(rz->z, Pympz_AS_MPZ(a), Pympz_AS_MPZ(b)); return (PyObject*)rz; } } if(options.debug) fprintf(stderr, "Pympz_inplace_rem returned NotImplemented\n"); Py_RETURN_NOTIMPLEMENTED; } /* Inplace mpz rshift. Does NOT mutate! */ static PyObject * Pympz_inplace_rshift(PyObject *a, PyObject *b) { PympzObject *rz; long temp; #if PY_MAJOR_VERSION == 3 int overflow; #endif /* Try to make mpz + small_int faster */ if(!(rz = Pympz_new())) return NULL; if(Pympz_Check(a)) { #if PY_MAJOR_VERSION == 2 if(PyInt_Check(b)) { if(options.debug) fprintf(stderr, "right shift\n"); if((temp = PyInt_AS_LONG(b)) >= 0) { mpz_fdiv_q_2exp(rz->z, Pympz_AS_MPZ(a), temp); return (PyObject *)rz; } else { PyErr_SetString(PyExc_ValueError, "negative shift count"); Py_DECREF((PyObject*)rz); return NULL; } } #endif if(PyLong_Check(b)) { if(options.debug) fprintf(stderr, "right shift\n"); #if PY_MAJOR_VERSION == 3 temp = PyLong_AsLongAndOverflow(b, &overflow); if(overflow) { #else temp = PyLong_AsLong(b); if(PyErr_Occurred()) { #endif PyErr_SetString(PyExc_ValueError, "outrageous shift count"); Py_DECREF((PyObject*)rz); return NULL; } else if(temp >= 0) { mpz_fdiv_q_2exp(rz->z, Pympz_AS_MPZ(a), temp); return (PyObject *)rz; } else { PyErr_SetString(PyExc_ValueError, "negative shift count"); Py_DECREF((PyObject*)rz); return NULL; } } if(Pympz_Check(b)) { if(mpz_sgn(Pympz_AS_MPZ(b)) < 0) { PyErr_SetString(PyExc_ValueError, "negative shift count"); Py_DECREF((PyObject*)rz); return NULL; } if(!mpz_fits_slong_p(Pympz_AS_MPZ(b))) { PyErr_SetString(PyExc_OverflowError, "outrageous shift count"); Py_DECREF((PyObject*)rz); return NULL; } temp = mpz_get_si(Pympz_AS_MPZ(b)); mpz_fdiv_q_2exp(rz->z, Pympz_AS_MPZ(a), temp); return (PyObject*)rz; } } if(options.debug) fprintf(stderr, "Pympz_inplace_rshift returned NotImplemented\n"); Py_RETURN_NOTIMPLEMENTED; } /* Inplace mpz lshift. Does NOT mutate! */ static PyObject * Pympz_inplace_lshift(PyObject *a, PyObject *b) { PympzObject *rz; long temp; #if PY_MAJOR_VERSION == 3 int overflow; #endif /* Try to make mpz + small_int faster */ if(!(rz = Pympz_new())) return NULL; if(Pympz_Check(a)) { #if PY_MAJOR_VERSION == 2 if(PyInt_Check(b)) { if(options.debug) fprintf(stderr, "left shift\n"); if((temp = PyInt_AS_LONG(b)) >= 0) { mpz_mul_2exp(rz->z, Pympz_AS_MPZ(a), temp); return (PyObject *)rz; } else { PyErr_SetString(PyExc_ValueError, "negative shift count"); Py_DECREF((PyObject*)rz); return NULL; } } #endif if(PyLong_Check(b)) { if(options.debug) fprintf(stderr, "left shift\n"); #if PY_MAJOR_VERSION == 3 temp = PyLong_AsLongAndOverflow(b, &overflow); if(overflow) { #else temp = PyLong_AsLong(b); if(PyErr_Occurred()) { #endif PyErr_SetString(PyExc_ValueError, "outrageous shift count"); Py_DECREF((PyObject*)rz); return NULL; } else if(temp >= 0) { mpz_mul_2exp(rz->z, Pympz_AS_MPZ(a), temp); return (PyObject *)rz; } else { PyErr_SetString(PyExc_ValueError, "negative shift count"); Py_DECREF((PyObject*)rz); return NULL; } } if(Pympz_Check(b)) { if(mpz_sgn(Pympz_AS_MPZ(b)) < 0) { PyErr_SetString(PyExc_ValueError, "negative shift count"); Py_DECREF((PyObject*)rz); return NULL; } if(!mpz_fits_slong_p(Pympz_AS_MPZ(b))) { PyErr_SetString(PyExc_OverflowError, "outrageous shift count"); Py_DECREF((PyObject*)rz); return NULL; } temp = mpz_get_si(Pympz_AS_MPZ(b)); mpz_mul_2exp(rz->z, Pympz_AS_MPZ(a), temp); return (PyObject*)rz; } } if(options.debug) fprintf(stderr, "Pympz_inplace_lshift returned NotImplemented\n"); Py_RETURN_NOTIMPLEMENTED; } /* Inplace mpz_pow. Does NOT mutate. */ static PyObject * Pympany_pow(PyObject *in_b, PyObject *in_e, PyObject *in_m); static PyObject * Pympz_inplace_pow(PyObject *in_b, PyObject *in_e, PyObject *in_m) { PympzObject *r, *e = 0; unsigned long el; if(options.debug) fprintf(stderr, "Pympz_inplace_pow\n"); if(!Pympz_Check(in_b)) { PyErr_SetString(PyExc_TypeError, "bogus base type"); return NULL; } e = Pympz_From_Integer(in_e); if(!e || (in_m != Py_None)) { PyErr_Clear(); Py_XDECREF((PyObject*)e); return Pympany_pow(in_b, in_e, in_m); } if(mpz_sgn(e->z) < 0) { PyErr_SetString(PyExc_ValueError, "mpz.pow with negative power"); Py_DECREF((PyObject*)e); return NULL; } if(!mpz_fits_ulong_p(e->z)) { PyErr_SetString(PyExc_ValueError, "mpz.pow outrageous exponent"); Py_DECREF((PyObject*)e); return NULL; } if(!(r = Pympz_new())) { Py_DECREF((PyObject*)e); return NULL; } el = mpz_get_ui(e->z); mpz_pow_ui(r->z, Pympz_AS_MPZ(in_b), el); Py_DECREF((PyObject*)e); return (PyObject*)r; } gmpy-1.17/src/gmpy_mpmath.c0000666000000000000000000006474112174774730014425 0ustar rootroot/* gmpy_mpmath.c * * Internal helper function for mpmath. * * This file should be considered part of gmpy.c. */ static PyObject * mpmath_build_mpf(long sign, PympzObject *man, PyObject *exp, long bc) { PyObject *tup, *tsign, *tbc; if(!(tup = PyTuple_New(4))){ Py_DECREF((PyObject*)man); Py_DECREF(exp); return NULL; } if(!(tsign=Py2or3Int_FromLong(sign))){ Py_DECREF((PyObject*)man); Py_DECREF(exp); Py_DECREF(tup); return NULL; } if(!(tbc=Py2or3Int_FromLong(bc))){ Py_DECREF((PyObject*)man); Py_DECREF(exp); Py_DECREF(tup); Py_DECREF(tsign); return NULL; } PyTuple_SET_ITEM(tup, 0, tsign); PyTuple_SET_ITEM(tup, 1, (PyObject*)man); PyTuple_SET_ITEM(tup, 2, (exp)?exp:Py2or3Int_FromLong(0)); PyTuple_SET_ITEM(tup, 3, tbc); return tup; } static char doc_mpmath_normalizeg[]="\ _mpmath_normalize(...): helper function for mpmath.\n\ "; static PyObject * Pympz_mpmath_normalize(PyObject *self, PyObject *args) { long sign = 0, bc = 0, prec = 0, shift, zbits, carry = 0; PyObject *exp = 0, *newexp = 0, *newexp2 = 0, *tmp = 0; PympzObject *man = 0; mpz_t upper, lower; char rnd = 0; if(PyTuple_GET_SIZE(args) == 6){ /* Need better error-checking here. Under Python 3.0, overflow into C-long is possible. */ sign = clong_From_Integer(PyTuple_GET_ITEM(args, 0)); man = (PympzObject *)PyTuple_GET_ITEM(args, 1); exp = PyTuple_GET_ITEM(args, 2); bc = clong_From_Integer(PyTuple_GET_ITEM(args, 3)); prec = clong_From_Integer(PyTuple_GET_ITEM(args, 4)); rnd = Py2or3String_AsString(PyTuple_GET_ITEM(args, 5))[0]; if(PyErr_Occurred()){ PyErr_SetString(PyExc_TypeError, "arguments long, PympzObject*," "PyObject*, long, long, char needed"); return NULL; } } else { PyErr_SetString(PyExc_TypeError, "6 arguments required"); return NULL; } if(!Pympz_Check(man)){ PyErr_SetString(PyExc_TypeError, "argument is not an mpz"); return NULL; } /* If the mantissa is 0, return the normalized representation. */ if(!mpz_sgn(man->z)) { Py_INCREF((PyObject*)man); return mpmath_build_mpf(0, man, 0, 0); } /* if bc <= prec and the number is odd return it */ if ((bc <= prec) && mpz_odd_p(man->z)) { Py_INCREF((PyObject*)man); Py_INCREF((PyObject*)exp); return mpmath_build_mpf(sign, man, exp, bc); } mpz_inoc(upper); mpz_inoc(lower); shift = bc - prec; if(shift>0) { switch(rnd) { case 'f': if(sign) { mpz_cdiv_q_2exp(upper, man->z, shift); } else { mpz_fdiv_q_2exp(upper, man->z, shift); } break; case 'c': if(sign) { mpz_fdiv_q_2exp(upper, man->z, shift); } else { mpz_cdiv_q_2exp(upper, man->z, shift); } break; case 'd': mpz_fdiv_q_2exp(upper, man->z, shift); break; case 'u': mpz_cdiv_q_2exp(upper, man->z, shift); break; case 'n': default: mpz_tdiv_r_2exp(lower, man->z, shift); mpz_tdiv_q_2exp(upper, man->z, shift); if(mpz_sgn(lower)) { /* lower is not 0 so it must have at least 1 bit set */ if(mpz_sizeinbase(lower, 2)==shift) { /* lower is >= 1/2 */ if(mpz_scan1(lower, 0)==shift-1) { /* lower is exactly 1/2 */ if(mpz_odd_p(upper)) carry = 1; } else { carry = 1; } } } if(carry) mpz_add_ui(upper, upper, 1); } if (!(tmp = Py2or3Int_FromLong(shift))) { mpz_cloc(upper); mpz_cloc(lower); return NULL; } if (!(newexp = PyNumber_Add(exp, tmp))) { mpz_cloc(upper); mpz_cloc(lower); Py_DECREF(tmp); return NULL; } Py_DECREF(tmp); bc = prec; } else { mpz_set(upper, man->z); newexp = exp; Py_INCREF(newexp); } /* Strip trailing 0 bits. */ if((zbits = mpz_scan1(upper, 0))) mpz_tdiv_q_2exp(upper, upper, zbits); if (!(tmp = Py2or3Int_FromLong(zbits))) { mpz_cloc(upper); mpz_cloc(lower); Py_DECREF(newexp); return NULL; } if (!(newexp2 = PyNumber_Add(newexp, tmp))) { mpz_cloc(upper); mpz_cloc(lower); Py_DECREF(tmp); Py_DECREF(newexp); return NULL; } Py_DECREF(newexp); Py_DECREF(tmp); bc -= zbits; /* Check if one less than a power of 2 was rounded up. */ if(!mpz_cmp_ui(upper, 1)) bc = 1; mpz_cloc(lower); return mpmath_build_mpf(sign, Pympz_FROM_MPZ(upper), newexp2, bc); } static char doc_mpmath_createg[]="\ _mpmath_create(...): helper function for mpmath.\n\ "; static PyObject * Pympz_mpmath_create(PyObject *self, PyObject *args) { long sign, bc, shift, zbits, carry = 0; PyObject *exp = 0, *newexp = 0, *newexp2 = 0, *tmp = 0; PympzObject *man = 0, *upper = 0, *lower = 0; const char *rnd = "f"; long prec = 0; if(PyTuple_GET_SIZE(args) < 2) { PyErr_SetString(PyExc_TypeError, "mpmath_create() expects 'mpz','int'[,'int','str'] arguments"); return NULL; } switch(PyTuple_GET_SIZE(args)) { case 4: rnd = Py2or3String_AsString(PyTuple_GET_ITEM(args, 3)); case 3: prec = clong_From_Integer(PyTuple_GET_ITEM(args, 2)); if(prec == -1 && PyErr_Occurred()) return NULL; prec = abs(prec); case 2: exp = PyTuple_GET_ITEM(args, 1); case 1: man = Pympz_From_Integer(PyTuple_GET_ITEM(args, 0)); if(!man) { PyErr_SetString(PyExc_TypeError, "mpmath_create() expects 'mpz','int'[,'int','str'] arguments"); return NULL; } } /* If the mantissa is 0, return the normalized representation. */ if(!mpz_sgn(man->z)) { return mpmath_build_mpf(0, man, 0, 0); } upper = Pympz_new(); lower = Pympz_new(); if(!upper||!lower) { Py_DECREF((PyObject*)man); Py_XDECREF((PyObject*)upper); Py_XDECREF((PyObject*)lower); return NULL; } /* Extract sign, make man positive, and set bit count */ sign = (mpz_sgn(man->z) == -1); mpz_abs(upper->z, man->z); bc = mpz_sizeinbase(upper->z, 2); if(!prec) prec = bc; shift = bc - prec; if(shift>0) { switch(rnd[0]) { case 'f': if(sign) { mpz_cdiv_q_2exp(upper->z, upper->z, shift); } else { mpz_fdiv_q_2exp(upper->z, upper->z, shift); } break; case 'c': if(sign) { mpz_fdiv_q_2exp(upper->z, upper->z, shift); } else { mpz_cdiv_q_2exp(upper->z, upper->z, shift); } break; case 'd': mpz_fdiv_q_2exp(upper->z, upper->z, shift); break; case 'u': mpz_cdiv_q_2exp(upper->z, upper->z, shift); break; case 'n': default: mpz_tdiv_r_2exp(lower->z, upper->z, shift); mpz_tdiv_q_2exp(upper->z, upper->z, shift); if(mpz_sgn(lower->z)) { /* lower is not 0 so it must have at least 1 bit set */ if(mpz_sizeinbase(lower->z, 2)==shift) { /* lower is >= 1/2 */ if(mpz_scan1(lower->z, 0)==shift-1) { /* lower is exactly 1/2 */ if(mpz_odd_p(upper->z)) carry = 1; } else { carry = 1; } } } if(carry) mpz_add_ui(upper->z, upper->z, 1); } if (!(tmp = Py2or3Int_FromLong(shift))) { Py_DECREF((PyObject*)upper); Py_DECREF((PyObject*)lower); return NULL; } if (!(newexp = PyNumber_Add(exp, tmp))) { Py_DECREF((PyObject*)man); Py_DECREF((PyObject*)upper); Py_DECREF((PyObject*)lower); Py_DECREF(tmp); return NULL; } Py_DECREF(tmp); bc = prec; } else { newexp = exp; Py_INCREF(newexp); } /* Strip trailing 0 bits. */ if((zbits = mpz_scan1(upper->z, 0))) mpz_tdiv_q_2exp(upper->z, upper->z, zbits); if (!(tmp = Py2or3Int_FromLong(zbits))) { Py_DECREF((PyObject*)man); Py_DECREF((PyObject*)upper); Py_DECREF((PyObject*)lower); Py_DECREF(newexp); return NULL; } if (!(newexp2 = PyNumber_Add(newexp, tmp))) { Py_DECREF((PyObject*)man); Py_DECREF((PyObject*)upper); Py_DECREF((PyObject*)lower); Py_DECREF(tmp); Py_DECREF(newexp); return NULL; } Py_DECREF(newexp); Py_DECREF(tmp); bc -= zbits; /* Check if one less than a power of 2 was rounded up. */ if(!mpz_cmp_ui(upper->z, 1)) bc = 1; Py_DECREF((PyObject*)lower); Py_DECREF((PyObject*)man); return mpmath_build_mpf(sign, upper, newexp2, bc); } /* Second version of helper functions for mpmath. See Issue 33 for details. */ static PyObject * do_mpmath_trim(mpz_t xman, mpz_t xexp, long prec, char rnd) { PyObject *result = 0; PympzObject *rman = 0, *rexp = 0; long bc, shift, zbits, carry = 0; mpz_t lower; result = PyTuple_New(2); rman = Pympz_new(); rexp = Pympz_new(); if(!result || !rman || !rexp) { Py_XDECREF(result); Py_XDECREF((PyObject*)rman); Py_XDECREF((PyObject*)rexp); return NULL; } mpz_set(rman->z, xman); mpz_set(rexp->z, xexp); /* If the mantissa is 0, just return the canonical representation of 0. */ if(!mpz_sgn(rman->z)) { mpz_set_ui(rexp->z, 0); goto return_result; } /* Remove trailing 0 bits and adjust exponenet. */ if((zbits = mpz_scan1(rman->z, 0))) { mpz_tdiv_q_2exp(rman->z, rman->z, zbits); mpz_add_ui(rexp->z, rexp->z, zbits); } /* If prec is 0, return with trailing 0 bits removed. */ if(prec == 0) goto return_result; bc = mpz_sizeinbase(rman->z, 2); /* If bc <= prec, just return. */ if(bc <= prec) goto return_result; /* We need to round the mantissa. */ shift = bc - prec; switch(rnd) { case 'f': mpz_fdiv_q_2exp(rman->z, rman->z, shift); break; case 'c': mpz_cdiv_q_2exp(rman->z, rman->z, shift); break; case 'd': if(mpz_sgn(rman->z) > 0) { mpz_fdiv_q_2exp(rman->z, rman->z, shift); } else { mpz_cdiv_q_2exp(rman->z, rman->z, shift); } break; case 'u': if(mpz_sgn(rman->z) > 0) { mpz_cdiv_q_2exp(rman->z, rman->z, shift); } else { mpz_fdiv_q_2exp(rman->z, rman->z, shift); } break; case 'n': default: mpz_inoc(lower); mpz_tdiv_r_2exp(lower, rman->z, shift); mpz_tdiv_q_2exp(rman->z, rman->z, shift); /* lower is not 0 so it must have at least 1 bit set */ if(mpz_sizeinbase(lower, 2) == shift) { /* lower is >= 1/2 */ if(mpz_scan1(lower, 0) == shift-1) { /* lower is exactly 1/2 */ if(mpz_odd_p(rman->z)) carry = 1; } else { carry = 1; } } mpz_cloc(lower); /* Add the carry bit. */ if(carry) { if(mpz_sgn(rman->z) < 0) { mpz_sub_ui(rman->z, rman->z, 1); } else { mpz_add_ui(rman->z, rman->z, 1); } } } if((zbits = mpz_scan1(rman->z, 0))) { mpz_tdiv_q_2exp(rman->z, rman->z, zbits); mpz_add_ui(rexp->z, rexp->z, zbits); } mpz_add_ui(rexp->z, rexp->z, shift); return_result: PyTuple_SET_ITEM(result, 0, (PyObject*)rman); PyTuple_SET_ITEM(result, 1, Pympz_To_Integer(rexp)); Py_DECREF((PyObject*)rexp); return result; } static char doc_mpmath_trimg[]="\ _mpmath_trim(xman, xexp, prec, rounding):\n\ Return (man, exp) by rounding xman*(2**xexp) to prec bits using the\n\ specified rounding mode.\n\ "; static PyObject * Pympz_mpmath_trim(PyObject *self, PyObject *args) { PyObject *arg0 = 0, *arg1 = 0, *result; long prec = 0; const char *rnd = "d"; switch(PyTuple_GET_SIZE(args)) { case 4: rnd = Py2or3String_AsString(PyTuple_GET_ITEM(args, 3)); case 3: prec = clong_From_Integer(PyTuple_GET_ITEM(args, 2)); case 2: arg1 = (PyObject*)Pympz_From_Integer(PyTuple_GET_ITEM(args, 1)); case 1: arg0 = (PyObject*)Pympz_From_Integer(PyTuple_GET_ITEM(args, 0)); } if(!arg0 || !arg1 || (prec < 0) || PyErr_Occurred()) { PyErr_SetString(PyExc_TypeError, "arguments mpz, mpz, long(>=0), char needed"); Py_XDECREF(arg0); Py_XDECREF(arg1); return NULL; } else { result = do_mpmath_trim(Pympz_AS_MPZ(arg0), Pympz_AS_MPZ(arg1), prec, rnd[0]); Py_DECREF(arg0); Py_DECREF(arg1); return result; } } static char doc_mpmath_addg[]="\ _mpmath_add(xman, xexp, yman, yexp, prec, rounding):\n\ Return (man, exp) by rounding xman*2**xexp + yman*2**yexp to prec\n\ bits using the specified rounding mode.\n\ "; static PyObject * Pympz_mpmath_add(PyObject *self, PyObject *args) { PyObject *arg0 = 0, *arg1 = 0, *arg2 = 0, * arg3 = 0, *result, *temp; mpz_t man, exp, xbc_z, ybc_z, prec_z, offset_z, temp_z; long prec = 0, offset, zbits; const char *rnd = "d"; switch(PyTuple_GET_SIZE(args)) { case 6: rnd = Py2or3String_AsString(PyTuple_GET_ITEM(args, 5)); case 5: prec = clong_From_Integer(PyTuple_GET_ITEM(args, 4)); case 4: arg3 = (PyObject*)Pympz_From_Integer(PyTuple_GET_ITEM(args, 3)); case 3: arg2 = (PyObject*)Pympz_From_Integer(PyTuple_GET_ITEM(args, 2)); case 2: arg1 = (PyObject*)Pympz_From_Integer(PyTuple_GET_ITEM(args, 1)); case 1: arg0 = (PyObject*)Pympz_From_Integer(PyTuple_GET_ITEM(args, 0)); } if(!arg0 || !arg1 || !arg2 || !arg3 || (prec < 0) || PyErr_Occurred()) { PyErr_SetString(PyExc_TypeError, "arguments mpz, mpz, mpz, mpz, long(>=0), char needed"); Py_XDECREF(arg0); Py_XDECREF(arg1); Py_XDECREF(arg2); Py_XDECREF(arg3); return NULL; } /* Check if either argument is zero. */ if(mpz_sgn(Pympz_AS_MPZ(arg0)) == 0) { result = do_mpmath_trim(Pympz_AS_MPZ(arg2), Pympz_AS_MPZ(arg3), prec, rnd[0]); goto return_result; } if(mpz_sgn(Pympz_AS_MPZ(arg2)) == 0) { result = do_mpmath_trim(Pympz_AS_MPZ(arg0), Pympz_AS_MPZ(arg1), prec, rnd[0]); goto return_result; } /* Remove trailing 0 bits. */ if((zbits = mpz_scan1(Pympz_AS_MPZ(arg0), 0))) { mpz_tdiv_q_2exp(Pympz_AS_MPZ(arg0), Pympz_AS_MPZ(arg0), zbits); mpz_add_ui(Pympz_AS_MPZ(arg1), Pympz_AS_MPZ(arg1), zbits); } if((zbits = mpz_scan1(Pympz_AS_MPZ(arg2), 0))) { mpz_tdiv_q_2exp(Pympz_AS_MPZ(arg2), Pympz_AS_MPZ(arg2), zbits); mpz_add_ui(Pympz_AS_MPZ(arg3), Pympz_AS_MPZ(arg3), zbits); } /* Swap arguments to ensure arg1 >= arg3. Note: this does NOT imply that (arg0,arg1) * represents a number with a larger (in absolute terms) than (arg2,arg3). */ if(mpz_cmp(Pympz_AS_MPZ(arg1), Pympz_AS_MPZ(arg3)) < 0) { temp = arg0; arg0 = arg2; arg2 = temp; temp = arg1; arg1 = arg3; arg3 = temp; } /* Get the bit lengths of the mantissas. */ mpz_inoc(xbc_z); mpz_set_ui(xbc_z, mpz_sizeinbase(Pympz_AS_MPZ(arg0), 2)); mpz_inoc(ybc_z); mpz_set_ui(ybc_z, mpz_sizeinbase(Pympz_AS_MPZ(arg2), 2)); /* Calculate the amount arg0 must be shifted to line up with arg2. */ mpz_inoc(offset_z); mpz_set(offset_z, Pympz_AS_MPZ(arg1)); mpz_sub(offset_z, offset_z, Pympz_AS_MPZ(arg3)); /* xbc_z now has the effective bitlength. It assumes the mantissa is * shifted. */ mpz_add(xbc_z, xbc_z, offset_z); /* ybc_z is incremented by 2. If offset_z is greater than ybc_z, then * we only need to perturb the result. */ mpz_add_ui(ybc_z, ybc_z, 2); mpz_inoc(prec_z); mpz_set_ui(prec_z, prec); mpz_add_ui(prec_z, prec_z, 3); mpz_inoc(temp_z); mpz_sub(temp_z, offset_z, ybc_z); mpz_inoc(man); mpz_inoc(exp); if(prec && mpz_cmp(temp_z, prec_z) > 0) { /* only need to perturb the result */ if(!mpz_fits_slong_p(offset_z)) { PyErr_SetString(PyExc_ValueError, "offset too large"); result = NULL; goto return_result; } else { offset = mpz_get_si(offset_z); } mpz_set(man, Pympz_AS_MPZ(arg0)); mpz_mul_2exp(man, man, offset + 3); if(mpz_sgn(Pympz_AS_MPZ(arg2)) > 0) { mpz_add_ui(man, man, 1); } else { mpz_sub_ui(man, man, 1); } mpz_set(exp, Pympz_AS_MPZ(arg1)); mpz_sub_ui(exp, exp, offset + 3); result = do_mpmath_trim(man, exp, prec, rnd[0]); } else { /* do a full addition */ if(!mpz_fits_slong_p(offset_z)) { PyErr_SetString(PyExc_ValueError, "offset too large"); result = NULL; goto return_result; } else { offset = mpz_get_si(offset_z); } mpz_set(man, Pympz_AS_MPZ(arg0)); if(offset) mpz_mul_2exp(man, man, offset); mpz_add(man, man, Pympz_AS_MPZ(arg2)); result = do_mpmath_trim(man, Pympz_AS_MPZ(arg3), prec, rnd[0]); } mpz_cloc(exp); mpz_cloc(man); mpz_cloc(offset_z); mpz_cloc(temp_z); mpz_cloc(prec_z); mpz_cloc(xbc_z); mpz_cloc(ybc_z); return_result: Py_DECREF(arg0); Py_DECREF(arg1); Py_DECREF(arg2); Py_DECREF(arg3); return result; } static char doc_mpmath_multg[]="\ _mpmath_mult(xman, xexp, yman, yexp, prec, rounding):\n\ Return (man, exp) by rounding xman*2**xexp * yman*2**yexp to prec\n\ bits using the specified rounding mode.\n\ "; static PyObject * Pympz_mpmath_mult(PyObject *self, PyObject *args) { PyObject *arg0 = 0, *arg1 = 0, *arg2 = 0, * arg3 = 0, *result; mpz_t man, exp; long prec = 0; const char *rnd = "d"; switch(PyTuple_GET_SIZE(args)) { case 6: rnd = Py2or3String_AsString(PyTuple_GET_ITEM(args, 5)); case 5: prec = clong_From_Integer(PyTuple_GET_ITEM(args, 4)); case 4: arg3 = (PyObject*)Pympz_From_Integer(PyTuple_GET_ITEM(args, 3)); case 3: arg2 = (PyObject*)Pympz_From_Integer(PyTuple_GET_ITEM(args, 2)); case 2: arg1 = (PyObject*)Pympz_From_Integer(PyTuple_GET_ITEM(args, 1)); case 1: arg0 = (PyObject*)Pympz_From_Integer(PyTuple_GET_ITEM(args, 0)); } if(!arg0 || !arg1 || !arg2 || !arg3 || (prec < 0) || PyErr_Occurred()) { PyErr_SetString(PyExc_TypeError, "arguments mpz, mpz, mpz, mpz, long(>=0), char needed"); Py_XDECREF(arg0); Py_XDECREF(arg1); Py_XDECREF(arg2); Py_XDECREF(arg3); return NULL; } else { mpz_inoc(man); mpz_inoc(exp); mpz_mul(man, Pympz_AS_MPZ(arg0), Pympz_AS_MPZ(arg2)); mpz_add(exp, Pympz_AS_MPZ(arg1), Pympz_AS_MPZ(arg3)); result = do_mpmath_trim(man, exp, prec, rnd[0]); mpz_cloc(man); mpz_cloc(exp); Py_DECREF(arg0); Py_DECREF(arg1); Py_DECREF(arg2); Py_DECREF(arg3); return result; } } static char doc_mpmath_divg[]="\ _mpmath_div(xman, xexp, yman, yexp, prec, rounding):\n\ Return (man, exp) by rounding xman*2**xexp / yman*2**yexp to prec\n\ bits using the specified rounding mode.\n\ "; static PyObject * Pympz_mpmath_div(PyObject *self, PyObject *args) { PyObject *arg0 = 0, *arg1 = 0, *arg2 = 0, * arg3 = 0, *result; mpz_t quot, rem, exp, delta_z; long prec = 0, delta, zbits; const char *rnd = "d"; switch(PyTuple_GET_SIZE(args)) { case 6: rnd = Py2or3String_AsString(PyTuple_GET_ITEM(args, 5)); case 5: prec = clong_From_Integer(PyTuple_GET_ITEM(args, 4)); case 4: arg3 = (PyObject*)Pympz_From_Integer(PyTuple_GET_ITEM(args, 3)); case 3: arg2 = (PyObject*)Pympz_From_Integer(PyTuple_GET_ITEM(args, 2)); case 2: arg1 = (PyObject*)Pympz_From_Integer(PyTuple_GET_ITEM(args, 1)); case 1: arg0 = (PyObject*)Pympz_From_Integer(PyTuple_GET_ITEM(args, 0)); } if(!arg0 || !arg1 || !arg2 || !arg3 || (prec < 1) || PyErr_Occurred()) { PyErr_SetString(PyExc_TypeError, "arguments mpz, mpz, mpz, mpz, long(>=1), char needed"); Py_XDECREF(arg0); Py_XDECREF(arg1); Py_XDECREF(arg2); Py_XDECREF(arg3); return NULL; } /* Check if either argument is zero. */ if(mpz_sgn(Pympz_AS_MPZ(arg2)) == 0) { PyErr_SetString(PyExc_ZeroDivisionError, "mpmath division by 0"); result = NULL; goto return_result; } if(mpz_sgn(Pympz_AS_MPZ(arg0)) == 0) { result = do_mpmath_trim(Pympz_AS_MPZ(arg0), Pympz_AS_MPZ(arg1), prec, rnd[0]); goto return_result; } /* Remove trailing 0 bits. */ if((zbits = mpz_scan1(Pympz_AS_MPZ(arg0), 0))) { mpz_tdiv_q_2exp(Pympz_AS_MPZ(arg0), Pympz_AS_MPZ(arg0), zbits); mpz_add_ui(Pympz_AS_MPZ(arg1), Pympz_AS_MPZ(arg1), zbits); } if((zbits = mpz_scan1(Pympz_AS_MPZ(arg2), 0))) { mpz_tdiv_q_2exp(Pympz_AS_MPZ(arg2), Pympz_AS_MPZ(arg2), zbits); mpz_add_ui(Pympz_AS_MPZ(arg3), Pympz_AS_MPZ(arg3), zbits); } mpz_inoc(delta_z); mpz_set_ui(delta_z, prec); mpz_sub_ui(delta_z, delta_z, mpz_sizeinbase(Pympz_AS_MPZ(arg0), 2)); mpz_add_ui(delta_z, delta_z, mpz_sizeinbase(Pympz_AS_MPZ(arg2), 2)); mpz_add_ui(delta_z, delta_z, 5); if(mpz_cmp_ui(delta_z, 5) < 0) { mpz_set_ui(delta_z, 5); } mpz_inoc(quot); mpz_inoc(rem); mpz_inoc(exp); if(!mpz_fits_slong_p(delta_z)) { PyErr_SetString(PyExc_ValueError, "delta too large"); result = NULL; goto return_result; } else { delta = mpz_get_si(delta_z); } mpz_set(quot, Pympz_AS_MPZ(arg0)); mpz_mul_2exp(quot, quot, delta); mpz_tdiv_qr(quot, rem, quot, Pympz_AS_MPZ(arg2)); if(mpz_sgn(rem)) { mpz_mul_2exp(quot, quot, 1); if(mpz_sgn(quot) < 0) { mpz_sub_ui(quot, quot, 1); } else { mpz_add_ui(quot, quot, 1); } mpz_add_ui(delta_z, delta_z, 1); } mpz_set(exp, Pympz_AS_MPZ(arg1)); mpz_sub(exp, exp, Pympz_AS_MPZ(arg3)); mpz_sub(exp, exp, delta_z); result = do_mpmath_trim(quot, exp, prec, rnd[0]); mpz_cloc(quot); mpz_cloc(rem); mpz_cloc(exp); mpz_cloc(delta_z); return_result: Py_DECREF(arg0); Py_DECREF(arg1); Py_DECREF(arg2); Py_DECREF(arg3); return result; } static char doc_mpmath_sqrtg[]="\ _mpmath_sqrt(man, exp, prec, rounding):\n\ Return (man, exp) by rounding square_root(xman*2**xexp)) to prec\n\ bits using the specified rounding mode.\n\ "; static PyObject * Pympz_mpmath_sqrt(PyObject *self, PyObject *args) { PyObject *arg0 = 0, *arg1 = 0, *result; mpz_t man, exp, rem; long prec = 0, zbits; unsigned long shift, temp; const char *rnd = "d"; switch(PyTuple_GET_SIZE(args)) { case 4: rnd = Py2or3String_AsString(PyTuple_GET_ITEM(args, 3)); case 3: prec = clong_From_Integer(PyTuple_GET_ITEM(args, 2)); case 2: arg1 = (PyObject*)Pympz_From_Integer(PyTuple_GET_ITEM(args, 1)); case 1: arg0 = (PyObject*)Pympz_From_Integer(PyTuple_GET_ITEM(args, 0)); } if(!arg0 || !arg1 || (prec < 1) || PyErr_Occurred()) { PyErr_SetString(PyExc_TypeError, "arguments mpz, mpz, long(>=1), char needed"); Py_XDECREF(arg0); Py_XDECREF(arg1); return NULL; } mpz_inoc(man); mpz_inoc(exp); mpz_inoc(rem); mpz_set(man, Pympz_AS_MPZ(arg0)); mpz_set(exp, Pympz_AS_MPZ(arg1)); if(mpz_sgn(man) < 0) { PyErr_SetString(PyExc_ValueError, "square root of a negative number"); result = NULL; goto return_result; } if(mpz_sgn(man) == 0) { result = do_mpmath_trim(man, exp, prec, rnd[0]); goto return_result; } if((zbits = mpz_scan1(man, 0))) { mpz_tdiv_q_2exp(man, man, zbits); mpz_add_ui(exp, exp, zbits); } if(mpz_odd_p(exp)) { mpz_sub_ui(exp, exp, 1); mpz_mul_2exp(man, man, 1); } else if(!mpz_cmp_ui(man, 1)) { /* Handle even powers of 2. */ mpz_tdiv_q_2exp(exp, exp, 1); result = do_mpmath_trim(man, exp, prec, rnd[0]); goto return_result; } shift = (2 * prec) + 4; temp = mpz_sizeinbase(man, 2); if(temp >= shift) { shift = 4; } else { shift -= temp; } if(shift < 4) shift = 4; shift += shift & 1; mpz_mul_2exp(man, man, shift); if((rnd[0] == 'f') || (rnd[0] == 'd')) { mpz_sqrt(man, man); } else { mpz_sqrtrem(man, rem, man); if(mpz_sgn(rem)) { mpz_mul_2exp(man, man, 1); mpz_add_ui(man, man, 1); shift += 2; } } mpz_sub_ui(exp, exp, shift); mpz_tdiv_q_2exp(exp, exp, 1); result = do_mpmath_trim(man, exp, prec, rnd[0]); return_result: mpz_cloc(man); mpz_cloc(exp); mpz_cloc(rem); Py_DECREF(arg0); Py_DECREF(arg1); return result; } gmpy-1.17/src/gmpy_misc.c0000666000000000000000000001553612174774730014070 0ustar rootroot/* gmpy_misc.c * * Miscellaneous module-level functions. * * This file should be considered part of gmpy.c. */ /* Return license information. */ static char doc_license[]="\ license(): returns string giving license information\n\ "; static PyObject * Pygmpy_get_license(PyObject *self, PyObject *args) { PARSE_NO_ARGS("license expects 0 arguments"); return Py_BuildValue("s", gmpy_license); } /* return GMPY, resp. GMP, versions, or CVS Id, as strings */ static char doc_version[]="\ version(): returns string giving current GMPY version\n\ "; static PyObject * Pygmpy_get_version(PyObject *self, PyObject *args) { PARSE_NO_ARGS("version expects 0 arguments"); return Py_BuildValue("s", gmpy_version); } static char doc_cvsid[]="\ _cvsid(): returns string giving current GMPY cvs Id\n\ "; static PyObject * Pygmpy_get_cvsid(PyObject *self, PyObject *args) { PARSE_NO_ARGS("get_cvsid expects 0 arguments"); return Py_BuildValue("s", _gmpy_cvs); } static char doc_gmp_version[]="\ gmp_version(): returns string giving current GMP version. Empty string\n\ returned if MPIR was used.\n\ "; static PyObject * Pygmpy_get_gmp_version(PyObject *self, PyObject *args) { PARSE_NO_ARGS("gmp_version expects 0 arguments"); #ifndef __MPIR_VERSION return Py_BuildValue("s", gmp_version); #else return Py_BuildValue("s", ""); #endif } static char doc_mpir_version[]="\ mpir_version(): returns string giving current MPIR version. Empty string\n\ returned if GMP was used.\n\ "; static PyObject * Pygmpy_get_mpir_version(PyObject *self, PyObject *args) { PARSE_NO_ARGS("mpir_version expects 0 arguments"); #ifdef __MPIR_VERSION return Py_BuildValue("s", mpir_version); #else return Py_BuildValue("s", ""); #endif } static char doc_gmp_limbsize[]="\ gmp_limbsize(): returns the number of bits per limb\n\ "; static PyObject * Pygmpy_get_gmp_limbsize(PyObject *self, PyObject *args) { PARSE_NO_ARGS("gmp_limbsize expects 0 arguments"); return Py_BuildValue("i", GMP_NUMB_BITS); } /* * access cache options */ static char doc_get_cache[]="\ get_cache(): returns the current cache-size (number of objects)\n\ and maximum size per object (number of limbs) for all objects.\n\ "; static PyObject * Pygmpy_get_cache(PyObject *self, PyObject *args) { PARSE_NO_ARGS("get_cache expects 0 arguments"); return Py_BuildValue("ii", options.cache_size, options.cache_obsize); } static char doc_set_cache[]="\ set_cache(n,size): sets the current cache-size (number of objects) to\n\ 'n' and the maximum size per object (number of limbs) to 'size'.\n\ Note: cache size 'n' must be between 0 and 1000, included. Object size\n\ 'size' must be between 0 and 16384, included.\n\ "; static PyObject * Pygmpy_set_cache(PyObject *self, PyObject *args) { int newcache, newsize; if(!PyArg_ParseTuple(args, "ii", &newcache, &newsize)) return NULL; if(newcache<0 || newcache>MAX_CACHE) { PyErr_SetString(PyExc_ValueError, "cache must between 0 and 1000"); return NULL; } if(newsize<0 || newsize>MAX_CACHE_LIMBS) { PyErr_SetString(PyExc_ValueError, "object size must between 0 and 16384"); return NULL; } options.cache_size=newcache; options.cache_obsize=newsize; set_zcache(); set_qcache(); set_fcache(); set_pympzcache(); return Py_BuildValue(""); } /* set a module-global flag, return previously-set value */ static char doc_set_debug[]="\ set_debug(n): resets (if n==0) or sets (if n!=0) the module\n\ level 'debug' setting, giving detailed info to stderr; also\n\ returns the previous value of this module-level setting.\n\ Note: only useful to debug gmpy's own internals!\n\ "; static PyObject * Pygmpy_set_debug(PyObject *self, PyObject *args) { int old = options.debug; ONE_ARG("set_debug", "i", &options.debug); return Py_BuildValue("i", old); } static char doc_set_tagoff[]="\ set_tagoff(n): resets (if n==0) or sets (if n!=0) the module\n\ level 'tagoff' setting, removing the 'gmpy.' prefix of the tag\n\ strings used by repr and (optionally) digits/fdigits/qdigits;\n\ also returns the previous value of this module-level setting.\n\ "; static PyObject * Pygmpy_set_tagoff(PyObject *self, PyObject *args) { int old = options.tagoff; ONE_ARG("set_tagoff", "i", &options.tagoff); if(options.tagoff) options.tagoff=5; return Py_BuildValue("i", old!=0); } static char doc_set_minprec[]="\ set_minprec(n): sets number of bits of precision to be at\n\ least n for all mpf objects generated from now on; also\n\ returns the previous value of this module-level setting.\n\ "; static PyObject * Pygmpy_set_minprec(PyObject *self, PyObject *args) { long old = options.minprec; long i; ONE_ARG("set_minprec", "l", &i); if(i<0) { PyErr_SetString(PyExc_ValueError, "minimum precision must be >= 0"); return 0; } options.minprec = i; return Py_BuildValue("l", old); } static char doc_set_fcoform[]="\ set_fcoform(s=None): resets (if s is None) or sets the module level\n\ 'fcoform' setting, the format in which to build an intermediate string\n\ to be used in float->mpf conversion (direct, if no fcoform); also\n\ returns the previous value of this module-level setting. Note that\n\ s must be a string usable for s%f formatting; or, s may be a Python\n\ int, 0e'.\n\ "; static PyObject * Pygmpy_set_fcoform(PyObject *self, PyObject *args) { PyObject *old = options.fcoform; PyObject *new = 0; long inew; ONE_ARG("set_fcoform", "|O", &new); if(new == Py_None) { /* none == missing-argument (reset string use) */ new = 0; } else if(new) { char buf[20]; if(isInteger(new)) { /* int arg (1 to 30) used as # of digits for intermediate string */ inew = clong_From_Integer(new); if(inew==-1 && PyErr_Occurred()) { PyErr_SetString(PyExc_ValueError, "number of digits n must be 030) { PyErr_SetString(PyExc_ValueError, "number of digits n must be 0 /* Generic addition * * Support addition for gmpy types with automatic conversion of Python types. * * The following conversion logic is used: * 1) 'mpz' combined with an integer type returns an 'mpz' * 2) 'mpz' combined with an integer or rational type returns an 'mpq' * 3) 'mpz' combined with a floating-point type returns an 'mpf' * 4) 'mpq' combined with an integer or rational type returns an 'mpq' * 5) 'mpq' combines with a floating-point type returns an 'mpf' * * The most common inputs are processed as efficiently as possible. */ static PyObject * Pympany_add(PyObject *a, PyObject *b) { PyObject *r = 0; mpz_t tempz; PympzObject *rz; PympqObject *rq = 0, *paq = 0, *pbq = 0; PympfObject *rf = 0, *paf = 0, *pbf = 0; long temp; #if PY_MAJOR_VERSION == 3 int overflow; #endif size_t bits; /* Try to make mpz + small_int faster */ if(Pympz_Check(a)) { if(!(rz = Pympz_new())) return NULL; #if PY_MAJOR_VERSION == 2 if(PyInt_Check(b)) { if(options.debug) fprintf(stderr, "Adding (mpz,small_int)\n"); if((temp = PyInt_AS_LONG(b)) >= 0) { mpz_add_ui(rz->z, Pympz_AS_MPZ(a), temp); } else { mpz_sub_ui(rz->z, Pympz_AS_MPZ(a), -temp); } return (PyObject *)rz; } #endif if(PyLong_Check(b)) { if(options.debug) fprintf(stderr, "Adding (mpz,long)\n"); #if PY_MAJOR_VERSION == 3 temp = PyLong_AsLongAndOverflow(b, &overflow); if(overflow) { #else temp = PyLong_AsLong(b); if(PyErr_Occurred()) { PyErr_Clear(); #endif mpz_inoc(tempz); mpz_set_PyLong(tempz, b); mpz_add(rz->z, Pympz_AS_MPZ(a), tempz); mpz_cloc(tempz); } else if(temp >= 0) { mpz_add_ui(rz->z, Pympz_AS_MPZ(a), temp); } else { mpz_sub_ui(rz->z, Pympz_AS_MPZ(a), -temp); } return (PyObject *) rz; } if(Pympz_Check(b)) { if(options.debug) fprintf(stderr, "Adding (mpz,mpz)\n"); mpz_add(rz->z, Pympz_AS_MPZ(a), Pympz_AS_MPZ(b)); return (PyObject *)rz; } Py_DECREF((PyObject*)rz); } if(Pympz_Check(b)) { if(!(rz = Pympz_new())) return NULL; #if PY_MAJOR_VERSION == 2 if(PyInt_Check(a)) { if(options.debug) fprintf(stderr, "Adding (small_int,mpz)\n"); if((temp = PyInt_AS_LONG(a)) >= 0) { mpz_add_ui(rz->z, Pympz_AS_MPZ(b), temp); } else { mpz_sub_ui(rz->z, Pympz_AS_MPZ(b), -temp); } return (PyObject *)rz; } #endif if(PyLong_Check(a)) { if(options.debug) fprintf(stderr, "Adding (long,mpz)\n"); #if PY_MAJOR_VERSION == 3 temp = PyLong_AsLongAndOverflow(a, &overflow); if(overflow) { #else temp = PyLong_AsLong(a); if(PyErr_Occurred()) { PyErr_Clear(); #endif mpz_inoc(tempz); mpz_set_PyLong(tempz, a); mpz_add(rz->z, Pympz_AS_MPZ(b), tempz); mpz_cloc(tempz); } else if(temp >=0) { mpz_add_ui(rz->z, Pympz_AS_MPZ(b), temp); } else { mpz_sub_ui(rz->z, Pympz_AS_MPZ(b), -temp); } return (PyObject *) rz; } Py_DECREF((PyObject*)rz); } if(isRational(a) && isRational(b)) { if (options.debug) fprintf(stderr, "Adding (rational,rational)\n"); paq = anyrational2Pympq(a); pbq = anyrational2Pympq(b); if(!paq || !pbq) { PyErr_SetString(PyExc_SystemError, "Can not convert rational to mpq"); Py_XDECREF((PyObject*)paq); Py_XDECREF((PyObject*)pbq); return NULL; } if (!(rq = Pympq_new())) { Py_DECREF((PyObject*)paq); Py_DECREF((PyObject*)pbq); return NULL; } mpq_add(rq->q, paq->q, pbq->q); Py_DECREF((PyObject*)paq); Py_DECREF((PyObject*)pbq); return (PyObject *) rq; } if(isNumber(a) && isNumber(b)) { if (options.debug) fprintf(stderr, "Adding (number,number)\n"); if(Pympf_Check(a) && Pympf_Check(b)) { paf = anynum2Pympf(a, 0); pbf = anynum2Pympf(b, 0); } else if(Pympf_Check(a)) { paf = anynum2Pympf(a, 0); pbf = anynum2Pympf(b, paf->rebits); } else if(Pympf_Check(b)) { pbf = anynum2Pympf(b, 0); paf = anynum2Pympf(a, pbf->rebits); } else { pbf = anynum2Pympf(b, 0); paf = anynum2Pympf(a, 0); } if(!paf || !pbf) { if(PyErr_Occurred()) { PyErr_Clear(); } else { PyErr_SetString(PyExc_SystemError, "Internal error status is confused."); return NULL; } /* Need to handle special float values. */ if(pbf && !paf && PyFloat_Check(a)) { double d = PyFloat_AS_DOUBLE(a); if(isinf(d) || isnan(d)) { r = PyFloat_FromDouble(d); Py_DECREF((PyObject*)pbf); return r; } } else if(paf && !pbf && PyFloat_Check(b)) { double d = PyFloat_AS_DOUBLE(b); if(isinf(d) || isnan(d)) { r = PyFloat_FromDouble(d); Py_DECREF((PyObject*)paf); return r; } } else { PyErr_SetString(PyExc_SystemError, "Can not convert number to mpf"); Py_XDECREF((PyObject*)paf); Py_XDECREF((PyObject*)pbf); return NULL; } } bits = paf->rebits; if(pbf->rebitsrebits; if (!(rf = Pympf_new(bits))) { Py_DECREF((PyObject*)paf); Py_DECREF((PyObject*)pbf); return NULL; } mpf_add(rf->f, paf->f, pbf->f); Py_DECREF((PyObject*)paf); Py_DECREF((PyObject*)pbf); mpf_normalize(rf->f); return (PyObject *) rf; } r = Py_NotImplemented; Py_INCREF(r); return r; } /* Generic Subtraction * * Follows the same conversion rules as Pympany_add. */ static PyObject * Pympany_sub(PyObject *a, PyObject *b) { PyObject *r = 0; mpz_t tempz; PympzObject *rz; PympqObject *rq = 0, *paq = 0, *pbq = 0; PympfObject *rf = 0, *paf = 0, *pbf = 0; long temp; #if PY_MAJOR_VERSION == 3 int overflow; #endif size_t bits; if(Pympz_Check(a)) { if(!(rz = Pympz_new())) return NULL; #if PY_MAJOR_VERSION == 2 if(PyInt_Check(b)) { if (options.debug) fprintf(stderr, "Subtracting (mpz,small_int)\n"); if((temp = PyInt_AS_LONG(b)) >= 0) { mpz_sub_ui(rz->z, Pympz_AS_MPZ(a), temp); } else { mpz_add_ui(rz->z, Pympz_AS_MPZ(a), -temp); } return (PyObject *)rz; } #endif if(PyLong_Check(b)) { if (options.debug) fprintf(stderr, "Subtracting (mpz,long)\n"); #if PY_MAJOR_VERSION == 3 temp = PyLong_AsLongAndOverflow(b, &overflow); if(overflow) { #else temp = PyLong_AsLong(b); if(PyErr_Occurred()) { PyErr_Clear(); #endif mpz_inoc(tempz); mpz_set_PyLong(tempz, b); mpz_sub(rz->z, Pympz_AS_MPZ(a), tempz); mpz_cloc(tempz); } else if(temp >= 0) { mpz_sub_ui(rz->z, Pympz_AS_MPZ(a), temp); } else { mpz_add_ui(rz->z, Pympz_AS_MPZ(a), -temp); } return (PyObject *)rz; } if(Pympz_Check(b)) { if(options.debug) fprintf(stderr, "Subtracting (mpz,mpz)\n"); mpz_sub(rz->z, Pympz_AS_MPZ(a), Pympz_AS_MPZ(b)); return (PyObject *)rz; } Py_DECREF((PyObject*)rz); } if(Pympz_Check(b)) { if(!(rz = Pympz_new())) return NULL; #if PY_MAJOR_VERSION == 2 if(PyInt_Check(a)) { if (options.debug) fprintf(stderr, "Subtracting (small_int,mpz)\n"); if((temp = PyInt_AS_LONG(a)) >= 0) { mpz_ui_sub(rz->z, temp, Pympz_AS_MPZ(b)); } else { mpz_add_ui(rz->z, Pympz_AS_MPZ(b), -temp); mpz_neg(rz->z, rz->z); } return (PyObject *)rz; } #endif if(PyLong_Check(a)) { if (options.debug) fprintf(stderr, "Subtracting (long,mpz)\n"); #if PY_MAJOR_VERSION == 3 temp = PyLong_AsLongAndOverflow(a, &overflow); if(overflow) { #else temp = PyLong_AsLong(a); if(PyErr_Occurred()) { PyErr_Clear(); #endif mpz_inoc(tempz); mpz_set_PyLong(tempz, a); mpz_sub(rz->z, tempz, Pympz_AS_MPZ(b)); mpz_cloc(tempz); } else if(temp >= 0) { mpz_ui_sub(rz->z, temp, Pympz_AS_MPZ(b)); } else { mpz_add_ui(rz->z, Pympz_AS_MPZ(b), -temp); mpz_neg(rz->z, rz->z); } return (PyObject *)rz; } Py_DECREF((PyObject*)rz); } if(isRational(a) && isRational(b)) { if (options.debug) fprintf(stderr, "Subtracting (rational,rational)\n"); paq = anyrational2Pympq(a); pbq = anyrational2Pympq(b); if(!paq || !pbq) { PyErr_SetString(PyExc_SystemError, "Can not convert rational to mpq"); Py_XDECREF((PyObject*)paq); Py_XDECREF((PyObject*)pbq); return NULL; } if (!(rq = Pympq_new())) { Py_DECREF((PyObject*)paq); Py_DECREF((PyObject*)pbq); return NULL; } mpq_sub(rq->q, paq->q, pbq->q); Py_DECREF((PyObject*)paq); Py_DECREF((PyObject*)pbq); return (PyObject *) rq; } if(isNumber(a) && isNumber(b)) { if (options.debug) fprintf(stderr, "Subtracting (number,number)\n"); if(Pympf_Check(a) && Pympf_Check(b)) { paf = anynum2Pympf(a, 0); pbf = anynum2Pympf(b, 0); } else if(Pympf_Check(a)) { paf = anynum2Pympf(a, 0); pbf = anynum2Pympf(b, paf->rebits); } else if(Pympf_Check(b)) { pbf = anynum2Pympf(b, 0); paf = anynum2Pympf(a, pbf->rebits); } else { pbf = anynum2Pympf(b, 0); paf = anynum2Pympf(a, 0); } if(!paf || !pbf) { if(PyErr_Occurred()) { PyErr_Clear(); } else { PyErr_SetString(PyExc_SystemError, "Internal error status is confused."); return NULL; } /* Need to handle special float values. */ if(pbf && !paf && PyFloat_Check(a)) { double d = PyFloat_AS_DOUBLE(a); if(isinf(d) || isnan(d)) { r = PyFloat_FromDouble(d); Py_DECREF((PyObject*)pbf); return r; } } else if(paf && !pbf && PyFloat_Check(b)) { double d = PyFloat_AS_DOUBLE(b); if(isinf(d) || isnan(d)) { if(isinf(d)) r = PyFloat_FromDouble(-d); else r = PyFloat_FromDouble(d); Py_DECREF((PyObject*)paf); return r; } } else { PyErr_SetString(PyExc_SystemError, "Can not convert number to mpf"); Py_XDECREF((PyObject*)paf); Py_XDECREF((PyObject*)pbf); return NULL; } } bits = paf->rebits; if(pbf->rebitsrebits; if (!(rf = Pympf_new(bits))) { Py_DECREF((PyObject*)paf); Py_DECREF((PyObject*)pbf); return NULL; } mpf_sub(rf->f, paf->f, pbf->f); Py_DECREF((PyObject*)paf); Py_DECREF((PyObject*)pbf); mpf_normalize(rf->f); return (PyObject *) rf; } r = Py_NotImplemented; Py_INCREF(r); return r; } /* Generic Multiplication * * Follows the same conversion rules as Pympany_add. */ static PyObject * Pympany_mul(PyObject *a, PyObject *b) { PyObject *r = 0; mpz_t tempz; PympzObject *rz = 0; PympqObject *rq = 0, *paq = 0, *pbq = 0; PympfObject *rf = 0, *paf = 0, *pbf = 0; long temp; size_t bits; #if PY_MAJOR_VERSION == 3 int overflow; #endif if(Pympz_Check(a)) { if(!(rz = Pympz_new())) return NULL; #if PY_MAJOR_VERSION == 2 if(PyInt_Check(b)) { if (options.debug) fprintf(stderr, "Multiplying (mpz,small_int)\n"); mpz_mul_si(rz->z, Pympz_AS_MPZ(a), PyInt_AS_LONG(b)); return (PyObject *)rz; } #endif if(PyLong_Check(b)) { if (options.debug) fprintf(stderr, "Multiplying (mpz,long)\n"); #if PY_MAJOR_VERSION == 3 temp = PyLong_AsLongAndOverflow(b, &overflow); if(overflow) { #else temp = PyLong_AsLong(b); if(PyErr_Occurred()) { PyErr_Clear(); #endif mpz_inoc(tempz); mpz_set_PyLong(tempz, b); mpz_mul(rz->z, Pympz_AS_MPZ(a), tempz); mpz_cloc(tempz); } else { mpz_mul_si(rz->z, Pympz_AS_MPZ(a), temp); } return (PyObject *)rz; } if(Pympz_Check(b)) { if(options.debug) fprintf(stderr, "Multiplying (mpz,mpz)\n"); mpz_mul(rz->z, Pympz_AS_MPZ(a), Pympz_AS_MPZ(b)); return (PyObject *)rz; } Py_DECREF((PyObject*)rz); } if(Pympz_Check(b)) { if(!(rz = Pympz_new())) return NULL; #if PY_MAJOR_VERSION == 2 if(PyInt_Check(a)) { if (options.debug) fprintf(stderr, "Multiplying (small_int,mpz)\n"); mpz_mul_si(rz->z, Pympz_AS_MPZ(b), PyInt_AS_LONG(a)); return (PyObject *)rz; } #endif if(PyLong_Check(a)) { if (options.debug) fprintf(stderr, "Multiplying (long,mpz)\n"); #if PY_MAJOR_VERSION == 3 temp = PyLong_AsLongAndOverflow(a, &overflow); if(overflow) { #else temp = PyLong_AsLong(a); if(PyErr_Occurred()) { PyErr_Clear(); #endif mpz_inoc(tempz); mpz_set_PyLong(tempz, a); mpz_mul(rz->z, Pympz_AS_MPZ(b), tempz); mpz_cloc(tempz); } else { mpz_mul_si(rz->z, Pympz_AS_MPZ(b), temp); } return (PyObject *)rz; } Py_DECREF((PyObject*)rz); } if(isRational(a) && isRational(b)) { if (options.debug) fprintf(stderr, "Multiplying (rational,rational)\n"); paq = anyrational2Pympq(a); pbq = anyrational2Pympq(b); if(!paq || !pbq) { PyErr_SetString(PyExc_SystemError, "Can not convert rational to mpq"); Py_XDECREF((PyObject*)paq); Py_XDECREF((PyObject*)pbq); return NULL; } if (!(rq = Pympq_new())) { Py_DECREF((PyObject*)paq); Py_DECREF((PyObject*)pbq); return NULL; } mpq_mul(rq->q, paq->q, pbq->q); Py_DECREF((PyObject*)paq); Py_DECREF((PyObject*)pbq); return (PyObject *) rq; } if(isNumber(a) && isNumber(b)) { if (options.debug) fprintf(stderr, "Multiplying (number,number)\n"); if(Pympf_Check(a) && Pympf_Check(b)) { paf = anynum2Pympf(a, 0); pbf = anynum2Pympf(b, 0); } else if(Pympf_Check(a)) { paf = anynum2Pympf(a, 0); pbf = anynum2Pympf(b, paf->rebits); } else if(Pympf_Check(b)) { pbf = anynum2Pympf(b, 0); paf = anynum2Pympf(a, pbf->rebits); } else { pbf = anynum2Pympf(b, 0); paf = anynum2Pympf(a, 0); } if(!paf || !pbf) { if(PyErr_Occurred()) { PyErr_Clear(); } else { PyErr_SetString(PyExc_SystemError, "Internal error status is confused."); return NULL; } /* Need to handle special float values. */ if(pbf && !paf && PyFloat_Check(a)) { double d = PyFloat_AS_DOUBLE(a); if(isnan(d)) { r = PyFloat_FromDouble(d); Py_DECREF((PyObject*)pbf); return r; } else if(isinf(d)) { if(mpf_sgn(pbf->f) == 0) { /* Ugly hack to avoid creating -NaN. This issue appears with * gcc 4.4.3: Inf * 0 returns -NaN. */ d = d * 0.0; r = PyFloat_FromDouble(-d); } else if(mpf_sgn(pbf->f) < 0) { r = PyFloat_FromDouble(-d); } else { r = PyFloat_FromDouble(d); } Py_DECREF((PyObject*)pbf); return r; } } else if(paf && !pbf && PyFloat_Check(b)) { double d = PyFloat_AS_DOUBLE(b); if(isnan(d)) { r = PyFloat_FromDouble(d); Py_DECREF((PyObject*)paf); return r; } else if(isinf(d)) { if(mpf_sgn(paf->f) == 0) { /* Ugly hack to avoid creating -NaN. This issue appears with * gcc 4.4.3: Inf * 0 returns -NaN. */ d = d * 0.0; r = PyFloat_FromDouble(-d); } else if(mpf_sgn(paf->f) < 0) { r = PyFloat_FromDouble(-d); } else { r = PyFloat_FromDouble(d); } Py_DECREF((PyObject*)paf); return r; } } else { PyErr_SetString(PyExc_SystemError, "Can not convert number to mpf"); Py_XDECREF((PyObject*)paf); Py_XDECREF((PyObject*)pbf); return NULL; } } bits = paf->rebits; if(pbf->rebitsrebits; if (!(rf = Pympf_new(bits))) { Py_DECREF((PyObject*)paf); Py_DECREF((PyObject*)pbf); return NULL; } mpf_mul(rf->f, paf->f, pbf->f); Py_DECREF((PyObject*)paf); Py_DECREF((PyObject*)pbf); mpf_normalize(rf->f); return (PyObject *) rf; } r = Py_NotImplemented; Py_INCREF(r); return r; } /* Pympany_floordiv follows the // semantics from Python 3.x. The result is * an mpz when the arguments are mpz or mpq, but the result is an mpf when * the arguments are mpf. */ static PyObject * Pympany_floordiv(PyObject *a, PyObject *b) { PyObject *r = 0; mpz_t tempz; PympzObject *rz = 0; PympqObject *rq = 0, *paq = 0, *pbq = 0; PympfObject *rf = 0, *paf = 0, *pbf = 0; long temp; size_t bits; #if PY_MAJOR_VERSION == 3 int overflow; #endif if(Pympz_Check(a)) { if(!(rz = Pympz_new())) return NULL; #if PY_MAJOR_VERSION == 2 if(PyInt_Check(b)) { if (options.debug) fprintf(stderr, "Floor divide (mpz,small_int)\n"); if((temp=PyInt_AS_LONG(b)) > 0) { mpz_fdiv_q_ui(rz->z, Pympz_AS_MPZ(a), temp); } else if(temp == 0) { PyErr_SetString(PyExc_ZeroDivisionError, "mpz division by zero"); Py_DECREF((PyObject *)rz); return NULL; } else { mpz_cdiv_q_ui(rz->z, Pympz_AS_MPZ(a), -temp); mpz_neg(rz->z, rz->z); } return (PyObject *)rz; } #endif if(PyLong_Check(b)) { if (options.debug) fprintf(stderr, "Floor divide (mpz,long)\n"); #if PY_MAJOR_VERSION == 3 temp = PyLong_AsLongAndOverflow(b, &overflow); if(overflow) { #else temp = PyLong_AsLong(b); if(PyErr_Occurred()) { PyErr_Clear(); #endif mpz_inoc(tempz); mpz_set_PyLong(tempz, b); mpz_fdiv_q(rz->z, Pympz_AS_MPZ(a), tempz); mpz_cloc(tempz); } else if(temp == 0) { PyErr_SetString(PyExc_ZeroDivisionError, "mpz division by zero"); Py_DECREF((PyObject *)rz); return NULL; } else if(temp > 0) { mpz_fdiv_q_ui(rz->z, Pympz_AS_MPZ(a), temp); } else { mpz_cdiv_q_ui(rz->z, Pympz_AS_MPZ(a), -temp); mpz_neg(rz->z, rz->z); } return (PyObject *)rz; } if(Pympz_Check(b)) { if(options.debug) fprintf(stderr, "Floor divide (integer,integer)\n"); if(mpz_sgn(Pympz_AS_MPZ(b)) == 0) { PyErr_SetString(PyExc_ZeroDivisionError, "mpz division by zero"); Py_DECREF((PyObject*)rz); return NULL; } mpz_fdiv_q(rz->z, Pympz_AS_MPZ(a), Pympz_AS_MPZ(b)); return (PyObject *)rz; } Py_DECREF((PyObject*)rz); } if(Pympz_Check(b)) { if(mpz_sgn(Pympz_AS_MPZ(b)) == 0) { PyErr_SetString(PyExc_ZeroDivisionError, "mpz division by zero"); return NULL; } if(!(rz = Pympz_new())) return NULL; #if PY_MAJOR_VERSION == 2 if(PyInt_Check(a)) { if (options.debug) fprintf(stderr, "Floor divide (small_int,mpz)\n"); mpz_inoc(tempz); mpz_set_si(tempz, PyInt_AS_LONG(a)); mpz_fdiv_q(rz->z, tempz, Pympz_AS_MPZ(b)); mpz_cloc(tempz); return (PyObject *)rz; } #endif if(PyLong_Check(a)) { if (options.debug) fprintf(stderr, "Floor divide (long,mpz)\n"); mpz_inoc(tempz); mpz_set_PyLong(tempz, a); mpz_fdiv_q(rz->z, tempz, Pympz_AS_MPZ(b)); mpz_cloc(tempz); return (PyObject *)rz; } Py_DECREF((PyObject*)rz); } if(isRational(a) && isRational(b)) { if(options.debug) fprintf(stderr, "Floor divide (rational,rational)\n"); paq = anyrational2Pympq(a); pbq = anyrational2Pympq(b); if(!paq || !pbq) { PyErr_SetString(PyExc_SystemError, "Can not convert rational to mpq"); Py_XDECREF((PyObject*)paq); Py_XDECREF((PyObject*)pbq); return NULL; } if(mpq_sgn(pbq->q)==0) { PyErr_SetString(PyExc_ZeroDivisionError, "mpq division by zero"); Py_DECREF((PyObject*)paq); Py_DECREF((PyObject*)pbq); return NULL; } if (!(rq = Pympq_new()) || !(rz = Pympz_new())) { Py_XDECREF((PyObject*)rq); Py_XDECREF((PyObject*)rz); Py_DECREF((PyObject*)paq); Py_DECREF((PyObject*)pbq); return NULL; } mpq_div(rq->q, paq->q, pbq->q); mpz_fdiv_q(rz->z, mpq_numref(rq->q), mpq_denref(rq->q)); Py_DECREF((PyObject*)paq); Py_DECREF((PyObject*)pbq); Py_DECREF((PyObject*)rq); return (PyObject *) rz; } if(isNumber(a) && isNumber(b)) { if(options.debug) fprintf(stderr, "Floor divide (number,number)\n"); if(Pympf_Check(a) && Pympf_Check(b)) { paf = anynum2Pympf(a, 0); pbf = anynum2Pympf(b, 0); } else if(Pympf_Check(a)) { paf = anynum2Pympf(a, 0); pbf = anynum2Pympf(b, paf->rebits); } else if(Pympf_Check(b)) { pbf = anynum2Pympf(b, 0); paf = anynum2Pympf(a, pbf->rebits); } else { pbf = anynum2Pympf(b, 0); paf = anynum2Pympf(a, 0); } if(!paf || !pbf) { if(PyErr_Occurred()) { PyErr_Clear(); } else { PyErr_SetString(PyExc_SystemError, "Internal error status is confused."); return NULL; } /* Need to handle special float values. */ if(pbf && !paf && PyFloat_Check(a)) { double d = PyFloat_AS_DOUBLE(a); if(isnan(d)) { if(mpf_sgn(pbf->f) == 0) { PyErr_SetString(PyExc_ZeroDivisionError, "mpf division by zero"); r = NULL; } else { r = PyFloat_FromDouble(d); } Py_DECREF((PyObject*)pbf); return r; } else if(isinf(d)) { if(mpf_sgn(pbf->f) == 0) { PyErr_SetString(PyExc_ZeroDivisionError, "mpf division by zero"); r = NULL; } else if(mpf_sgn(pbf->f) < 0) { r = PyFloat_FromDouble(-d); } else { r = PyFloat_FromDouble(d); } Py_DECREF((PyObject*)pbf); return r; } } else if(paf && !pbf && PyFloat_Check(b)) { double d = PyFloat_AS_DOUBLE(b); if(isnan(d)) { r = PyFloat_FromDouble(d); Py_DECREF((PyObject*)paf); return r; } else if(isinf(d)) { mpf_set_d(paf->f, 0.0); return (PyObject*)paf; } } else { PyErr_SetString(PyExc_SystemError, "Can not convert number to mpf"); Py_XDECREF((PyObject*)paf); Py_XDECREF((PyObject*)pbf); return NULL; } } if(mpf_sgn(pbf->f)==0) { PyErr_SetString(PyExc_ZeroDivisionError, "mpf division by zero"); Py_DECREF((PyObject*)paf); Py_DECREF((PyObject*)pbf); return NULL; } bits = paf->rebits; if(pbf->rebitsrebits; if (!(rf = Pympf_new(bits))) { Py_XDECREF((PyObject*)rf); Py_DECREF((PyObject*)paf); Py_DECREF((PyObject*)pbf); return NULL; } mpf_div(rf->f, paf->f, pbf->f); mpf_floor(rf->f, rf->f); Py_DECREF((PyObject*)paf); Py_DECREF((PyObject*)pbf); mpf_normalize(rf->f); return (PyObject *) rf; } r = Py_NotImplemented; Py_INCREF(r); return r; } /* Pympany_truediv follows the / semantics from Python 3.x. The result types * are: * mpz / mpz -> mpf * mpq / mpq -> mpq * mpf / mpf -> mpf * * The behavior of mpq now mimics the behavior of fractions.Fraction. */ static PyObject * Pympany_truediv(PyObject *a, PyObject *b) { PyObject *r = 0; PympqObject *rq = 0, *paq = 0, *pbq = 0; PympfObject *rf = 0, *paf = 0, *pbf = 0; size_t bits; if(Pympz_Check(b) && (mpz_sgn(Pympz_AS_MPZ(b)) == 0)) { PyErr_SetString(PyExc_ZeroDivisionError, "mpz division by zero"); return NULL; } if(Pympq_Check(b) && (mpq_sgn(Pympq_AS_MPQ(b)) == 0)) { PyErr_SetString(PyExc_ZeroDivisionError, "mpq division by zero"); return NULL; } if(isInteger(a) && isInteger(b)) { if(options.debug) fprintf(stderr, "True divide (integer,integer)\n"); paf = anynum2Pympf(a, 0); pbf = anynum2Pympf(b, 0); if(!paf || !pbf) { PyErr_SetString(PyExc_SystemError, "Can not convert number to mpf"); Py_XDECREF((PyObject*)paf); Py_XDECREF((PyObject*)pbf); return NULL; } if(mpf_sgn(pbf->f)==0) { PyErr_SetString(PyExc_ZeroDivisionError, "mpz division by zero"); Py_DECREF((PyObject*)paf); Py_DECREF((PyObject*)pbf); return NULL; } if (!(rf = Pympf_new(0))) { Py_DECREF((PyObject*)paf); Py_DECREF((PyObject*)pbf); return NULL; } mpf_div(rf->f, paf->f, pbf->f); Py_DECREF((PyObject*)paf); Py_DECREF((PyObject*)pbf); return (PyObject *) rf; } if(isRational(a) && isRational(b)) { if(options.debug) fprintf(stderr, "True divide (rational,rational)\n"); paq = anyrational2Pympq(a); pbq = anyrational2Pympq(b); if(!paq || !pbq) { PyErr_SetString(PyExc_SystemError, "Can not convert rational to mpq"); Py_XDECREF((PyObject*)paq); Py_XDECREF((PyObject*)pbq); return NULL; } if(mpq_sgn(pbq->q)==0) { PyErr_SetString(PyExc_ZeroDivisionError, "mpq division by zero"); Py_DECREF((PyObject*)paq); Py_DECREF((PyObject*)pbq); return NULL; } if (!(rq = Pympq_new())) { Py_DECREF((PyObject*)paq); Py_DECREF((PyObject*)pbq); return NULL; } mpq_div(rq->q, paq->q, pbq->q); Py_DECREF((PyObject*)paq); Py_DECREF((PyObject*)pbq); return (PyObject *) rq; } if(isNumber(a) && isNumber(b)) { if(options.debug) fprintf(stderr, "True divide (number,number)\n"); if(Pympf_Check(a) && Pympf_Check(b)) { paf = anynum2Pympf(a, 0); pbf = anynum2Pympf(b, 0); } else if(Pympf_Check(a)) { paf = anynum2Pympf(a, 0); pbf = anynum2Pympf(b, paf->rebits); } else if(Pympf_Check(b)) { pbf = anynum2Pympf(b, 0); paf = anynum2Pympf(a, pbf->rebits); } else { pbf = anynum2Pympf(b, 0); paf = anynum2Pympf(a, 0); } if(!paf || !pbf) { if(PyErr_Occurred()) { PyErr_Clear(); } else { PyErr_SetString(PyExc_SystemError, "Internal error status is confused."); return NULL; } /* Need to handle special float values. */ if(pbf && !paf && PyFloat_Check(a)) { double d = PyFloat_AS_DOUBLE(a); if(isnan(d)) { if(mpf_sgn(pbf->f) == 0) { PyErr_SetString(PyExc_ZeroDivisionError, "mpf division by zero"); r = NULL; } else { r = PyFloat_FromDouble(d); } Py_DECREF((PyObject*)pbf); return r; } else if(isinf(d)) { if(mpf_sgn(pbf->f) == 0) { PyErr_SetString(PyExc_ZeroDivisionError, "mpf division by zero"); r = NULL; } else if(mpf_sgn(pbf->f) < 0) { r = PyFloat_FromDouble(-d); } else { r = PyFloat_FromDouble(d); } Py_DECREF((PyObject*)pbf); return r; } } else if(paf && !pbf && PyFloat_Check(b)) { double d = PyFloat_AS_DOUBLE(b); if(isnan(d)) { r = PyFloat_FromDouble(d); Py_DECREF((PyObject*)paf); return r; } else if(isinf(d)) { mpf_set_d(paf->f, 0.0); return (PyObject*)paf; } } else { PyErr_SetString(PyExc_SystemError, "Can not convert number to mpf"); Py_XDECREF((PyObject*)paf); Py_XDECREF((PyObject*)pbf); return NULL; } } if(mpf_sgn(pbf->f)==0) { PyErr_SetString(PyExc_ZeroDivisionError, "mpf division by zero"); Py_DECREF((PyObject*)paf); Py_DECREF((PyObject*)pbf); return NULL; } bits = paf->rebits; if(pbf->rebitsrebits; if (!(rf = Pympf_new(bits))) { Py_DECREF((PyObject*)paf); Py_DECREF((PyObject*)pbf); return NULL; } mpf_div(rf->f, paf->f, pbf->f); Py_DECREF((PyObject*)paf); Py_DECREF((PyObject*)pbf); mpf_normalize(rf->f); return (PyObject *) rf; } r = Py_NotImplemented; Py_INCREF(r); return r; } #if PY_MAJOR_VERSION == 2 /* Pympany_div2 follows the conversions rules for Python 2.x. The behavior is * a mix of floordiv and truediv. The type conversion behavior is: * mpz / mpz -> mpz * mpq / mpq -> mpq * mpf / mpf -> mpf * * A division operator with these properties is not available with Python 3.x. */ static PyObject * Pympany_div2(PyObject *a, PyObject *b) { PyObject *r = 0; mpz_t tempz; PympzObject *rz = 0; PympqObject *rq = 0, *paq = 0, *pbq = 0; PympfObject *rf = 0, *paf = 0, *pbf = 0; long temp; size_t bits; #if PY_MAJOR_VERSION == 3 int overflow; #endif /* Use floordiv for integer types. */ if(Pympz_Check(a)) { if(!(rz = Pympz_new())) return NULL; #if PY_MAJOR_VERSION == 2 if(PyInt_Check(b)) { if (options.debug) fprintf(stderr, "True divide (mpz,small_int)\n"); if((temp=PyInt_AS_LONG(b)) > 0) { mpz_fdiv_q_ui(rz->z, Pympz_AS_MPZ(a), temp); } else if(temp == 0) { PyErr_SetString(PyExc_ZeroDivisionError, "mpz division by zero"); Py_DECREF((PyObject*)rz); return NULL; } else { mpz_cdiv_q_ui(rz->z, Pympz_AS_MPZ(a), -temp); mpz_neg(rz->z, rz->z); } return (PyObject *)rz; } #endif if(PyLong_Check(b)) { if (options.debug) fprintf(stderr, "True divide (mpz,long)\n"); #if PY_MAJOR_VERSION == 3 temp = PyLong_AsLongAndOverflow(b, &overflow); if(overflow) { #else temp = PyLong_AsLong(b); if(PyErr_Occurred()) { PyErr_Clear(); #endif mpz_inoc(tempz); mpz_set_PyLong(tempz, b); mpz_fdiv_q(rz->z, Pympz_AS_MPZ(a), tempz); mpz_cloc(tempz); } else if(temp > 0) { mpz_fdiv_q_ui(rz->z, Pympz_AS_MPZ(a), temp); } else if(temp == 0) { PyErr_SetString(PyExc_ZeroDivisionError, "mpz division by zero"); Py_DECREF((PyObject*)rz); return NULL; } else { mpz_cdiv_q_ui(rz->z, Pympz_AS_MPZ(a), temp); mpz_neg(rz->z, rz->z); } return (PyObject*)rz; } if(Pympz_Check(b)) { if(options.debug) fprintf(stderr, "True divide (integer,integer)\n"); if(mpz_sgn(Pympz_AS_MPZ(b)) == 0) { PyErr_SetString(PyExc_ZeroDivisionError, "mpz division by zero"); Py_DECREF((PyObject*)rz); return NULL; } mpz_fdiv_q(rz->z, Pympz_AS_MPZ(a), Pympz_AS_MPZ(b)); return (PyObject*)rz; } Py_DECREF((PyObject*)rz); } if(Pympz_Check(b)) { if(mpz_sgn(Pympz_AS_MPZ(b)) == 0) { PyErr_SetString(PyExc_ZeroDivisionError, "mpz division by zero"); return NULL; } if(!(rz = Pympz_new())) return NULL; #if PY_MAJOR_VERSION == 2 if(PyInt_Check(a)) { if (options.debug) fprintf(stderr, "True divide (small_int,mpz)\n"); mpz_inoc(tempz); mpz_set_si(tempz, PyInt_AS_LONG(a)); mpz_fdiv_q(rz->z, tempz, Pympz_AS_MPZ(b)); mpz_cloc(tempz); return (PyObject *)rz; } #endif if(PyLong_Check(a)) { if (options.debug) fprintf(stderr, "True divide (long,mpz)\n"); mpz_inoc(tempz); mpz_set_PyLong(tempz, a); mpz_fdiv_q(rz->z, tempz, Pympz_AS_MPZ(b)); mpz_cloc(tempz); return (PyObject*)rz; } Py_DECREF((PyObject*)rz); } /* Use truediv for rational types. */ if(isRational(a) && isRational(b)) { if(options.debug) fprintf(stderr, "True divide (rational,rational)\n"); paq = anyrational2Pympq(a); pbq = anyrational2Pympq(b); if(!paq || !pbq) { PyErr_SetString(PyExc_SystemError, "Can not convert rational to mpq"); Py_XDECREF((PyObject*)paq); Py_XDECREF((PyObject*)pbq); return NULL; } if(mpq_sgn(pbq->q)==0) { PyErr_SetString(PyExc_ZeroDivisionError, "mpq division by zero"); Py_DECREF((PyObject*)paq); Py_DECREF((PyObject*)pbq); return NULL; } if (!(rq = Pympq_new())) { Py_DECREF((PyObject*)paq); Py_DECREF((PyObject*)pbq); return NULL; } mpq_div(rq->q, paq->q, pbq->q); Py_DECREF((PyObject*)paq); Py_DECREF((PyObject*)pbq); return (PyObject *) rq; } /* Use truediv for floating-point types. */ if(isNumber(a) && isNumber(b)) { if(options.debug) fprintf(stderr, "True divide (number,number)\n"); if(Pympf_Check(a) && Pympf_Check(b)) { paf = anynum2Pympf(a, 0); pbf = anynum2Pympf(b, 0); } else if(Pympf_Check(a)) { paf = anynum2Pympf(a, 0); pbf = anynum2Pympf(b, paf->rebits); } else if(Pympf_Check(b)) { pbf = anynum2Pympf(b, 0); paf = anynum2Pympf(a, pbf->rebits); } else { pbf = anynum2Pympf(b, 0); paf = anynum2Pympf(a, 0); } if(!paf || !pbf) { if(PyErr_Occurred()) { PyErr_Clear(); } else { PyErr_SetString(PyExc_SystemError, "Internal error status is confused."); return NULL; } /* Need to handle special float values. */ if(pbf && !paf && PyFloat_Check(a)) { double d = PyFloat_AS_DOUBLE(a); if(isnan(d)) { if(mpf_sgn(pbf->f) == 0) { PyErr_SetString(PyExc_ZeroDivisionError, "mpf division by zero"); r = NULL; } else { r = PyFloat_FromDouble(d); } Py_DECREF((PyObject*)pbf); return r; } else if(isinf(d)) { if(mpf_sgn(pbf->f) == 0) { PyErr_SetString(PyExc_ZeroDivisionError, "mpf division by zero"); r = NULL; } else if(mpf_sgn(pbf->f) < 0) { r = PyFloat_FromDouble(-d); } else { r = PyFloat_FromDouble(d); } Py_DECREF((PyObject*)pbf); return r; } } else if(paf && !pbf && PyFloat_Check(b)) { double d = PyFloat_AS_DOUBLE(b); if(isnan(d)) { r = PyFloat_FromDouble(d); Py_DECREF((PyObject*)paf); return r; } else if(isinf(d)) { mpf_set_d(paf->f, 0.0); return (PyObject*)paf; } } else { PyErr_SetString(PyExc_SystemError, "Can not convert number to mpf"); Py_XDECREF((PyObject*)paf); Py_XDECREF((PyObject*)pbf); return NULL; } } if(mpf_sgn(pbf->f)==0) { PyErr_SetString(PyExc_ZeroDivisionError, "mpf division by zero"); Py_DECREF((PyObject*)paf); Py_DECREF((PyObject*)pbf); return NULL; } bits = paf->rebits; if(pbf->rebitsrebits; if (!(rf = Pympf_new(bits))) { Py_DECREF((PyObject*)paf); Py_DECREF((PyObject*)pbf); return NULL; } mpf_div(rf->f, paf->f, pbf->f); Py_DECREF((PyObject*)paf); Py_DECREF((PyObject*)pbf); mpf_normalize(rf->f); return (PyObject *) rf; } r = Py_NotImplemented; Py_INCREF(r); return r; } #endif /* Pympany_rem follows the % semantics from Python 3.x. The result types * are: * mpz % mpz -> mpz * mpq % mpq -> mpq * mpf % mpf -> mpf * * The behavior of mpq now mimics the behavior of fractions.Fraction. */ static PyObject * Pympany_rem(PyObject *a, PyObject *b) { PyObject *r = 0; mpz_t tempz; PympzObject *rz = 0; PympqObject *rq = 0, *paq = 0, *pbq = 0; PympfObject *rf = 0, *paf = 0, *pbf = 0; long temp; size_t bits, tempbits; #if PY_MAJOR_VERSION == 3 int overflow; #endif if(Pympz_Check(a)) { if(!(rz = Pympz_new())) return NULL; #if PY_MAJOR_VERSION == 2 if(PyInt_Check(b)) { if (options.debug) fprintf(stderr, "Modulo (mpz,small_int)\n"); if((temp=PyInt_AS_LONG(b)) == 0) { PyErr_SetString(PyExc_ZeroDivisionError, "mpz modulo by zero"); Py_DECREF((PyObject*)rz); return NULL; } else if(temp>0) { mpz_fdiv_r_ui(rz->z, Pympz_AS_MPZ(a), temp); } else { mpz_cdiv_r_ui(rz->z, Pympz_AS_MPZ(a), -temp); } return (PyObject *)rz; } #endif if(PyLong_Check(b)) { if (options.debug) fprintf(stderr, "Modulo (mpz,long)\n"); #if PY_MAJOR_VERSION == 3 temp = PyLong_AsLongAndOverflow(b, &overflow); if(overflow) { #else temp = PyLong_AsLong(b); if(PyErr_Occurred()) { PyErr_Clear(); #endif mpz_inoc(tempz); mpz_set_PyLong(tempz, b); mpz_fdiv_r(rz->z, Pympz_AS_MPZ(a), tempz); mpz_cloc(tempz); } else if(temp > 0) { mpz_fdiv_r_ui(rz->z, Pympz_AS_MPZ(a), temp); } else if(temp == 0) { PyErr_SetString(PyExc_ZeroDivisionError, "mpz modulo by zero"); Py_DECREF((PyObject*)rz); return NULL; } else { mpz_cdiv_r_ui(rz->z, Pympz_AS_MPZ(a), -temp); } return (PyObject *)rz; } if(Pympz_Check(b)) { if(options.debug) fprintf(stderr, "Modulo (integer,integer)\n"); if(mpz_sgn(Pympz_AS_MPZ(b)) == 0) { PyErr_SetString(PyExc_ZeroDivisionError, "mpz modulo by zero"); Py_DECREF((PyObject*)rz); return NULL; } mpz_fdiv_r(rz->z, Pympz_AS_MPZ(a), Pympz_AS_MPZ(b)); return (PyObject *)rz; } Py_DECREF((PyObject*)rz); } if(Pympz_Check(b)) { if(mpz_sgn(Pympz_AS_MPZ(b)) == 0) { PyErr_SetString(PyExc_ZeroDivisionError, "mpz division by zero"); return NULL; } if(!(rz = Pympz_new())) return NULL; #if PY_MAJOR_VERSION == 2 if(PyInt_Check(a)) { if (options.debug) fprintf(stderr, "Modulo (small_int,mpz)\n"); mpz_inoc(tempz); mpz_set_si(tempz, PyInt_AS_LONG(a)); mpz_fdiv_r(rz->z, tempz, Pympz_AS_MPZ(b)); mpz_cloc(tempz); return (PyObject *)rz; } #endif if(PyLong_Check(a)) { if (options.debug) fprintf(stderr, "Modulo (long,mpz)\n"); mpz_inoc(tempz); mpz_set_PyLong(tempz, a); mpz_fdiv_r(rz->z, tempz, Pympz_AS_MPZ(b)); mpz_cloc(tempz); return (PyObject *)rz; } Py_DECREF((PyObject*)rz); } if(isRational(a) && isRational(b)) { if(options.debug) fprintf(stderr, "Modulo (rational,rational)\n"); paq = anyrational2Pympq(a); pbq = anyrational2Pympq(b); if(!paq || !pbq) { PyErr_SetString(PyExc_SystemError, "Can not convert rational to mpq"); Py_XDECREF((PyObject*)paq); Py_XDECREF((PyObject*)pbq); return NULL; } if(mpq_sgn(pbq->q)==0) { PyErr_SetString(PyExc_ZeroDivisionError, "mpq modulo by zero"); Py_DECREF((PyObject*)paq); Py_DECREF((PyObject*)pbq); return NULL; } if (!(rq = Pympq_new())) { Py_XDECREF((PyObject*)rq); Py_DECREF((PyObject*)paq); Py_DECREF((PyObject*)pbq); return NULL; } mpz_inoc(tempz); mpq_div(rq->q, paq->q, pbq->q); mpz_fdiv_q(tempz, mpq_numref(rq->q), mpq_denref(rq->q)); /* Need to calculate paq - rz * pbq */ mpq_set_z(rq->q, tempz); mpq_mul(rq->q, rq->q, pbq->q); mpq_sub(rq->q, paq->q, rq->q); Py_DECREF((PyObject*)paq); Py_DECREF((PyObject*)pbq); mpz_cloc(tempz); return (PyObject *) rq; } if(isNumber(a) && isNumber(b)) { if(options.debug) fprintf(stderr, "Modulo (number,number)\n"); if(Pympf_Check(a) && Pympf_Check(b)) { paf = anynum2Pympf(a, 0); pbf = anynum2Pympf(b, 0); } else if(Pympf_Check(a)) { paf = anynum2Pympf(a, 0); pbf = anynum2Pympf(b, paf->rebits); } else if(Pympf_Check(b)) { pbf = anynum2Pympf(b, 0); paf = anynum2Pympf(a, pbf->rebits); } else { pbf = anynum2Pympf(b, 0); paf = anynum2Pympf(a, 0); } if(!paf || !pbf) { if(PyErr_Occurred()) { PyErr_Clear(); } else { PyErr_SetString(PyExc_SystemError, "Internal error status is confused."); return NULL; } /* Need to handle special float values. */ if(pbf && !paf && PyFloat_Check(a)) { double d = PyFloat_AS_DOUBLE(a); if(isnan(d)) { if(mpf_sgn(pbf->f) == 0) { PyErr_SetString(PyExc_ZeroDivisionError, "mpf division by zero"); r = NULL; } else { r = PyFloat_FromDouble(d); } Py_DECREF((PyObject*)pbf); return r; } else if(isinf(d)) { if(mpf_sgn(pbf->f) == 0) { PyErr_SetString(PyExc_ZeroDivisionError, "mpf division by zero"); r = NULL; } else if(mpf_sgn(pbf->f) < 0) { r = PyFloat_FromDouble(-d); } else { r = PyFloat_FromDouble(d); } Py_DECREF((PyObject*)pbf); return r; } } else if(paf && !pbf && PyFloat_Check(b)) { double d = PyFloat_AS_DOUBLE(b); if(isnan(d)) { r = PyFloat_FromDouble(d); Py_DECREF((PyObject*)paf); return r; } else if(isinf(d)) { mpf_set_d(paf->f, 0.0); return (PyObject*)paf; } } else { PyErr_SetString(PyExc_SystemError, "Can not convert number to mpf"); Py_XDECREF((PyObject*)paf); Py_XDECREF((PyObject*)pbf); return NULL; } } if(mpf_sgn(pbf->f)==0) { PyErr_SetString(PyExc_ZeroDivisionError, "mpf modulo by zero"); Py_DECREF((PyObject*)paf); Py_DECREF((PyObject*)pbf); return NULL; } bits = paf->rebits; if(pbf->rebitsrebits; /* To prevent rounding errors, the working precision is increased. */ tempbits = (paf->f->_mp_exp - pbf->f->_mp_exp) * GMP_NUMB_BITS + bits; if(options.debug) { fprintf(stderr, "Working precision %ld\n", tempbits); } if (!(rf = Pympf_new(tempbits))) { Py_DECREF((PyObject*)paf); Py_DECREF((PyObject*)pbf); return NULL; } mpf_div(rf->f, paf->f, pbf->f); mpf_floor(rf->f, rf->f); mpf_mul(rf->f, pbf->f, rf->f); mpf_sub(rf->f, paf->f, rf->f); mpf_set_prec(rf->f, bits); rf->rebits = bits; Py_DECREF((PyObject*)paf); Py_DECREF((PyObject*)pbf); mpf_normalize(rf->f); return (PyObject *) rf; } r = Py_NotImplemented; Py_INCREF(r); return r; } /* Pympany_divmod follows the semantics from Python 3.x. The result types * are: * divmod(mpz, mpz) -> (mpz, mpz) * divmod(mpq, mpq) -> (mpz, mpq) * divmod(mpf, mpf) -> (mpf, mpf) * * The behavior of mpq now mimics the behavior of fractions.Fraction. */ static PyObject * Pympany_divmod(PyObject *a, PyObject *b) { PyObject *r = 0; mpz_t tempz; PympzObject *qz = 0, *rz = 0; PympqObject *rq = 0, *paq = 0, *pbq = 0; PympfObject *qf = 0, *rf = 0, *paf = 0, *pbf = 0; long temp; size_t bits, tempbits; #if PY_MAJOR_VERSION == 3 int overflow; #endif if(Pympz_Check(a)) { if(!(r=PyTuple_New(2)) || !(rz=Pympz_new()) || !(qz=Pympz_new())) { Py_XDECREF((PyObject*)rz); Py_XDECREF((PyObject*)qz); Py_XDECREF(r); return NULL; } #if PY_MAJOR_VERSION == 2 if(PyInt_Check(b)) { if (options.debug) fprintf(stderr, "divmod (mpz,small_int)\n"); if((temp=PyInt_AS_LONG(b)) > 0) { mpz_fdiv_qr_ui(qz->z, rz->z, Pympz_AS_MPZ(a), temp); } else if(temp==0) { PyErr_SetString(PyExc_ZeroDivisionError, "mpz divmod by zero"); Py_DECREF((PyObject*)rz); Py_DECREF((PyObject*)qz); Py_DECREF(r); return NULL; } else { mpz_cdiv_qr_ui(qz->z, rz->z, Pympz_AS_MPZ(a), -temp); mpz_neg(qz->z, qz->z); } PyTuple_SET_ITEM(r, 0, (PyObject*)qz); PyTuple_SET_ITEM(r, 1, (PyObject*)rz); return r; } #endif if(PyLong_Check(b)) { if (options.debug) fprintf(stderr, "divmod (mpz,long)\n"); #if PY_MAJOR_VERSION == 3 temp = PyLong_AsLongAndOverflow(b, &overflow); if(overflow) { #else temp = PyLong_AsLong(b); if(PyErr_Occurred()) { PyErr_Clear(); #endif mpz_inoc(tempz); mpz_set_PyLong(tempz, b); mpz_fdiv_qr(qz->z, rz->z, Pympz_AS_MPZ(a), tempz); mpz_cloc(tempz); } else if(temp > 0) { mpz_fdiv_qr_ui(qz->z, rz->z, Pympz_AS_MPZ(a), temp); } else if(temp == 0) { PyErr_SetString(PyExc_ZeroDivisionError, "mpz divmod by zero"); Py_DECREF((PyObject*)rz); Py_DECREF((PyObject*)qz); Py_DECREF(r); return NULL; } else { mpz_cdiv_qr_ui(qz->z, rz->z, Pympz_AS_MPZ(a), -temp); mpz_neg(qz->z, qz->z); } PyTuple_SET_ITEM(r, 0, (PyObject*)qz); PyTuple_SET_ITEM(r, 1, (PyObject*)rz); return r; } if(Pympz_Check(b)) { if(options.debug) fprintf(stderr, "divmod (integer,integer)\n"); if(mpz_sgn(Pympz_AS_MPZ(b)) == 0) { PyErr_SetString(PyExc_ZeroDivisionError, "mpz divmod by zero"); Py_DECREF((PyObject*)rz); Py_DECREF((PyObject*)qz); Py_DECREF(r); return NULL; } mpz_fdiv_qr(qz->z, rz->z, Pympz_AS_MPZ(a), Pympz_AS_MPZ(b)); PyTuple_SET_ITEM(r, 0, (PyObject*)qz); PyTuple_SET_ITEM(r, 1, (PyObject*)rz); return r; } Py_DECREF((PyObject*)rz); } if(Pympz_Check(b)) { if(mpz_sgn(Pympz_AS_MPZ(b))==0) { PyErr_SetString(PyExc_ZeroDivisionError, "mpz modulo by zero"); return NULL; } if(!(r=PyTuple_New(2)) || !(rz=Pympz_new()) || !(qz=Pympz_new())) { Py_XDECREF((PyObject*)rz); Py_XDECREF((PyObject*)qz); Py_XDECREF(r); return NULL; } #if PY_MAJOR_VERSION == 2 if(PyInt_Check(a)) { if (options.debug) fprintf(stderr, "divmod (small_int,mpz)\n"); mpz_inoc(tempz); mpz_set_si(tempz, PyInt_AS_LONG(a)); mpz_fdiv_qr(qz->z, rz->z, tempz, Pympz_AS_MPZ(b)); mpz_cloc(tempz); PyTuple_SET_ITEM(r, 0, (PyObject*)qz); PyTuple_SET_ITEM(r, 1, (PyObject*)rz); return r; } #endif if(PyLong_Check(a)) { if (options.debug) fprintf(stderr, "divmod (long,mpz)\n"); mpz_inoc(tempz); mpz_set_PyLong(tempz, a); mpz_fdiv_qr(qz->z, rz->z, tempz, Pympz_AS_MPZ(b)); mpz_cloc(tempz); PyTuple_SET_ITEM(r, 0, (PyObject*)qz); PyTuple_SET_ITEM(r, 1, (PyObject*)rz); return r; } Py_DECREF((PyObject*)rz); } if(isRational(a) && isRational(b)) { if(options.debug) fprintf(stderr, "Divmod (rational,rational)\n"); paq = anyrational2Pympq(a); pbq = anyrational2Pympq(b); if(!paq || !pbq) { PyErr_SetString(PyExc_SystemError, "Can not convert rational to mpq"); Py_XDECREF((PyObject*)paq); Py_XDECREF((PyObject*)pbq); return NULL; } if(mpq_sgn(pbq->q)==0) { PyErr_SetString(PyExc_ZeroDivisionError, "mpq divmod by zero"); Py_DECREF((PyObject*)paq); Py_DECREF((PyObject*)pbq); return NULL; } if (!(rq = Pympq_new()) || !(qz = Pympz_new())) { Py_XDECREF((PyObject*)rq); Py_XDECREF((PyObject*)qz); Py_DECREF((PyObject*)paq); Py_DECREF((PyObject*)pbq); return NULL; } mpq_div(rq->q, paq->q, pbq->q); mpz_fdiv_q(qz->z, mpq_numref(rq->q), mpq_denref(rq->q)); /* Need to calculate paq - rz * pbq */ mpq_set_z(rq->q, qz->z); mpq_mul(rq->q, rq->q, pbq->q); mpq_sub(rq->q, paq->q, rq->q); Py_DECREF((PyObject*)paq); Py_DECREF((PyObject*)pbq); return Py_BuildValue("(NN)", qz, rq); } if(isNumber(a) && isNumber(b)) { if(options.debug) fprintf(stderr, "Divmod (number,number)\n"); if(Pympf_Check(a) && Pympf_Check(b)) { paf = anynum2Pympf(a, 0); pbf = anynum2Pympf(b, 0); } else if(Pympf_Check(a)) { paf = anynum2Pympf(a, 0); pbf = anynum2Pympf(b, paf->rebits); } else if(Pympf_Check(b)) { pbf = anynum2Pympf(b, 0); paf = anynum2Pympf(a, pbf->rebits); } else { pbf = anynum2Pympf(b, 0); paf = anynum2Pympf(a, 0); } if(!paf || !pbf) { if(PyErr_Occurred()) { PyErr_Clear(); } else { PyErr_SetString(PyExc_SystemError, "Internal error status is confused."); return NULL; } /* Need to handle special float values. */ if(pbf && !paf && PyFloat_Check(a)) { double d = PyFloat_AS_DOUBLE(a); if(isinf(d) || isnan(d)) { /* divmod(inf|nan, number) */ if(mpf_sgn(pbf->f) == 0) { /* if number == 0, raise ZeroDivisionError */ PyErr_SetString(PyExc_ZeroDivisionError, "mpf division by zero"); r = NULL; Py_DECREF((PyObject*)pbf); return r; } else { /* if number != 0, return (nan,nan) */ Py_DECREF((PyObject*)pbf); if(isinf(d)) { /* Ugly hack to avoid creating -NaN. This issue appears with * gcc 4.4.3: Inf * 0 returns -NaN. */ d = d * 0.0; paf = (PympfObject*)PyFloat_FromDouble(-d); pbf = (PympfObject*)PyFloat_FromDouble(-d); } else { paf = (PympfObject*)PyFloat_FromDouble(d); pbf = (PympfObject*)PyFloat_FromDouble(d); } return Py_BuildValue("(NN)", paf, pbf); } } } else if(paf && !pbf && PyFloat_Check(b)) { /* divmod(number, inf|nan) */ double d = PyFloat_AS_DOUBLE(b); if(isnan(d)) { Py_DECREF((PyObject*)paf); paf = (PympfObject*)PyFloat_FromDouble(d); pbf = (PympfObject*)PyFloat_FromDouble(d); return Py_BuildValue("(NN)", paf, pbf); } else if(isinf(d)) { if(mpf_sgn(paf->f) == 0) { /* if number == 0, return (0.0, 0.0) */ pbf = Pympf_new(paf->rebits); mpf_set_d(pbf->f, 0.0); mpf_set_d(paf->f, 0.0); return Py_BuildValue("(NN)", paf, pbf); } else if(mpf_sgn(paf->f) < 0) { if(d < 0) { /* return (0, number) */ /* XXX Not checking out-of-memory! */ pbf = Pympf_new(paf->rebits); mpf_set_d(pbf->f, 0.0); return Py_BuildValue("(NN)", pbf, paf); } else { /* return (-1.0, inf) */ pbf = Pympf_new(paf->rebits); mpf_set_d(pbf->f, -1.0); Py_DECREF((PyObject*)paf); paf = (PympfObject*)PyFloat_FromDouble(d); return Py_BuildValue("(NN)", pbf, paf); } } else { if(d > 0) { /* return (0, number) */ pbf = Pympf_new(paf->rebits); mpf_set_d(pbf->f, 0.0); return Py_BuildValue("(NN)", pbf, paf); } else { /* return (-1.0, inf) */ pbf = Pympf_new(paf->rebits); mpf_set_d(pbf->f, -1.0); Py_DECREF((PyObject*)paf); paf = (PympfObject*)PyFloat_FromDouble(d); return Py_BuildValue("(NN)", pbf, paf); } } } } else { PyErr_SetString(PyExc_SystemError, "Can not convert number to mpf"); Py_XDECREF((PyObject*)paf); Py_XDECREF((PyObject*)pbf); return NULL; } } if(mpf_sgn(pbf->f)==0) { PyErr_SetString(PyExc_ZeroDivisionError, "mpf divmod by zero"); Py_DECREF((PyObject*)paf); Py_DECREF((PyObject*)pbf); return NULL; } bits = paf->rebits; if(pbf->rebitsrebits; /* To prevent rounding errors, the working precision is increased. */ tempbits = (paf->f->_mp_exp - pbf->f->_mp_exp) * GMP_NUMB_BITS + bits; if(options.debug) { fprintf(stderr, "Working precision %ld\n", tempbits); } if (!(qf = Pympf_new(tempbits)) || !(rf = Pympf_new(tempbits))) { Py_XDECREF((PyObject*)qf); Py_XDECREF((PyObject*)rf); Py_DECREF((PyObject*)paf); Py_DECREF((PyObject*)pbf); return NULL; } mpf_div(qf->f, paf->f, pbf->f); mpf_floor(qf->f, qf->f); mpf_mul(rf->f, pbf->f, qf->f); mpf_sub(rf->f, paf->f, rf->f); mpf_set_prec(rf->f, bits); rf->rebits = bits; mpf_set_prec(qf->f, bits); qf->rebits = bits; Py_DECREF((PyObject*)paf); Py_DECREF((PyObject*)pbf); mpf_normalize(qf->f); mpf_normalize(rf->f); return Py_BuildValue("(NN)", qf, rf); } r = Py_NotImplemented; Py_INCREF(r); return r; } gmpy-1.17/src/gmpy.vcproj0000666000000000000000000002031512174774730014125 0ustar rootroot gmpy-1.17/src/gmpy.sln0000666000000000000000000000231312174774730013414 0ustar rootroot Microsoft Visual Studio Solution File, Format Version 10.00 # Visual Studio 2008 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gmpy", "gmpy.vcproj", "{CA80B30F-7C98-4A7C-A412-9E0012C5E27E}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 Debug|x64 = Debug|x64 Release|Win32 = Release|Win32 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {CA80B30F-7C98-4A7C-A412-9E0012C5E27E}.Debug|Win32.ActiveCfg = Debug|Win32 {CA80B30F-7C98-4A7C-A412-9E0012C5E27E}.Debug|Win32.Build.0 = Debug|Win32 {CA80B30F-7C98-4A7C-A412-9E0012C5E27E}.Debug|x64.ActiveCfg = Debug|x64 {CA80B30F-7C98-4A7C-A412-9E0012C5E27E}.Debug|x64.Build.0 = Debug|x64 {CA80B30F-7C98-4A7C-A412-9E0012C5E27E}.Release|Win32.ActiveCfg = Release|Win32 {CA80B30F-7C98-4A7C-A412-9E0012C5E27E}.Release|Win32.Build.0 = Release|Win32 {CA80B30F-7C98-4A7C-A412-9E0012C5E27E}.Release|x64.ActiveCfg = Release|x64 {CA80B30F-7C98-4A7C-A412-9E0012C5E27E}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal gmpy-1.17/src/gmpy.h0000666000000000000000000001543212174774730013055 0ustar rootroot/* gmpy C API extension header file. Part of Python's gmpy module since version 0.4 Created by Pearu Peterson , November 2000. Edited by A. Martelli , December 2000. Version 1.02, February 2007. Version 1.03, June 2008 Version 1.04, June 2008 (no changes) Version 1.05, February 2009 (support MPIR) */ #ifndef Py_GMPYMODULE_H #define Py_GMPYMODULE_H #ifdef __cplusplus extern "C" { #endif #if defined(MS_WIN32) && defined(_MSC_VER) /* the __MPN determination in stock gmp.h doesn't work, so...: */ # define __MPN(x) __gmpn_##x # define _PROTO(x) x #define inline __inline #endif #if defined MPIR #include "mpir.h" #else #include "gmp.h" #endif /* ensure 2.5 compatibility */ #if PY_VERSION_HEX < 0x02050000 typedef int Py_ssize_t; #define PY_FORMAT_SIZE_T "" #endif #ifndef Py_TPFLAGS_HAVE_INDEX #define Py_TPFLAGS_HAVE_INDEX 0 #endif #if PY_VERSION_HEX < 0x030200A3 typedef long Py_hash_t; typedef unsigned long Py_uhash_t; #endif /* Header file for gmpy */ typedef struct { PyObject_HEAD /* PyObject* callable; */ /* long flags; */ } mpob; typedef struct { mpob ob; mpz_t z; } PympzObject; typedef struct { mpob ob; mpq_t q; } PympqObject; typedef struct { mpob ob; mpf_t f; size_t rebits; } PympfObject; /* #define MPOBCAL(obj) ((mpob*)obj)->callable */ /* #define MPOBFLA(obj) ((mpob*)obj)->flags */ #define Pympz_AS_MPZ(obj) (((PympzObject *)(obj))->z) #define Pympq_AS_MPQ(obj) (((PympqObject *)(obj))->q) #define Pympf_AS_MPF(obj) (((PympfObject *)(obj))->f) #define Pympz_Type_NUM 0 #define Pympq_Type_NUM 1 #define Pympf_Type_NUM 2 /* C API functions */ #define Pympz_new_NUM 3 #define Pympz_new_RETURN PympzObject * #define Pympz_new_PROTO (void) #define Pympq_new_NUM 4 #define Pympq_new_RETURN PympqObject * #define Pympq_new_PROTO (void) #define Pympf_new_NUM 5 #define Pympf_new_RETURN PympfObject * #define Pympf_new_PROTO (size_t bits) #define Pympz_dealloc_NUM 6 #define Pympz_dealloc_RETURN void #define Pympz_dealloc_PROTO (PympzObject *self) #define Pympq_dealloc_NUM 7 #define Pympq_dealloc_RETURN void #define Pympq_dealloc_PROTO (PympqObject *self) #define Pympf_dealloc_NUM 8 #define Pympf_dealloc_RETURN void #define Pympf_dealloc_PROTO (PympfObject *self) #define Pympz_convert_arg_NUM 9 #define Pympz_convert_arg_RETURN int #define Pympz_convert_arg_PROTO (PyObject *arg, PyObject **ptr) #define Pympq_convert_arg_NUM 10 #define Pympq_convert_arg_RETURN int #define Pympq_convert_arg_PROTO (PyObject *arg, PyObject **ptr) #define Pympf_convert_arg_NUM 11 #define Pympf_convert_arg_RETURN int #define Pympf_convert_arg_PROTO (PyObject *arg, PyObject **ptr) /* Total number of C API pointers */ #define Pygmpy_API_pointers 12 #ifdef GMPY_MODULE /* This section is used when compiling gmpy.c */ static PyTypeObject Pympz_Type; #define Pympz_Check(v) (((PyObject*)v)->ob_type == &Pympz_Type) static PyTypeObject Pympq_Type; #define Pympq_Check(v) (((PyObject*)v)->ob_type == &Pympq_Type) static PyTypeObject Pympf_Type; #define Pympf_Check(v) (((PyObject*)v)->ob_type == &Pympf_Type) static Pympz_new_RETURN Pympz_new Pympz_new_PROTO; static Pympz_dealloc_RETURN Pympz_dealloc Pympz_dealloc_PROTO; static Pympz_convert_arg_RETURN Pympz_convert_arg Pympz_convert_arg_PROTO; static Pympq_new_RETURN Pympq_new Pympq_new_PROTO; static Pympq_dealloc_RETURN Pympq_dealloc Pympq_dealloc_PROTO; static Pympq_convert_arg_RETURN Pympq_convert_arg Pympq_convert_arg_PROTO; static Pympf_new_RETURN Pympf_new Pympf_new_PROTO; static Pympf_dealloc_RETURN Pympf_dealloc Pympf_dealloc_PROTO; static Pympf_convert_arg_RETURN Pympf_convert_arg Pympf_convert_arg_PROTO; #if PY_MAJOR_VERSION < 3 #define export_gmpy(m) { \ PyObject *d; \ static void *Pygmpy_API[Pygmpy_API_pointers]; \ PyObject *c_api_object; \ \ Pygmpy_API[Pympz_Type_NUM] = (void*)&Pympz_Type;\ Pygmpy_API[Pympq_Type_NUM] = (void*)&Pympq_Type;\ Pygmpy_API[Pympf_Type_NUM] = (void*)&Pympf_Type;\ \ Pygmpy_API[Pympz_new_NUM] = (void*)Pympz_new;\ Pygmpy_API[Pympz_dealloc_NUM] = (void*)Pympz_dealloc;\ Pygmpy_API[Pympz_convert_arg_NUM] = (void*)Pympz_convert_arg;\ Pygmpy_API[Pympq_new_NUM] = (void*)Pympq_new;\ Pygmpy_API[Pympq_dealloc_NUM] = (void*)Pympq_dealloc;\ Pygmpy_API[Pympq_convert_arg_NUM] = (void*)Pympq_convert_arg;\ Pygmpy_API[Pympf_new_NUM] = (void*)Pympf_new;\ Pygmpy_API[Pympf_dealloc_NUM] = (void*)Pympf_dealloc;\ Pygmpy_API[Pympf_convert_arg_NUM] = (void*)Pympf_convert_arg;\ \ c_api_object = PyCObject_FromVoidPtr((void*)Pygmpy_API, NULL);\ d = PyModule_GetDict(m);\ PyDict_SetItemString(d, "_C_API", c_api_object);\ } #endif #else /* This section is used in other C-coded modules that use gmpy's API */ static void **Pygmpy_API; #define Pympz_Check(op) \ ((op)->ob_type == (PyTypeObject *)Pygmpy_API[Pympz_Type_NUM]) #define Pympz_Type (*(PyTypeObject *)Pygmpy_API[Pympz_Type_NUM]) #define Pympq_Check(op) \ ((op)->ob_type == (PyTypeObject *)Pygmpy_API[Pympq_Type_NUM]) #define Pympq_Type (*(PyTypeObject *)Pygmpy_API[Pympq_Type_NUM]) #define Pympf_Check(op) \ ((op)->ob_type == (PyTypeObject *)Pygmpy_API[Pympf_Type_NUM]) #define Pympf_Type (*(PyTypeObject *)Pygmpy_API[Pympf_Type_NUM]) #define Pympz_new \ (*(Pympz_new_RETURN (*)Pympz_new_PROTO) Pygmpy_API[Pympz_new_NUM]) #define Pympz_dealloc \ (*(Pympz_dealloc_RETURN (*)Pympz_dealloc_PROTO) Pygmpy_API[Pympz_dealloc_NUM]) #define Pympz_convert_arg \ (*(Pympz_convert_arg_RETURN (*)Pympz_convert_arg_PROTO) Pygmpy_API[Pympz_convert_arg_NUM]) #define Pympq_new \ (*(Pympq_new_RETURN (*)Pympq_new_PROTO) Pygmpy_API[Pympq_new_NUM]) #define Pympq_dealloc \ (*(Pympq_dealloc_RETURN (*)Pympq_dealloc_PROTO) Pygmpy_API[Pympq_dealloc_NUM]) #define Pympq_convert_arg \ (*(Pympq_convert_arg_RETURN (*)Pympq_convert_arg_PROTO) Pygmpy_API[Pympq_convert_arg_NUM]) #define Pympf_new \ (*(Pympf_new_RETURN (*)Pympf_new_PROTO) Pygmpy_API[Pympf_new_NUM]) #define Pympf_dealloc \ (*(Pympf_dealloc_RETURN (*)Pympf_dealloc_PROTO) Pygmpy_API[Pympf_dealloc_NUM]) #define Pympf_convert_arg \ (*(Pympf_convert_arg_RETURN (*)Pympf_convert_arg_PROTO) Pygmpy_API[Pympf_convert_arg_NUM]) #if PY_MAJOR_VERSION < 3 #define import_gmpy() \ { \ PyObject *module = PyImport_ImportModule("gmpy");\ if (module != NULL) { \ PyObject *module_dict = PyModule_GetDict(module); \ PyObject *c_api_object = PyDict_GetItemString(module_dict, "_C_API"); \ if (PyCObject_Check(c_api_object)) { \ Pygmpy_API = (void **)PyCObject_AsVoidPtr(c_api_object); \ } \ } \ } #else static int import_gmpy(void) { Pygmpy_API = (void **)PyCapsule_Import("gmpy._C_API", 0); return (Pygmpy_API != NULL) ? 0 : -1; } #endif #endif #ifdef __cplusplus } #endif #endif /* !defined(Py_GMPYMODULE_H */ gmpy-1.17/src/gmpy.c0000666000000000000000000067334312174774730013063 0ustar rootroot/* gmpy.c * * Python interface to the GMP or MPIR multiple precision library, * Copyright (C) 2000 - 2010 Alex Martelli * Copyright (C) 2008 - 2012 Case Van Horsen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * ************************************************************************* * * originally written for GMP-2.0 (by AMK...?) * Rewritten by Niels Möller, May 1996 * * Version for GMP-4, Python 2.X, with support for MSVC++6, * addition of mpf's, &c: Alex Martelli (now aleaxit@gmail.com, Nov 2000). * cleanups & reorgs leading to 1.0: Alex Martelli (until Aug 2003) * further cleanups and bugfixes leading to 1.01, Alex Martelli (Nov 2005) * minor bugfixes+new decimal (&c) support to 1.02, Alex Martelli (Feb 2006) * various bugfixes for 64-bit platforms, 1.03, aleaxit and casevh (Jun 2008) * rich comparisons, 1.04, aleaxit and casevh (Jan 2009) * support for Python 3.x, 1.10, casevh (Oct 2009) * * Some hacks by Gustavo Niemeyer . * * 0.1, pre-alpha; date: 2000-11-06 first placed on sourceforge * * 0.2, still pre-alpha: 2000-11-15: bugfixes re formatting (tx, Peanu!) * no tags on oct() and hex() of mpz's * insert 'tagoff' in options (gmpy.mpz() vs mpz() in repr) (for Peanu!) * speedups for _nonzero & _cmp (tx, Peanu!) * slight speedup (7/8%?) for excess reallocs 4<->8 bytes (Peanu's help!) * added copy/fcopy; bin; fib; remove * * 0.3, still pre-alpha, but...: * performance tweaks via mpz-caching & fixed-constants * added get/set functions for zcache, zco min/max * added get-only function for versions (of gmp, and of gmpy) * removed all 'traces' of mutability (to be re-done... much later!) * cleaned up all of the mpz_cmp_ui(X,0) to mpz_sgn(X) * cleaned up Py_BuildValue usage (N vs O, explicit-() for tuples) * added numdigits, lowbits, root, next_prime, invert, popcount, * hamdist, scan0, scan1 * renamed bin to bincoef * * 0.4: * split gmpy.c/gmpy.h introducing C-API interface (Pearu's suggestion) * cleanup some casts using Pearu's new macros * further cache-tweaks at Pearu's suggestion (macros introduced) * added sign (Pearu's request), getbit, setbit * added docstrings * renamed copy functions to start with _ ('internal, private') * added .comb as a synonym of .bincoef * * 0.5: * added jacobi, legendre, kronecker * added random-number generation, seed set/save, shuffling * added mpq (at last!-) * * 0.6: (lots of good ideas from Pearu once more!-): * fixed silly bugs in kronecker and mpq_abs * gmpy-level workaround for scan0/scan1 bugs (?) in GMP 3.1.1 * added qdiv; anynum->mpq substituted for all such conversions * (also anynum->mpz and anynum->mpf by analogy, with care!) * added options.fcoform for optional use of intermediate string in * float2mpf (used for any float->mpf conversion) * added set_fcoform function for options.fcoform access * general cleanup of sources; added alloca for MSVC++; * many sundry minor bugfixes & uniformization; * a little useful refactoring (more would be good...) * added caching of mpq objects * power for mpq * Stern-Brocot algorithm for mpf->mpq (also exposed as f2q) * also used for float->mpq * with stricter tracking of mpf's requested-precision * added getrprec method to mpf, getrprec module-function * exposed ceil, floor and trunc methods/functions for mpf's * changed a couple exceptions from Value to ZeroDivision * added 'qual' and 'floa' options to gmpy.rand * * 0.7: (good feedback from Keith Briggs, some advice from Tim Peters * and Fred Lundh -- thanks all!): * fixed bug of '"%d" where "%ld" was meant' in many places * and other sundry minor warnings given by gcc * fixed hash (delegating to Python) so mp[nqz](x) will * produce the same value as hash(x) for any Python number x * workaround for GMP 3.1.1 bug, mpz_root wrongly returning * 'exact' for non-exact root if dest==source, which stopped * needed value-error for inexact mpq**mpq operations * determined correct 'actual precision' of floats * explicitly stored precision with binary-form mpf's * extended explicit-bits request to all ->mpf operations * (good in itself, plus, preparing for future MPFR) * removed the limitation of no binary-form for <0 mpz * introduced macros to parse args, for conciseness * * 0.8: (again, requests & suggestions by great Pearu!) * raise test coverage 72.5% -> 90.0% * introduced callbacks (not documented/tested for now; * Pearu will test/support/document in PySymbolic) * some errors went undiagnosed, caused crash: now fixed * workaround for GMP bug(?s?) in mpz_fits_... (?) * added exposure of mpf_ sqrt and pow_ui * * 0.9: (ditto) * change ValueError to OverflowError for 'too-large' errors * fix bug in mpq_pow (negative base, exp. with odd denominator) * (fix now corrected -- _even_ denominator is the error!) * fixed gcc warnings reported by K. Briggs * * 0.9b: * support GMP 4 (but added no GMP4-only functionality yet) * * 0.9c: * updated tests to 0.9, better coverage * * 1.0: * minor cleanups, ensure support for Python 2.3 * fixed misdiagnosis of some argument counts in macro * SELF_ONE_ARG_CONVERTED (tx to Paul Rubin!) * * 1.01: * cleanups, ensure support for Python 2.4.1 on MacOSX 10.4/XCode 2.1 * as well as Python 2.2 and 2.3 (on MacOSX and Linux) * fixed memory leak on divm (thanks to mensanator@aol.com) * fixed bug on mpq('123') [[str2mpq on string w/o a slash]] * added floordiv and truediv operators, and tests for them * NOT tested on GMP 3 (have none left around...), ONLY on GMP 4.* * * 1.02: * fix warning in comparison of mpq's * added support of mpq('12.34') [[string w/o a slash, but with a dot]] * fixes for 64-bit build (thanks to a patch by dmcooke) * added experimental support for decimal.Decimal (and user-coded types) * via wider use of special conversion methods (if present) and their * sly insertion on-the-fly into the decimal.Decimal class (!) * two bugfixes, thanks to Simon Burton * Brought back into C89 compliance (thanks to Chip Turner), had * drifted to C99 (declarations in the middle of the code). * Python 2.5 support (Py_ssize_t, __index__) thanks to Chip Turner * Pushed coverage to 93.3% (missing only "sanity check" level error * tests [mostly for out-of-memory conditions], output to stderr * conditioned by options.debug, & a couple of very obscure cases) * * 1.03: * Fixed the bug that caused crashes on gmpy.mpf(float('inf')) and * other such conversions, implicit and explicit * Fixed a bug in get_zconst's prototype affecting 64-bit machines, * thanks to Gary Bunting * Fixed a bug in hashing on 64-bit systems. hash(long) now equals * hash(mpz) for large values. (casevh) * Changed int() to return a long value instead of OverFlowError. * Complies with PEP 237. (casevh) * Added support in setup.py for darwinports/macports build of GMP * on MacOSX. (aleaxit) * * 1.04: * Avoid GMP/mingw32 bug when converting very small floats to mpz. * (casevh) * Significant performance improvement for long->mpz and mpz->long. * (casevh) * Added "rich comparisons" to mpz, mpq and mpf types (aleaxit) * Added additional tests (casevh, aleaxit) * Fixed bug when converting very large mpz to str (casevh) * Faster conversion from mpz->binary and binary->mpz (casevh) * Added support for pickling (casevh) * Added divexact (casevh) * Fixed mpf comparisons by rounding mpf results when GMP returns * a longer result. Added fround() (casevh) * Added bit_length (Thanks Mario Pernici) * Added helper functions for mpmath (casevh) * Faster conversion from mpq->binary and binary->mpq (casevh) * Recognize MPIR, mpir_version() (casevh) * * 1.10: * Remove dependancy on pymemcompat.h (casevh) * Remove callback (casevh) * Added support for -DMPIR to include MPIR instead of GMP (casevh) * Major code revisions to add support for Python 3.x (casevh) * Fixed bug in binary() and qbinary() (casevh) * Fixed bug in rich comparisons (casevh) * Added % and divmod support to mpq and mpf (casevh) * Changed memory allocation functions to use PyMem (casevh) * Removed small number interning (casevh) * Added tdivmod, cdivmod, and fdivmod (casevh) * Added more helper functions for mpmath (casevh) * Faster mpz<>PyLong conversion (casevh) * Faster hash(mpz) (casevh) * * 1.11: * Recognize True/False (bug in 1.10) (casevh) * Optimize argument handling (casevh) * Added caching for mpz (casevh) * * 1.12: * Fix test compatibility with Python 3.1.2 and 3.2 (casevh) * Change hash function for Python 3.2 (casevh) * Support MPIR 2.0 (casevh) * * 1.13: * Fix regression in formatting of mpq (casevh) * Improved caching for mpq (casevh) * Added .numerator and .denominator to mpq (casevh) * * 1.14 * Fix leaking reference in basic operations (casevh) * Fixed incorrect type declaration for options.debug (casevh) * Support wide hash result on Win64, new for Python 3.2 (casevh) * Fix repr(mpq) formatting when denominator was 1 (casevh) * * 1.15 * Fix ref-count bug in divmod(x,0) (casevh) * Fix crash in remove(n,1) (casevh) * Discontinue use of custom memory allocator & PyMem (casevh) * Modified directory search logic in setup.py (casevh) * Allow base-62 conversion for mpz and mpf (casevh) * * 1.16 * Fix compatibility with Python 2.4 (casevh) * Fix compatibility with Python 3.3 (casevh) * * 1.17 * Fix gmpy's C-API support for Python 3.x (casevh) */ #include "Python.h" /* * we do have a dependence on Python's internals, specifically: * how Python "long int"s are internally represented. */ #include "longintrepr.h" #include #include #include #include #define GMPY_MODULE #include "gmpy.h" /* To prevent excessive memory usage, we don't want to save very large * numbers in the cache. The default value specified in the options * structure is 128 words (512 bytes on 32-bit platforms, 1024 bytes on * 64-bit platforms). */ #define MAX_CACHE_LIMBS 16384 /* The maximum number of objects that can be saved in a cache is specified * here. The default value is 100.*/ #define MAX_CACHE 1000 #if defined(MS_WIN32) && defined(_MSC_VER) /* so one won't need to link explicitly to gmp.lib...: */ #if defined(MPIR) #pragma comment(lib,"mpir.lib") #else #pragma comment(lib,"gmp.lib") #endif #define isnan _isnan #define isinf !_finite #define USE_ALLOCA 1 #endif #ifdef __GNUC__ #define USE_ALLOCA 1 #endif #ifndef alloca # ifdef __GNUC__ # define alloca __builtin_alloca # else # ifdef _MSC_VER # include # define alloca _alloca # else # if HAVE_ALLOCA_H # include # else char *alloca (); # endif # endif # endif #endif #define Py_RETURN_NOTIMPLEMENTED\ return Py_INCREF(Py_NotImplemented), Py_NotImplemented /* Define various macros to deal with differences between Python 2 and 3. */ #if PY_MAJOR_VERSION >= 3 #define Py2or3Int_FromLong PyLong_FromLong #define Py2or3String_FromString PyUnicode_FromString #define Py2or3String_Check PyUnicode_Check #define Py2or3String_Format PyUnicode_Format #define Py2or3String_AsString PyUnicode_AS_DATA #define Py2or3Bytes_ConcatAndDel PyBytes_ConcatAndDel #define Py2or3Bytes_FromString PyBytes_FromString #define Py2or3Bytes_AS_STRING PyBytes_AS_STRING #define Py2or3Bytes_FromStringAndSize PyBytes_FromStringAndSize #else #define Py2or3Int_FromLong PyInt_FromLong #define Py2or3String_FromString PyString_FromString #define Py2or3String_Check PyString_Check #define Py2or3String_Format PyString_Format #define Py2or3String_AsString PyString_AsString #define Py2or3Bytes_ConcatAndDel PyString_ConcatAndDel #define Py2or3Bytes_FromString PyString_FromString #define Py2or3Bytes_AS_STRING PyString_AS_STRING #define Py2or3Bytes_FromStringAndSize PyString_FromStringAndSize #endif #ifndef PyLong_SHIFT #define PyLong_SHIFT SHIFT #endif #ifndef PyLong_MASK #define PyLong_MASK MASK #endif #ifndef Py_SIZE #define Py_SIZE(ob) (((PyVarObject*)(ob))->ob_size) #endif #ifndef Py_TYPE #define Py_TYPE(ob) (((PyObject*)(ob))->ob_type) #endif #ifndef Py_REFCNT #define Py_REFCNT(ob) (((PyObject*)(ob))->ob_refcnt) #endif /* Include fast mpz to/from PyLong conversion from sage. */ #include "mpz_pylong.c" #ifdef __MPIR_VERSION #define MPIR_VER \ __MPIR_VERSION * 10000 + \ __MPIR_VERSION_MINOR * 100 + \ __MPIR_VERSION_PATCHLEVEL #if ((MPIR_VER < 10300) && (MPIR_VER > 10399)) char gmpy_license[] = "\ The GMPY source code is licensed under LGPL 2.1 or later. \ This version of the MPIR library is licensed under LGPL 3 or later. \ Therefore, this combined module is licensed under LGPL 3 or later.\ "; #else char gmpy_license[] = "\ The GMPY source code is licensed under LGPL 2.1 or later. \ This version of the MPIR library is licensed under LGPL 2.1 or later. \ Therefore, this combined module is licensed under LGPL 2.1 or later.\ "; #endif #else #define GNU_MP_VER \ __GNU_MP_VERSION * 10000 + \ __GNU_MP_VERSION_MINOR * 100 + \ __GNU_MP_VERSION_PATCHLEVEL #if GNU_MP_VER > 40201 char gmpy_license[] = "\ The GMPY source code is licensed under LGPL 2.1 or later. \ This version of the GMP library is licensed under LGPL 3 or later. \ Therefore, this combined module is licensed under LGPL 3 or later.\ "; #else char gmpy_license[] = "\ The GMPY source code is licensed under LGPL 2.1 or later. \ This version of the GMP library is licensed under LGPL 2.1 or later. \ Therefore, this combined module is licensed under LGPL 2.1 or later.\ "; #endif #endif #undef GNU_MP_VER char gmpy_version[] = "1.17"; char _gmpy_cvs[] = "$Id: gmpy.c 818 2013-07-21 05:52:09Z casevh $"; #define ALLOC_THRESHOLD 8192 #ifdef USE_ALLOCA #define TEMP_ALLOC(B, S) \ if(S < ALLOC_THRESHOLD) { \ B = alloca(S); \ } else { \ if(!(B = malloc(S))) { \ PyErr_NoMemory(); \ return NULL; \ } \ } #define TEMP_FREE(B, S) if(S >= ALLOC_THRESHOLD) free(B) #else #define TEMP_ALLOC(B, S) \ if(!(B = malloc(S))) { \ PyErr_NoMemory(); \ return NULL; \ } #define TEMP_FREE(B, S) free(B) #endif /* * global data declarations */ static PyObject *gmpy_module = NULL; static struct gmpy_options { int debug; /* != 0 if debug messages desired on stderr */ long minprec; /* min #of bits' precision on new mpf's built */ int tagoff; /* 0 for full tags 'gmpy.mpz()', else 5 for 'mpz()' */ int cache_size; /* size of cache, for all caches */ int cache_obsize; /* maximum size of the objects that are cached */ PyObject* fcoform; /* if non-NULL, format for float->mpf (via string) */ } options = { 0, 0, 5, 100, 128, 0 }; /* Number of bits that are significant in a float */ static unsigned int double_mantissa = 0; /* caching macro (later expanded for mpz, mpq, mpf) */ #define DEFCACHE(mpX_t,Xcache,in_Xcache,set_Xcache,mpX_clear) \ static mpX_t* Xcache; \ static int in_Xcache; \ static void set_Xcache(void) \ { \ if(in_Xcache > options.cache_size) { \ int i; \ if(options.debug) \ fprintf(stderr, "Clean %d from " #Xcache "\n", \ in_Xcache-options.cache_size); \ for(i=options.cache_size; i_mp_alloc <= options.cache_obsize) { (zcache[in_zcache++])[0] = oldo[0]; if(options.debug) fprintf(stderr, "Stashed %d to zcache\n", in_zcache); } else { if(options.debug) fprintf(stderr, "Not placing in full zcache(%d/%d)\n", in_zcache, options.cache_size); mpz_clear(oldo); } } /* init-or-cache macro & function -- fetch from cache, else init, an MPQ */ static void mpq_inoc(mpq_t newo) { if(in_qcache) { if(options.debug) fprintf(stderr, "Getting %d from qcache\n", in_qcache); newo[0] = (qcache[--in_qcache])[0]; } else { if(options.debug) fprintf(stderr, "Initing new not in qcache\n"); mpq_init(newo); if(options.debug) fprintf(stderr, "Initing new not in qcache, done\n"); } } /* clear-or-cache macro & function -- stash into cache, else clear, an MPQ */ static void mpq_cloc(mpq_t oldo) { if(in_qcache_mp_alloc <= options.cache_obsize && mpq_denref(oldo)->_mp_alloc <= options.cache_obsize) { (qcache[in_qcache++])[0] = oldo[0]; if(options.debug) fprintf(stderr, "Stashed %d to qcache\n", in_qcache); } else { if(options.debug) fprintf(stderr, "Not placing in full qcache(%d/%d)\n", in_qcache, options.cache_size); mpq_clear(oldo); } } #ifdef FALSE /* init-or-cache macro & function -- fetch from cache, else init, an MPF */ static void mpf_inoc(mpf_t newo) { if(in_fcache) { if(options.debug) fprintf(stderr, "Getting %d from fcache\n", in_fcache); newo[0] = (fcache[--in_fcache])[0]; } else { if(options.debug) fprintf(stderr, "Initing new not in fcache\n"); mpf_init(newo); } } /* clear-or-cache macro & function -- stash into cache, else clear, an MPF */ static void mpf_cloc(mpf_t oldo) { if(in_fcache options.cache_size) { for(i = options.cache_size; i < in_pympzcache; ++i) { mpz_cloc(pympzcache[i]->z); PyObject_Del(pympzcache[i]); } in_pympzcache = options.cache_size; } pympzcache = realloc(pympzcache, sizeof(PympzObject)*options.cache_size); } /* Cache Pympq objects directly */ static PympqObject **pympqcache; static int in_pympqcache; static void set_pympqcache(void) { int i; if(options.debug) fprintf(stderr, "Entering set_pympqcache\n"); if(in_pympqcache > options.cache_size) { for(i = options.cache_size; i < in_pympqcache; ++i) { mpq_cloc(pympqcache[i]->q); PyObject_Del(pympqcache[i]); } in_pympqcache = options.cache_size; } pympqcache = realloc(pympqcache, sizeof(PympqObject)*options.cache_size); } /* forward declarations of type-objects and method-arrays for them */ #ifdef _MSC_VER PyTypeObject Pympz_Type; PyTypeObject Pympq_Type; PyTypeObject Pympf_Type; PyMethodDef Pympz_methods []; PyMethodDef Pympq_methods []; PyMethodDef Pympf_methods []; #endif #ifdef ignore_me static PyTypeObject Pympz_Type; static PyTypeObject Pympq_Type; static PyTypeObject Pympf_Type; static PyMethodDef Pympz_methods []; static PyMethodDef Pympq_methods []; static PyMethodDef Pympf_methods []; #endif /* utility macros for argument parsing */ /* * Verify that a function expects no arguments. "msg" should be an error * message that includes the function name. Replaces NO_ARGS. */ #define PARSE_NO_ARGS(msg)\ if (PyTuple_GET_SIZE(args) != 0) {\ PyErr_SetString(PyExc_TypeError, msg);\ return NULL;\ } /* * Parses one, and only one, argument into "self" and converts it to an * mpz. Is faster, but not as generic, as using PyArg_ParseTuple. It * supports either gmpy2.fname(z) or z.fname(). "self" must be decref'ed. * "msg" should be an error message that includes the function name and * describes the required arguments. Replaces SELF_MPZ_NO_ARG. */ #define PARSE_ONE_MPZ(msg) \ if(self && Pympz_Check(self)) {\ if (PyTuple_GET_SIZE(args) != 0) {\ PyErr_SetString(PyExc_TypeError, msg);\ return NULL;\ }\ Py_INCREF(self);\ } else {\ if (PyTuple_GET_SIZE(args) != 1) {\ PyErr_SetString(PyExc_TypeError, msg);\ return NULL;\ }\ self = (PyObject*)Pympz_From_Integer(PyTuple_GET_ITEM(args, 0));\ if(!self) {\ PyErr_SetString(PyExc_TypeError, msg);\ return NULL;\ }\ } /* * Parses one argument into "self" and an optional second argument into * 'var". The second argument is converted into a C long. If there is not a * second argument, "var" is unchanged. Is faster, but not as generic, as * using PyArg_ParseTuple with "|l". It supports either gmpy2.fname(z,l) or * z.fname(l). "self" must be decref'ed. "var" must be a pointer to a long. * "msg" should be an error message that includes the function name and * describes the required arguments. Replaces some uses of SELF_MPZ_ONE_ARG. */ #define PARSE_ONE_MPZ_OPT_CLONG(var, msg) \ if(self && Pympz_Check(self)) {\ if (PyTuple_GET_SIZE(args) == 1) {\ *var = clong_From_Integer(PyTuple_GET_ITEM(args, 0)); \ if(*var == -1 && PyErr_Occurred()) {\ PyErr_SetString(PyExc_TypeError, msg);\ return NULL;\ }\ } else if (PyTuple_GET_SIZE(args) > 1) {\ PyErr_SetString(PyExc_TypeError, msg);\ return NULL;\ }\ Py_INCREF(self);\ } else {\ if (PyTuple_GET_SIZE(args) == 2) {\ *var = clong_From_Integer(PyTuple_GET_ITEM(args, 1)); \ if(*var == -1 && PyErr_Occurred()) {\ PyErr_SetString(PyExc_TypeError, msg);\ return NULL;\ }\ self = (PyObject*)Pympz_From_Integer(PyTuple_GET_ITEM(args, 0));\ } else if (PyTuple_GET_SIZE(args) == 1) {\ self = (PyObject*)Pympz_From_Integer(PyTuple_GET_ITEM(args, 0));\ } else {\ PyErr_SetString(PyExc_TypeError, msg);\ return NULL;\ }\ if(!self) {\ PyErr_SetString(PyExc_TypeError, msg);\ return NULL;\ }\ } /* * Parses one argument into "self" and a required second argument into * 'var". The second argument is converted into a C long. Is faster, but not * as generic, as using PyArg_ParseTuple with "l". It supports either * gmpy2.fname(z,l) or z.fname(l). "self" must be decref'ed. "var" must be a * pointer to a long. "msg" should be an error message that includes the * function name and describes the required arguments. Replaces some uses of * SELF_MPZ_ONE_ARG. */ #define PARSE_ONE_MPZ_REQ_CLONG(var, msg) \ if(self && Pympz_Check(self)) {\ if (PyTuple_GET_SIZE(args) != 1) {\ PyErr_SetString(PyExc_TypeError, msg);\ return NULL;\ } else {\ *var = clong_From_Integer(PyTuple_GET_ITEM(args, 0)); \ if(*var == -1 && PyErr_Occurred()) {\ PyErr_SetString(PyExc_TypeError, msg);\ return NULL;\ }\ }\ Py_INCREF(self);\ } else {\ if (PyTuple_GET_SIZE(args) != 2) {\ PyErr_SetString(PyExc_TypeError, msg);\ return NULL;\ } else {\ *var = clong_From_Integer(PyTuple_GET_ITEM(args, 1)); \ if(*var == -1 && PyErr_Occurred()) {\ PyErr_SetString(PyExc_TypeError, msg);\ return NULL;\ }\ self = (PyObject*)Pympz_From_Integer(PyTuple_GET_ITEM(args, 0));\ }\ if(!self) {\ PyErr_SetString(PyExc_TypeError, msg);\ return NULL;\ }\ } /* * Parses two, and only two, arguments into "self" and "var" and converts * them both to mpz. Is faster, but not as generic, as using PyArg_ParseTuple. * It supports either gmpy2.fname(z,z) or z.fname(z). "self" & "var" must be * decref'ed after use. "msg" should be an error message that includes the * function name and describes the required arguments. Replaces * SELF_MPZ_ONE_ARG_CONVERTED(var). */ #define PARSE_TWO_MPZ(var, msg) \ if(self && Pympz_Check(self)) {\ if (PyTuple_GET_SIZE(args) != 1) {\ PyErr_SetString(PyExc_TypeError, msg);\ return NULL;\ }\ var = (PyObject*)Pympz_From_Integer(PyTuple_GET_ITEM(args, 0));\ if(!var) {\ PyErr_SetString(PyExc_TypeError, msg);\ return NULL;\ }\ Py_INCREF(self);\ } else {\ if (PyTuple_GET_SIZE(args) != 2) {\ PyErr_SetString(PyExc_TypeError, msg);\ return NULL;\ }\ self = (PyObject*)Pympz_From_Integer(PyTuple_GET_ITEM(args, 0));\ var = (PyObject*)Pympz_From_Integer(PyTuple_GET_ITEM(args, 1));\ if(!self || !var) {\ PyErr_SetString(PyExc_TypeError, msg);\ Py_XDECREF((PyObject*)self);\ Py_XDECREF((PyObject*)var);\ return NULL;\ }\ } #define ONE_ARG(nm, fm, var) \ if(!PyArg_ParseTuple(args, fm, var)) { return NULL; } /* Define three different versions of the SELF_NO_ARG macro. Under Python 2.x, self is NULL when a function is called via gmpy.fname(..). But under Python 3.x, self is a module. */ #define SELF_MPQ_NO_ARG \ if(self && Pympq_Check(self)) { \ if(!PyArg_ParseTuple(args, "")) \ return NULL; \ Py_INCREF(self); \ } else { \ if(!PyArg_ParseTuple(args, "O&", Pympq_convert_arg, &self)) \ return NULL; \ } #define SELF_MPF_NO_ARG \ if(self && Pympf_Check(self)) { \ if(!PyArg_ParseTuple(args, "")) \ return NULL; \ Py_INCREF(self); \ } else { \ if(!PyArg_ParseTuple(args, "O&", Pympf_convert_arg, &self)) \ return NULL; \ } #define SELF_MPQ_ONE_ARG(fm, var) \ if(self && Pympq_Check(self)) { \ if(!PyArg_ParseTuple(args, fm, var)) \ return NULL; \ Py_INCREF(self); \ } else { \ if(!PyArg_ParseTuple(args, "O&" fm, Pympq_convert_arg, &self, var)) \ return NULL; \ } #define SELF_MPF_ONE_ARG(fm, var) \ if(self && Pympf_Check(self)) { \ if(!PyArg_ParseTuple(args, fm, var)) \ return NULL; \ Py_INCREF(self); \ } else { \ if(!PyArg_ParseTuple(args, "O&" fm, Pympf_convert_arg, &self, var)) \ return NULL; \ } #define SELF_MPQ_ONE_ARG_CONVERTED(var) \ if(self && Pympq_Check(self)) { \ if(args && !PyArg_ParseTuple(args, "O&", Pympq_convert_arg, var)) \ return NULL; \ Py_INCREF(self); \ } else { \ if(!PyArg_ParseTuple(args, "O&O&", Pympq_convert_arg,&self, \ Pympq_convert_arg,var)) \ return NULL; \ } #define SELF_MPF_ONE_ARG_CONVERTED(var) \ if(self && Pympf_Check(self)) { \ if(args && !PyArg_ParseTuple(args, "O&", Pympf_convert_arg, var)) \ return NULL; \ Py_INCREF(self); \ } else { \ if(!PyArg_ParseTuple(args, "O&O&", Pympf_convert_arg,&self, \ Pympf_convert_arg,var)) \ return NULL; \ } #define SELF_MPF_ONE_ARG_CONVERTED_OPT(var) \ if(self && Pympf_Check(self)) { \ if(args && !PyArg_ParseTuple(args, "|O&", Pympf_convert_arg,var)) \ return NULL; \ Py_INCREF(self); \ } else { \ if(!PyArg_ParseTuple(args, "O&|O&", Pympf_convert_arg,&self, \ Pympf_convert_arg,var)) \ return NULL; \ } #define TWO_ARG_CONVERTED(converter, var1, var2) \ if(!PyArg_ParseTuple(args, "O&O&", converter,var1, converter,var2)) \ return NULL; /* generation of new, uninitialized objects; deallocations */ static PympzObject * Pympz_new(void) { PympzObject * self; if(options.debug) fprintf(stderr, "Entering Pympz_new\n"); if(in_pympzcache) { if(options.debug) fprintf(stderr, "Pympz_new is reusing an old object\n"); self = (pympzcache[--in_pympzcache]); /* Py_INCREF does not set the debugging pointers, so need to use _Py_NewReference instead. */ _Py_NewReference((PyObject*)self); } else { if(options.debug) fprintf(stderr, "Pympz_new is creating a new object\n"); if(!(self = PyObject_New(PympzObject, &Pympz_Type))) return NULL; mpz_inoc(self->z); } return self; } static PympqObject * Pympq_new(void) { PympqObject * self; if(options.debug) fprintf(stderr, "Entering Pympq_new\n"); if(in_pympqcache) { if(options.debug) fprintf(stderr, "Pympq_new is reusing an old object\n"); self = (pympqcache[--in_pympqcache]); /* Py_INCREF does not set the debugging pointers, so need to use _Py_NewReference instead. */ _Py_NewReference((PyObject*)self); } else { if(options.debug) fprintf(stderr, "Pympq_new is creating a new object\n"); if(!(self = PyObject_New(PympqObject, &Pympq_Type))) return NULL; mpq_inoc(self->q); } return self; } static PympfObject * Pympf_new(size_t bits) { PympfObject * self; if(!(self = PyObject_New(PympfObject, &Pympf_Type))) return NULL; if(bits < options.minprec) bits = options.minprec; mpf_init2(self->f, bits); self->rebits = bits; return self; } static void Pympz_dealloc(PympzObject *self) { if(options.debug) fprintf(stderr, "Pympz_dealloc: %p\n", (void *)self); if(in_pympzcachez->_mp_alloc<=options.cache_obsize) { (pympzcache[in_pympzcache++]) = self; } else { mpz_cloc(self->z); PyObject_Del(self); } } /* Pympz_dealloc */ static void Pympq_dealloc(PympqObject *self) { if(options.debug) fprintf(stderr, "Pympq_dealloc: %p\n", (void *)self); if(in_pympqcacheq)->_mp_alloc <= options.cache_obsize && mpq_denref(self->q)->_mp_alloc <= options.cache_obsize) { (pympqcache[in_pympqcache++]) = self; } else { mpq_cloc(self->q); PyObject_Del(self); } } /* Pympq_dealloc */ static void Pympf_dealloc(PympfObject *self) { if(options.debug) fprintf(stderr, "Pympf_dealloc: %p\n", (void *)self); mpf_clear(self->f); PyObject_Del(self); } /* Pympf_dealloc */ /* * Normalize the internal representation of an mpf. GMP allocates 1 * or more additional limbs to store the mantissa of an mpf. The * additional limbs may or may not be used but when used, they can * confuse comparisions. We will normalize all mpf such that the additional * limbs, if used, are set to 0. */ static void Pympf_normalize(PympfObject *i) { Py_ssize_t temp, toclear, size, prec; mp_limb_t bit1, rem, carry; prec = mpf_get_prec(i->f); size = mpf_size(i->f); toclear = size - ((prec / GMP_NUMB_BITS) + 1); if(toclear>0) { bit1 = (i->f->_mp_d[toclear-1] & ((mp_limb_t)1 << (GMP_NUMB_BITS - 1))) ? 1 : 0; rem = (i->f->_mp_d[toclear-1] & (((mp_limb_t)1 << (GMP_NUMB_BITS - 1)) - 1)) ? 1 : 0; carry = bit1 && ((i->f->_mp_d[toclear] & 1) || rem); } else { carry = 0; } if(options.debug) { fprintf(stderr, "prec %ld size %ld toclear %ld carry %ld\n", prec, size, toclear, carry ); } temp = toclear; if(temp>0) { i->f->_mp_d[--temp] = 0; } if(carry) { if(options.debug) { fprintf(stderr, "adding carry bit\n"); } carry = mpn_add_1(i->f->_mp_d + toclear, i->f->_mp_d + toclear, size-toclear, carry); if(carry) { if(options.debug) { fprintf(stderr, "carry bit extended\n"); } i->f->_mp_d[size-1] = 1; i->f->_mp_exp++; } } } /* CONVERSIONS AND COPIES */ static PympzObject * Pympz2Pympz(PympzObject *i) { PympzObject *newob; assert(Pympz_Check(i)); if(!(newob = Pympz_new())) return NULL; mpz_set(newob->z, i->z); return newob; } static PympqObject * Pympq2Pympq(PympqObject *q) { PympqObject *newob; assert(Pympq_Check(q)); if(!(newob = Pympq_new())) return NULL; mpq_set(newob->q, q->q); return newob; } static PympfObject * Pympf2Pympf(PympfObject *f, size_t bits) { PympfObject *newob; assert(Pympf_Check(f)); if(!(newob = Pympf_new(bits))) return NULL; mpf_set(newob->f, f->f); mpf_set_prec(newob->f, bits); newob->rebits = bits; Pympf_normalize(newob); return newob; } #if PY_MAJOR_VERSION < 3 static PympzObject * PyInt2Pympz(PyObject *i) { PympzObject *newob; assert(PyInt_Check(i)); if(!(newob = Pympz_new())) return NULL; mpz_set_si(newob->z, PyInt_AsLong(i)); return newob; } static PympqObject * PyInt2Pympq(PyObject *i) { PympqObject *newob; assert(PyInt_Check(i)); if(!(newob = Pympq_new())) return NULL; mpq_set_si(newob->q, PyInt_AsLong(i), 1); return newob; } static PympfObject * PyInt2Pympf(PyObject *i, size_t bits) { PympfObject *newob; long li; assert(PyInt_Check(i)); li = PyInt_AsLong(i); /* on a 64-bit machine, SIZEOF_LONG*8 > double_mantissa, so to simplify the representation, only use that many bits if we have an integer that won't fit in an int. */ if(!bits) { if ((li > INT_MAX) || (li < (-INT_MAX-1))) { bits = SIZEOF_LONG*8; } else { bits = SIZEOF_INT*8; } } if(!(newob = Pympf_new(bits))) return NULL; mpf_set_si(newob->f, li); Pympf_normalize(newob); return newob; } #endif static PympzObject * PyFloat2Pympz(PyObject *f) { PympzObject *newob; assert(PyFloat_Check(f)); if((newob = Pympz_new())) { double d = PyFloat_AsDouble(f); if (isnan(d)) { PyErr_SetString(PyExc_ValueError, "gmpy does not handle nan"); return NULL; } if (isinf(d)) { PyErr_SetString(PyExc_ValueError, "gmpy does not handle infinity"); return NULL; } if(fabs(d) < 1.0) d = 0.0; mpz_set_d(newob->z, d); } return newob; } /* forward...: */ static PyObject *f2q_internal(PympfObject* self, PympfObject* err, size_t bits, int mayz); static PyObject* Pympf_f2q(PyObject *self, PyObject *args); static PympfObject* anynum2Pympf(PyObject* obj, size_t bits); static PympqObject * PyFloat2Pympq(PyObject *f) { PympfObject *self = Pympf_new(double_mantissa); if(!self) return NULL; assert(PyFloat_Check(f)); { double d = PyFloat_AsDouble(f); if (isnan(d)) { PyErr_SetString(PyExc_ValueError, "gmpy does not handle nan"); return NULL; } if (isinf(d)) { PyErr_SetString(PyExc_ValueError, "gmpy does not handle infinity"); return NULL; } mpf_set_d(self->f, d); } return (PympqObject*)f2q_internal(self, 0, double_mantissa, 0); } /* forward */ static PympfObject *PyStr2Pympf(PyObject *s, long base, size_t bits); static PympfObject * PyFloat2Pympf(PyObject *f, size_t bits) { PympfObject *newob = 0; assert(PyFloat_Check(f)); if(!bits) bits=double_mantissa; if(options.debug) fprintf(stderr, "PyFloat2Pympf(%p,%"PY_FORMAT_SIZE_T"d)\n", (void *)f, bits); if(options.fcoform) { /* 2-step float->mpf conversion process: first, get a * Python string by formatting the Python float; then, * use str2mpf to build the mpf from the string. */ PyObject* tuple=Py_BuildValue("(O)",f); PyObject* s; if(!tuple) return 0; s=Py2or3String_Format(options.fcoform, tuple); Py_DECREF(tuple); if(options.debug) fprintf(stderr,"f2mp(%s,%f->%s)\n", Py2or3String_AsString(options.fcoform), PyFloat_AsDouble(f), s?Py2or3String_AsString(s):""); if(!s) return NULL; newob = PyStr2Pympf(s, 10, bits); if(!newob) { Py_DECREF(s); return NULL; } Py_DECREF(s); } else { /* direct float->mpf conversion, faster but rougher */ if((newob = Pympf_new(bits))) { double d = PyFloat_AsDouble(f); if (isnan(d)) { PyErr_SetString(PyExc_ValueError, "gmpy does not handle nan"); return NULL; } if (isinf(d)) { PyErr_SetString(PyExc_ValueError, "gmpy does not handle infinity"); return NULL; } mpf_set_d(newob->f, d); } } Pympf_normalize(newob); return newob; } static PympfObject * Pympz2Pympf(PyObject * obj, size_t bits) { PympfObject *newob; assert(Pympz_Check(obj)); if(!bits) bits = mpz_sizeinbase(Pympz_AS_MPZ(obj),2)+2; if(!(newob = Pympf_new(bits))) return NULL; mpf_set_z(newob->f, Pympz_AS_MPZ(obj)); Pympf_normalize(newob); return newob; } static PympzObject * Pympf2Pympz(PyObject * obj) { PympzObject *newob; assert(Pympf_Check(obj)); if(!(newob = Pympz_new())) return NULL; mpz_set_f(newob->z, Pympf_AS_MPF(obj)); return newob; } static PympqObject * Pympz2Pympq(PyObject * obj) { PympqObject *newob; assert(Pympz_Check(obj)); if(!(newob = Pympq_new())) return NULL; mpq_set_z(newob->q, Pympz_AS_MPZ(obj)); return newob; } static PympqObject * Pympf2Pympq(PyObject * obj) { return (PympqObject*) Pympf_f2q(obj,0); } static PympfObject * Pympq2Pympf(PyObject * obj, size_t bits) { PympfObject *newob; assert(Pympq_Check(obj)); if(!(newob = Pympf_new(bits))) return NULL; mpf_set_q(newob->f, Pympq_AS_MPQ(obj)); Pympf_normalize(newob); return newob; } static PympzObject * Pympq2Pympz(PyObject * obj) { PympzObject *newob; assert(Pympq_Check(obj)); if(!(newob = Pympz_new())) return NULL; mpz_set_q(newob->z, Pympq_AS_MPQ(obj)); return newob; } /* For fast conversion between PyLong and mpz, we use code located in * mpz_pylong.c. */ static PympzObject * PyLong2Pympz(PyObject * obj) { PympzObject *newob; if(!(newob = Pympz_new())) return NULL; mpz_set_PyLong(Pympz_AS_MPZ(newob), obj); return newob; } /* * long->mpf delegates via long->mpz->mpf to avoid duplicating * the above-seen dependencies; ditto long->mpq */ static PympfObject * PyLong2Pympf(PyObject * obj, size_t bits) { PympfObject *newob; PyObject *intermediate = (PyObject*)PyLong2Pympz(obj); if(!intermediate) return 0; newob = Pympz2Pympf(intermediate, bits); Py_DECREF(intermediate); return newob; } static PympqObject * PyLong2Pympq(PyObject * obj) { PympqObject *newob; PyObject *intermediate = (PyObject*)PyLong2Pympz(obj); if(!intermediate) return 0; newob = Pympz2Pympq(intermediate); Py_DECREF(intermediate); return newob; } /* * mpz conversion from string includes from-binary (base-256 LSB string * of bytes) and 'true' from-string (bases 2 to 62; bases 8 and 16 are * special -- decorations of leading 0/0x are allowed (not required). * * Binary form was previously (0.6) limited to >=0 values; now (0.7) * extended to <0 values, by adding one last sign-byte, 0xFF for <0, * 0x00 for >0 (the latter only if the #bits is exact multiple of 8). */ static PympzObject * PyStr2Pympz(PyObject *s, long base) { PympzObject *newob; unsigned char *cp; Py_ssize_t len; int i; PyObject *ascii_str = NULL; #if PY_MAJOR_VERSION >= 3 assert(PyBytes_Check(s) || PyUnicode_Check(s)); #else assert(PyString_Check(s) || PyUnicode_Check(s)); #endif if(!(newob = Pympz_new())) return NULL; #if PY_MAJOR_VERSION >= 3 if(PyBytes_Check(s)) { len = PyBytes_Size(s); cp = (unsigned char*)PyBytes_AsString(s); } else { ascii_str = PyUnicode_AsASCIIString(s); if(!ascii_str) { PyErr_SetString(PyExc_ValueError, "string contains non-ASCII characters"); Py_DECREF(newob); return NULL; } len = PyBytes_Size(ascii_str); cp = (unsigned char*)PyBytes_AsString(ascii_str); } #else if(PyString_Check(s)) { len = PyString_Size(s); cp = (unsigned char*)PyString_AsString(s); } else { ascii_str = PyUnicode_AsASCIIString(s); if(!ascii_str) { PyErr_SetString(PyExc_ValueError, "string contains non-ASCII characters"); Py_DECREF((PyObject*)newob); return NULL; } len = PyString_Size(ascii_str); cp = (unsigned char*)PyString_AsString(ascii_str); } #endif if(256 == base) { /* Least significant octet first */ int negative = 0; if(cp[len-1] == 0xFF) { negative = 1; --len; } mpz_set_si(newob->z, 0); mpz_import(newob->z, len, -1, sizeof(char), 0, 0, cp); if(negative) mpz_neg(newob->z, newob->z); } else { /* Don't allow NULL characters */ for(i=0; iz, (char*)cp, base)) { PyErr_SetString(PyExc_ValueError, "invalid digits"); Py_DECREF((PyObject*)newob); Py_XDECREF(ascii_str); return NULL; } } Py_XDECREF(ascii_str); return newob; } /* * mpq conversion from string includes from-binary (base-256 LSB string * of bytes) and 'true' from-string (bases 2 to 36; bases 8 and 16 are * special -- decorations of leading 0/0x are allowed (but not required). * For 'true-bases' 2..36 there is a '/' separator between numerator and * denominator (if none, just numerator!); decimal point NOT allowed. * * Added in gmpy 1.02: also support a string of the form '12.34', i.e., * WITH a decimal point and WITHOUT a slash * * Binary-form: 4-byte numerator length (upper bit set if <0), then * numerator (as above for mpz), then denominator (ditto). */ static PympqObject * PyStr2Pympq(PyObject *stringarg, long base) { PympqObject *newob; unsigned char *cp; Py_ssize_t len; int i; PyObject *ascii_str = NULL; #if PY_MAJOR_VERSION >= 3 assert(PyBytes_Check(stringarg) || PyUnicode_Check(stringarg)); #else assert(PyString_Check(stringarg) || PyUnicode_Check(stringarg)); #endif if(!(newob = Pympq_new())) return NULL; #if PY_MAJOR_VERSION >= 3 if(PyBytes_Check(stringarg)) { len = PyBytes_Size(stringarg); cp = (unsigned char*)PyBytes_AsString(stringarg); } else { ascii_str = PyUnicode_AsASCIIString(stringarg); if(!ascii_str) { PyErr_SetString(PyExc_ValueError, "string contains non-ASCII characters"); Py_DECREF(newob); return NULL; } len = PyBytes_Size(ascii_str); cp = (unsigned char*)PyBytes_AsString(ascii_str); } #else if(PyString_Check(stringarg)) { len = PyString_Size(stringarg); cp = (unsigned char*)PyString_AsString(stringarg); } else { ascii_str = PyUnicode_AsASCIIString(stringarg); if(!ascii_str) { PyErr_SetString(PyExc_ValueError, "string contains non-ASCII characters"); Py_DECREF((PyObject*)newob); return NULL; } len = PyString_Size(ascii_str); cp = (unsigned char*)PyString_AsString(ascii_str); } #endif if(256 == base) { /* TODO: better factoring of str2mpz (for speed) */ int topper, isnega, numlen; PyObject *s; PympzObject *numerator, *denominator; if(len < 6) { PyErr_SetString(PyExc_ValueError, "invalid mpq binary (too short)"); Py_DECREF((PyObject*)newob); Py_XDECREF(ascii_str); return 0; } topper = cp[3] & 0x7f; isnega = cp[3] & 0x80; numlen = cp[0]+256*(cp[1]+256*(cp[2]+256*topper)); if(len < (4+numlen+1)) { PyErr_SetString(PyExc_ValueError, "invalid mpq binary (num len)"); Py_DECREF((PyObject*)newob); Py_XDECREF(ascii_str); return 0; } s = Py2or3Bytes_FromStringAndSize((char*)cp+4, numlen); numerator = PyStr2Pympz(s,256); Py_DECREF(s); if (!numerator) { Py_DECREF((PyObject*)newob); Py_XDECREF(ascii_str); return 0; } if(mpz_sgn(numerator->z) < 0) { PyErr_SetString(PyExc_ValueError, "invalid mpq binary (num sgn)"); Py_DECREF((PyObject*)newob); Py_DECREF((PyObject*)numerator); Py_XDECREF(ascii_str); return 0; } if(isnega) mpz_neg(numerator->z, numerator->z); s = Py2or3Bytes_FromStringAndSize((char*)cp+4+numlen, len-4-numlen); denominator = PyStr2Pympz(s,256); Py_DECREF(s); if (!denominator) { Py_DECREF((PyObject*)newob); Py_DECREF((PyObject*)numerator); Py_XDECREF(ascii_str); return 0; } if(mpz_sgn(denominator->z) != 1) { PyErr_SetString(PyExc_ValueError, "invalid mpq binary (den sgn)"); Py_DECREF((PyObject*)newob); Py_DECREF((PyObject*)numerator); Py_DECREF((PyObject*)denominator); Py_XDECREF(ascii_str); return 0; } mpq_set_num(newob->q, numerator->z); mpq_set_den(newob->q, denominator->z); mpq_canonicalize(newob->q); Py_DECREF((PyObject*)numerator); Py_DECREF((PyObject*)denominator); } else { /* Don't allow NULL characters */ for(i=0; iq), (char*)cp, base)) { if(whereslash) *whereslash = '/'; PyErr_SetString(PyExc_ValueError, "invalid digits"); Py_DECREF((PyObject*)newob); Py_XDECREF(ascii_str); return NULL; } if(whereslash) { *whereslash = '/'; if(-1==mpz_set_str(mpq_denref(newob->q), whereslash+1, base)) { PyErr_SetString(PyExc_ValueError, "invalid digits"); Py_DECREF((PyObject*)newob); Py_XDECREF(ascii_str); return NULL; } if(0==mpz_sgn(mpq_denref(newob->q))) { Py_DECREF((PyObject*)newob); Py_XDECREF(ascii_str); PyErr_SetString(PyExc_ZeroDivisionError, "mpq: zero denominator"); return NULL; } mpq_canonicalize(newob->q); } else { mpz_set_ui(mpq_denref (newob->q), 1); } } } Py_XDECREF(ascii_str); return newob; } /* * mpf conversion from string includes from-binary (base-256, format is * explained later) and 'true' from-string (bases 2 to 62), where exponent * if any is denoted by 'e' if base<=10, else by '@', and is always decimal. */ static PympfObject * PyStr2Pympf(PyObject *s, long base, size_t bits) { PympfObject *newob; unsigned char *cp; Py_ssize_t len, precision, i; PyObject *ascii_str = NULL; #if PY_MAJOR_VERSION >= 3 assert(PyBytes_Check(s) || PyUnicode_Check(s)); #else assert(PyString_Check(s) || PyUnicode_Check(s)); #endif #if PY_MAJOR_VERSION >= 3 if(PyBytes_Check(s)) { len = PyBytes_Size(s); cp = (unsigned char*)PyBytes_AsString(s); } else { ascii_str = PyUnicode_AsASCIIString(s); if(!ascii_str) { PyErr_SetString(PyExc_ValueError, "string contains non-ASCII characters"); return NULL; } len = PyBytes_Size(ascii_str); cp = (unsigned char*)PyBytes_AsString(ascii_str); } #else if(PyString_Check(s)) { len = PyString_Size(s); cp = (unsigned char*)PyString_AsString(s); } else { ascii_str = PyUnicode_AsASCIIString(s); if(!ascii_str) { PyErr_SetString(PyExc_ValueError, "string contains non-ASCII characters"); return NULL; } len = PyString_Size(ascii_str); cp = (unsigned char*)PyString_AsString(ascii_str); } #endif if(bits != 0) { precision = bits; } else { /* precision to be defaulted or fetched */ if(base == 256) { /* it may be encoded for fetching */ precision = 8*(len-5); /* default precision */ if((len>=5) && (cp[0]&8)) { /* precision must be fetched */ precision = 0; for(i=4; i>0; --i) { precision = (precision<<8) | cp[i]; } } } else { /* true-string, never encoded, just default it */ precision = double_mantissa; } if(precision<=0) precision=1; } if(!(newob = Pympf_new(precision))) { Py_XDECREF(ascii_str); return NULL; } if(256 == base) { /* * binary format for MP floats: first, a code-byte, then, a LSB * 4-byte unsigned int (exponent magnitude), then the "mantissa" * (actually, "significand", but "mantissa" is the usual term...) * in MSB form. * * The codebyte encodes both the signs, exponent and result, or * also the zeroness of the result (in which case, nothing more). */ mpf_t digit; int codebyte = cp[0]; int resusign = codebyte & 1; int exposign = codebyte & 2; int resuzero = codebyte & 4; int precilen = (codebyte & 8)?4:0; unsigned int expomag = 0; /* mpf zero has a very compact (1-byte) binary encoding!-) */ if(resuzero) { mpf_set_ui(newob->f, 0); return newob; } /* all other numbers are 6+ bytes: codebyte, 4-byte exp, 1+ * bytes for the mantissa; check this string is 6+ bytes */ if(len<6+precilen) { PyErr_SetString(PyExc_ValueError, "string too short to be a gmpy.mpf binary encoding"); Py_DECREF((PyObject*)newob); Py_XDECREF(ascii_str); return NULL; } /* reconstruct exponent */ for(i=4+precilen; i>precilen; --i) { expomag = (expomag<<8) | cp[i]; } /* reconstruct 'mantissa' (significand) */ mpf_set_si(newob->f, 0); mpf_init2(digit, newob->rebits); for(i=5+precilen; if, newob->f, digit); } mpf_clear(digit); /* apply exponent, with its appropriate sign */ if(exposign) mpf_div_2exp(newob->f, newob->f, 8*expomag); else mpf_mul_2exp(newob->f, newob->f, 8*expomag); /* apply significand-sign (sign of the overall number) */ if(resusign) mpf_neg(newob->f, newob->f); } else { /* Don't allow NULL characters */ for(i=0; if, (char*)cp, base)) { PyErr_SetString(PyExc_ValueError, "invalid digits"); Py_DECREF((PyObject*)newob); Py_XDECREF(ascii_str); return NULL; } } Pympf_normalize(newob); Py_XDECREF(ascii_str); return newob; } /* For fast mpz to PyLong conversion, we use code located in mpz_pylong. */ static PyObject * Pympz2PyLong(PympzObject *x) { return mpz_get_PyLong(Pympz_AS_MPZ(x)); } /* * mpf->long delegates via mpf->mpz->long to avoid duplicating * the above-seen thorny dependencies; ditto mpq->long */ static PyObject * Pympf2PyLong(PympfObject *x) { PyObject* result; PympzObject *intermediate = Pympf2Pympz((PyObject*)x); if(!intermediate) return 0; result = Pympz2PyLong(intermediate); Py_DECREF((PyObject*)intermediate); return result; } static PyObject * Pympq2PyLong(PympqObject *x) { PyObject* result; PympzObject *intermediate = Pympq2Pympz((PyObject*)x); if(!intermediate) return 0; result = Pympz2PyLong(intermediate); Py_DECREF((PyObject*)intermediate); return result; } static PyObject * Pympz_To_Integer(PympzObject *x) { #if PY_MAJOR_VERSION >= 3 return Pympz2PyLong(x); #else if(mpz_fits_slong_p(x->z)) return PyInt_FromLong(mpz_get_si(x->z)); else return Pympz2PyLong(x); #endif } /* * mpf->int delegates via mpf->mpz->int for convenience; ditto mpq->int */ #if PY_MAJOR_VERSION < 3 static PyObject * Pympf2PyInt(PympfObject *x) { PyObject* result; PympzObject *intermediate = Pympf2Pympz((PyObject*)x); if(!intermediate) return 0; result = Pympz_To_Integer(intermediate); Py_DECREF((PyObject*)intermediate); return result; } static PyObject * Pympq2PyInt(PympqObject *x) { PyObject* result; PympzObject *intermediate = Pympq2Pympz((PyObject*)x); if(!intermediate) return 0; result = Pympz_To_Integer(intermediate); Py_DECREF((PyObject*)intermediate); return result; } #endif static PyObject * Pympz2PyFloat(PympzObject *x) { double res = mpz_get_d(x->z); return PyFloat_FromDouble(res); } static PyObject * Pympf2PyFloat(PympfObject *x) { double res = mpf_get_d(x->f); return PyFloat_FromDouble(res); } static PyObject * Pympq2PyFloat(PympqObject *x) { double res = mpq_get_d(x->q); return PyFloat_FromDouble(res); } /* * build binary representation of mpz (base-256 little-endian) * Note: design limitation used to forbid binary repr of <0 mpz; * this has now been remedied, but at the price of full compatibility * with files saved in gmpy releases 0.6 and earlier. */ static PyObject * Pympz2binary(PympzObject *x) { size_t size, usize; int negative, needtrail; char *buffer; PyObject *s; assert(Pympz_Check( (PyObject *) x)); if(mpz_sgn(x->z) < 0) { negative = 1; mpz_neg(x->z, x->z); /* Change the sign temporarily! */ } else { negative = 0; } size = mpz_sizeinbase(x->z, 2); needtrail = (size%8)==0; usize = size = (size + 7) / 8; if(negative || needtrail) ++size; TEMP_ALLOC(buffer, size); buffer[0] = 0x00; mpz_export(buffer, NULL, -1, sizeof(char), 0, 0, x->z); if(usize < size) { buffer[usize] = negative?0xff:0x00; } if(negative) { mpz_neg(x->z, x->z); } s = Py2or3Bytes_FromStringAndSize(buffer, size); TEMP_FREE(buffer, size); return s; } /* * build binary representation of mpq (base-256 little-endian * for num, then den; before those, 4 bytes for _length_ of * numerator, which also encode sign as the single top bit). */ static PyObject * Pympq2binary(PympqObject *x) { size_t sizenum, sizeden, size, sizetemp; int negative=0; char *buffer; size_t i; PyObject *s; assert(Pympq_Check( (PyObject *) x)); if(mpq_sgn(x->q) < 0) { negative = 1; mpz_abs(mpq_numref(x->q), mpq_numref(x->q)); } else { negative = 0; } assert(mpz_sgn(mpq_denref(x->q))>0); sizenum = (mpz_sizeinbase(mpq_numref(x->q), 2) + 7) / 8; sizeden = (mpz_sizeinbase(mpq_denref(x->q), 2) + 7) / 8; size = sizenum+sizeden+4; TEMP_ALLOC(buffer, size); sizetemp = sizenum; for(i=0; i<4; i++) { buffer[i] = (char)(sizetemp & 0xff); sizetemp >>= 8; } if(negative) buffer[3] |= 0x80; buffer[4] = 0x00; mpz_export(buffer+4, NULL, -1, sizeof(char), 0, 0, mpq_numref(x->q)); mpz_export(buffer+sizenum+4, NULL, -1, sizeof(char), 0, 0, mpq_denref(x->q)); if(negative) { mpz_neg( mpq_numref(x->q), mpq_numref(x->q)); } s = Py2or3Bytes_FromStringAndSize(buffer, size); TEMP_FREE(buffer, size); return s; } /* * helper functions for mpf->binary conversion * hof: maps a hex-digit character into 0..15 * di256: maps two hex-digits chars into 0..255 */ static int hof(int hedi) { static char table[] = "0123456789abcdef"; char* p = strchr(table, tolower(hedi)); assert(hedi && p); return (int) (p-table); } static char di256(int di1, int di2) { return (char)(hof(di2)+16*hof(di1)); } /* * build binary representation of mpf (see format description above) */ static PyObject * Pympf2binary(PympfObject *x) { size_t size, hexdigs, lprec; char *buffer, *aux; size_t i, j; PyObject *s; int sign, codebyte; mp_exp_t the_exp; long lexp; int lexpodd, extrabyte; assert(Pympf_Check( (PyObject *) x)); /* prepare codebyte */ sign = mpf_sgn(x->f); if(sign==0) { /* 0 -> single codebyte with 'zerovalue' bit set */ #if PY_MAJOR_VERSION >= 3 return Py_BuildValue("y", "\004"); #else return Py_BuildValue("s", "\004"); #endif /* codebyte = 0; */ } else if(sign<0) { codebyte = 1; mpf_neg(x->f, x->f); /* note we TEMPORARILY change sign!!! */ } else { codebyte = 0; } /* get buffer of base-16 digits */ buffer = mpf_get_str(0, &the_exp, 16, 0, x->f); /* no need to worry about null-buffer as x->f==0.0 was * already handled above (see first test on 'sign'). */ /* restore correct sign to x->f if it was changed! */ if(codebyte) { mpf_neg(x->f, x->f); } hexdigs = strlen(buffer); /* adjust exponent, & possibly set codebyte's expo-sign bit. * note the_exp is base-16 exp, while we need to have it in * base-256 -- so it's basically halved (but, with care...!). */ if(the_exp<0) { codebyte |= 2; the_exp = -the_exp; } lexp = the_exp; lexpodd = lexp&1; lexp = lexp/2 + lexpodd; if(lexpodd && (codebyte&2)) --lexp; /* remember we also store precision explicitly */ codebyte |= 8; /* allocate suitably-sized, uninitialized Python string */ size = (hexdigs+1)/2; /* allocate an extra byte if lexpodd and hexdigs is even */ extrabyte = lexpodd & ~hexdigs; s = Py2or3Bytes_FromStringAndSize(0, 1+4+size+4+extrabyte); if(!s) return 0; /* set the data to the new Python string's buffer */ aux = Py2or3Bytes_AS_STRING(s); /* codebyte first */ aux[0] = (char)codebyte; /* then precision */ lprec = x->rebits; for(i=0; i<4; ++i) { aux[i+1] = (char)(lprec & 0xFF); lprec >>= 8; } /* then exponent */ for(i=0; i<4; ++i) { aux[4+i+1] = (char)(lexp & 0xFF); lexp >>= 8; } /* then mantissa, grouping 2 hex digits per base-256 digits; * with some care for the first & last ones... */ j=0; i=0; if(lexpodd) { aux[i+9] = di256('0',buffer[0]); j=1; i=1; } for(; i 62))) { PyErr_SetString(PyExc_ValueError, "base must be either 0 or in the interval 2 ... 62"); return NULL; } /* Allocate extra space for: * * minus sign and trailing NULL byte (2) * 'gmpy.mpz()' tag (10) * '0x' prefix (2) * 'L' suffix (1) * ----- * 15 */ size = mpz_sizeinbase(z, base) + 16; TEMP_ALLOC(buffer, size); mpz_inoc(temp); if(mpz_sgn(z) < 0) { minus = 1; mpz_neg(temp, z); } else { minus = 0; mpz_set(temp, z); } p = buffer; if(with_tag) { strcpy(p, ztag+options.tagoff); p += strlen(p); } if(minus) *(p++) = '-'; if (!no_prefix) { if(base == 8) *(p++) = '0'; else if(base == 16) { *(p++) = '0'; *(p++) = 'x'; } } mpz_get_str(p, base, temp); /* Doesn't return number of characters */ p = buffer + strlen(buffer); /* Address of NULL byte */ #if PY_MAJOR_VERSION < 3 if(with_tag && !no_prefix && !mpz_fits_slong_p(temp)) *(p++) = 'L'; #endif if(with_tag) *(p++) = ')'; s = Py2or3Bytes_FromStringAndSize(buffer, p - buffer); mpz_cloc(temp); TEMP_FREE(buffer, size); return s; } static PyObject * Pympz_ascii(PympzObject *self, int base, int with_tag, int no_prefix) { #if PY_MAJOR_VERSION >= 3 PyObject *s, *t; assert(Pympz_Check( (PyObject *) self)); t = mpz_ascii(self->z, base, with_tag, no_prefix); if(!t) return NULL; s = PyUnicode_FromString(PyBytes_AS_STRING(t)); Py_DECREF(t); return s; #else assert(Pympz_Check( (PyObject *) self)); return mpz_ascii(self->z, base, with_tag, no_prefix); #endif } static char* qtag = "gmpy.mpq("; static int qden_1(mpq_t q) { return 0==mpz_cmp_ui(mpq_denref(q),1); } static PyObject * Pympq_ascii(PympqObject *self, int base, int with_tag) { PyObject *result = 0; PyObject *numstr = mpz_ascii(mpq_numref(self->q), base, 0, 0); PyObject *denstr = 0; PyObject *temp = 0; if(!numstr) return 0; if(with_tag || !qden_1(self->q)) { denstr = mpz_ascii(mpq_denref(self->q), base, 0, 0); if(!denstr) { Py_DECREF(numstr); return 0; } } if(with_tag) { result = Py2or3Bytes_FromString(qtag+options.tagoff); if(result) Py2or3Bytes_ConcatAndDel(&result, numstr); if(!result) { Py_XDECREF(denstr); return 0; } #if PY_MAJOR_VERSION < 3 if(!mpz_fits_slong_p(mpq_numref(self->q))) { temp = Py2or3Bytes_FromString("L"); Py2or3Bytes_ConcatAndDel(&result, temp); if(!result) { Py_XDECREF(denstr); return 0; } } #endif } else { result = numstr; numstr = 0; } if(denstr) { char* separator = with_tag?",":"/"; temp = Py2or3Bytes_FromString(separator); Py2or3Bytes_ConcatAndDel(&result, temp); if(!result) { Py_DECREF(denstr); return 0; } Py2or3Bytes_ConcatAndDel(&result, denstr); #if PY_MAJOR_VERSION < 3 if(with_tag && !mpz_fits_slong_p(mpq_denref(self->q))) { temp = Py2or3Bytes_FromString("L"); Py2or3Bytes_ConcatAndDel(&result, temp); if(!result) { return 0; } } #endif } if(with_tag && result) { temp = Py2or3Bytes_FromString(")"); Py2or3Bytes_ConcatAndDel(&result, temp); } #if PY_MAJOR_VERSION >= 3 temp = PyUnicode_FromString(PyBytes_AS_STRING(result)); Py_DECREF(result); return temp; #else return result; #endif } #define OP_TAG 1 #define OP_RAW 2 static char ftag[]="gmpy.mpf('"; /* * format mpf into any base (2 to 62), optionally with * a "gmpy.mpf('...')" tag around it so it can be recovered * through a Python eval of the resulting string. * Note: tag can be just mpf() if options.tagoff=5 * digits: number of digits to ask GMP for (0=all of * them) -- fewer will be given, if fewer significant * minexfi: format as mantissa-exponent if expmaxexfi * note that, e.g., minexfi=0, maxexfi=-1, means * "always format as mantissa-exponent". If not * mantissa-exponent, the number will be formatted * as "fixed point" (FP). Note the decimal point * is _always_ explicitly inserted by this function * (except when bit OP_RAW is set in optionflags). * optionflags: bitmap of option-values; currently: * OP_TAG (1): add the gmpy.mpf('...') tag * OP_RAW (2): ignore minexfi/maxexfi/OP_TAG * and return a 3-element tuple digits/exponent/rprec * (as GMP gives them) for Python formatting; * 'digits' may include a '-' sign, but no decimal * point, nor tag, nor any exponent-indicator. * other bits are currently ignored */ static PyObject * Pympf_ascii(PympfObject *self, int base, int digits, int minexfi, int maxexfi, int optionflags) { PyObject *res; #if PY_MAJOR_VERSION >= 3 PyObject *temp; #endif char *buffer; mp_exp_t the_exp; /* check arguments are valid */ assert(Pympf_Check((PyObject*)self)); if(! ( (base==0) || ((base >= 2) && (base <= 62)))) { PyErr_SetString(PyExc_ValueError, "base must be either 0 or in the interval 2 ... 62"); return NULL; } if(digits < 0) { PyErr_SetString(PyExc_ValueError, "digits must be >= 0"); return NULL; } /* obtain digits-string and exponent */ buffer = mpf_get_str(0, &the_exp, base, digits, self->f); if(!*buffer) { /* need to use malloc here for uniformity with mpf_get_str */ free(buffer); buffer = malloc(2); strcpy(buffer, "0"); the_exp = 1; } if(optionflags & OP_RAW) { res = Py_BuildValue("(sii)", buffer, the_exp, self->rebits); free(buffer); return res; } else { /* insert formatting elements (decimal-point, leading or * trailing 0's, other indication of exponent...) */ size_t buflen = strlen(buffer); /* account for the decimal point that is always inserted */ size_t size = buflen+1; char expobuf[24]; char auprebuf[24]; int isfp=1; /* flag: fixed-point format (FP)? */ int isnegative=0; if(buffer[0]==0x2d) isnegative=1; /* compute size of needed Python string */ if(optionflags & OP_TAG) { size += strlen(ftag+options.tagoff) + 2; if(self->rebits != double_mantissa) { sprintf(auprebuf,",%"PY_FORMAT_SIZE_T"d",self->rebits); size += strlen(auprebuf); } } if(the_expmaxexfi) { /* exponential format */ /* add exponent-length + 1 for '@' or 'e' marker */ sprintf(expobuf,"%ld",the_exp-1); size += strlen(expobuf) + 1; isfp = 0; } else { /* 'fixed-point' format */ /* add number of leading or trailing 0's */ if(the_exp <= 0) { /* add leading 0's */ size += abs(the_exp)+1; } else { /* add trailing 0's if needed */ if(the_exp >= (buflen-isnegative)) size += (the_exp-(buflen-isnegative))+1; } } /* allocate the string itself (uninitialized, as yet) */ res = Py2or3Bytes_FromStringAndSize(0, size); { /* proceed with building the string-buffer value */ char* pd = Py2or3Bytes_AS_STRING(res); char* ps = buffer; /* insert leading tag if requested */ if(optionflags & OP_TAG) { char* pt = ftag+options.tagoff; while(*pt) *pd++ = *pt++; } /* copy sign if it's there */ if(*ps=='-') { *pd++ = *ps++; } /* insert a leading-0 if needed for non-positive-exp FP, * else just copy the leading digit (goes before '.') */ if(isfp && the_exp<=0) *pd++ = '0'; else if(*ps) *pd++ = *ps++; else *pd++ = '0'; /* insert what else goes before '.' for FP */ if(isfp && the_exp>1) { /* number of digits-to-copy before the '.' */ int dtc = the_exp-1; /* copy requested # of digits as long as there * are still digits to copy in the buffer */ while(dtc && *ps) { *pd++ = *ps++; --dtc; } /* insert trailing 0's before the '.' if * needed to make up the total # digits * that go before the '.' in FP/large exp */ while(dtc>0) { *pd++ = '0'; --dtc; } } /* the decimal-point is _always_ explicitly there */ *pd++ = '.'; /* as is at least 1 trailing-digit after it, if FP, * so put a 0 if no more digits to copy */ if(isfp && !*ps) *pd++ = '0'; /* in FP with negative exp, we have more leading 0's * after the decimal-point before copying the digits * from the buffer */ if(isfp && the_exp<0) { int dtc = abs(the_exp); while(dtc>0) { *pd++ = '0'; --dtc; } } /* copy all remaining digits from buffer, if any */ while(*ps) *pd++ = *ps++; /* insert marker-and-exponent if _not_ FP */ if(!isfp) { char* pe = expobuf; *pd++ = (base<=10)?'e':'@'; while(*pe) *pd++ = *pe++; } /* insert trailing-part of the tag if needed */ if(optionflags & OP_TAG) { char* pe = auprebuf; *pd++ = '\''; if(self->rebits != double_mantissa) while(*pe) *pd++ = *pe++; *pd++ = ')'; } } free(buffer); #if PY_MAJOR_VERSION >= 3 temp = PyUnicode_FromString(PyBytes_AS_STRING(res)); Py_DECREF(res); return temp; #else return res; #endif } } /* Classify an object as a type of number. If an object is recognized as a * number, it must be properly converted by the routines below. */ static int isNumber(PyObject* obj) { if(options.debug) fprintf(stderr, "isNumber: object type is %s\n", Py_TYPE(obj)->tp_name); if(Pympz_Check(obj)) { return 1; } else if(PyLong_Check(obj)) { return 1; #if PY_MAJOR_VERSION == 2 } else if(PyInt_Check(obj)) { return 1; #endif } else if(Pympq_Check(obj)) { return 1; } else if(Pympf_Check(obj)) { return 1; } else if(PyFloat_Check(obj)) { return 1; } else if(!strcmp(Py_TYPE(obj)->tp_name, "Decimal")) { return 1; } else if(!strcmp(Py_TYPE(obj)->tp_name, "decimal.Decimal")) { return 1; } else if(!strcmp(Py_TYPE(obj)->tp_name, "Fraction")) { return 1; } return 0; } static int isRational(PyObject* obj) { if(options.debug) fprintf(stderr, "isRational: object type is %s\n", Py_TYPE(obj)->tp_name); if(Pympz_Check(obj)) { return 1; } else if(PyLong_Check(obj)) { return 1; #if PY_MAJOR_VERSION == 2 } else if(PyInt_Check(obj)) { return 1; #endif } else if(Pympq_Check(obj)) { return 1; } else if(!strcmp(Py_TYPE(obj)->tp_name, "Fraction")) { return 1; } return 0; } static int isInteger(PyObject* obj) { if(options.debug) fprintf(stderr, "isInteger: object type is %s\n", Py_TYPE(obj)->tp_name); if(Pympz_Check(obj)) { return 1; } else if(PyLong_Check(obj)) { return 1; #if PY_MAJOR_VERSION == 2 } else if(PyInt_Check(obj)) { return 1; #endif } return 0; } /* Number conversion routines * * The routines anynum2mpX will attempt to convert any number-like object into * into a gmpy object. These routines are intended for construction of mpXs. * The accepted number-like objects are: * 1) int (Python 2.x) * 2) long (Python 2.x and 3.x) * 3) float * 4) Decimal * 5) Fraction * 6) other gmpy objects * * The routine Pympz_From_Integer will only convert integer-like objects into to a * gmpy mpz. The accepted integer-like objects are: * 1) int * 2) long * 2) mpz * * The routine anyrational2Pympq will convert an integer- and rational-like * object into a gmpy mpq. The accepted objects are: * 1) int * 2) long * 3) Fraction * 4) mpz * 5) mpq */ static PympqObject* anynum2Pympq(PyObject* obj) { PympqObject* newob = 0; if(Pympq_Check(obj)) { Py_INCREF(obj); newob = (PympqObject *) obj; } else if(Pympz_Check(obj)) { newob = Pympz2Pympq(obj); #if PY_MAJOR_VERSION == 2 } else if(PyInt_Check(obj)) { newob = PyInt2Pympq(obj); #endif } else if(Pympf_Check(obj)) { newob = Pympf2Pympq(obj); } else if(PyFloat_Check(obj)) { newob = PyFloat2Pympq(obj); } else if(PyLong_Check(obj)) { newob = PyLong2Pympq(obj); } else if(!strcmp(Py_TYPE(obj)->tp_name, "Decimal")) { PyObject *s = PyObject_Str(obj); if(s) { newob = PyStr2Pympq(s, 10); Py_DECREF(s); } } else if(!strcmp(Py_TYPE(obj)->tp_name, "decimal.Decimal")) { PyObject *s = PyObject_Str(obj); if(s) { newob = PyStr2Pympq(s, 10); Py_DECREF(s); } } else if(!strcmp(Py_TYPE(obj)->tp_name, "Fraction")) { PyObject *s = PyObject_Str(obj); if(s) { newob = PyStr2Pympq(s, 10); Py_DECREF(s); } } if(options.debug) fprintf(stderr,"anynum2Pympq(%p)->%p\n", (void *)obj, (void *)newob); return newob; } /* Convert an integer or mpz to mpq. */ static PympqObject* anyrational2Pympq(PyObject* obj) { PympqObject* newob = 0; if(Pympq_Check(obj)) { Py_INCREF(obj); newob = (PympqObject *) obj; } else if(Pympz_Check(obj)) { newob = Pympz2Pympq(obj); #if PY_MAJOR_VERSION == 2 } else if(PyInt_Check(obj)) { newob = PyInt2Pympq(obj); #endif } else if(PyLong_Check(obj)) { newob = PyLong2Pympq(obj); } else if(!strcmp(Py_TYPE(obj)->tp_name, "Fraction")) { PyObject *s = PyObject_Str(obj); if(s) { newob = PyStr2Pympq(s, 10); Py_DECREF(s); } } if(options.debug) fprintf(stderr,"anyrational2Pympq(%p)->%p\n", (void *)obj, (void *)newob); return newob; } static PympzObject* anynum2Pympz(PyObject* obj) { PympzObject* newob = 0; PympqObject* temp = 0; if(Pympz_Check(obj)) { Py_INCREF(obj); newob = (PympzObject *) obj; #if PY_MAJOR_VERSION == 2 } else if(PyInt_Check(obj)) { newob = PyInt2Pympz(obj); #endif } else if(PyLong_Check(obj)) { newob = PyLong2Pympz(obj); } else if(Pympq_Check(obj)) { newob = Pympq2Pympz(obj); } else if(Pympf_Check(obj)) { newob = Pympf2Pympz(obj); } else if(PyFloat_Check(obj)) { newob = PyFloat2Pympz(obj); } else if(PyNumber_Check(obj) && !strcmp(Py_TYPE(obj)->tp_name, "Decimal")) { PyObject *s = PyNumber_Long(obj); if(s) { newob = PyLong2Pympz(s); Py_DECREF(s); } } else if(PyNumber_Check(obj) && !strcmp(Py_TYPE(obj)->tp_name, "decimal.Decimal")) { PyObject *s = PyNumber_Long(obj); if(s) { newob = PyLong2Pympz(s); Py_DECREF(s); } } else if(PyNumber_Check(obj) && !strcmp(Py_TYPE(obj)->tp_name, "Fraction")) { PyObject *s = PyObject_Str(obj); if(s) { temp = PyStr2Pympq(s, 10); newob = Pympq2Pympz((PyObject *)temp); Py_DECREF(s); Py_DECREF((PyObject*)temp); } } if(options.debug) fprintf(stderr,"anynum2Pympz(%p)->%p\n", (void *)obj, (void *)newob); return newob; } /* * Convert an Integer-like object (as determined by isInteger) to * a Pympz. Returns NULL and raises a TypeError if obj is not an * Integer-like object. */ static PympzObject* Pympz_From_Integer(PyObject* obj) { PympzObject* newob = 0; if(Pympz_Check(obj)) { Py_INCREF(obj); newob = (PympzObject*) obj; #if PY_MAJOR_VERSION == 2 } else if(PyInt_Check(obj)) { newob = PyInt2Pympz(obj); #endif } else if(PyLong_Check(obj)) { newob = PyLong2Pympz(obj); } if(options.debug) fprintf(stderr,"Pympz_From_Integer(%p)->%p\n", (void *)obj, (void *)newob); if(!newob) { PyErr_SetString(PyExc_TypeError, "conversion error in Pympz_From_Integer"); } return newob; } /* * Convert an Integer-like object (as determined by isInteger) to * a C long. Returns -1 and raises OverflowError if the the number is * too large. Returns -1 and raises TypeError if obj was not an * Integer-like object. */ static long clong_From_Integer(PyObject *obj) { if(PyLong_Check(obj)) { return PyLong_AsLong(obj); #if PY_MAJOR_VERSION == 2 } else if(PyInt_Check(obj)) { return PyInt_AS_LONG(obj); #endif } else if(Pympz_Check(obj)) { if(mpz_fits_slong_p(Pympz_AS_MPZ(obj))) { return mpz_get_si(Pympz_AS_MPZ(obj)); } } PyErr_SetString(PyExc_TypeError, "conversion error in clong_From_Integer"); return -1; } static PympfObject* anynum2Pympf(PyObject* obj, size_t bits) { PympfObject* newob = 0; PympqObject* temp = 0; if(Pympf_Check(obj)) { newob = (PympfObject *) obj; if(!bits || newob->rebits==bits) { Py_INCREF(obj); } else { newob = Pympf2Pympf(newob, bits); } } else if(PyFloat_Check(obj)) { newob = PyFloat2Pympf(obj, bits); #if PY_MAJOR_VERSION == 2 } else if(PyInt_Check(obj)) { newob = PyInt2Pympf(obj, bits); #endif } else if(Pympq_Check(obj)) { newob = Pympq2Pympf(obj, bits); } else if(Pympz_Check(obj)) { newob = Pympz2Pympf(obj, bits); } else if(PyLong_Check(obj)) { newob = PyLong2Pympf(obj, bits); } else if(!strcmp(Py_TYPE(obj)->tp_name, "Decimal")) { PyObject *s = PyObject_Str(obj); if(s) { newob = PyStr2Pympf(s, 10, bits); if(!newob) { Py_DECREF(s); return NULL; } Py_DECREF(s); } } else if(!strcmp(Py_TYPE(obj)->tp_name, "decimal.Decimal")) { PyObject *s = PyObject_Str(obj); if(s) { newob = PyStr2Pympf(s, 10, bits); if(!newob) { Py_DECREF(s); return NULL; } Py_DECREF(s); } } else if(!strcmp(Py_TYPE(obj)->tp_name, "Fraction")) { PyObject *s = PyObject_Str(obj); if(s) { temp = PyStr2Pympq(s, 10); newob = Pympq2Pympf((PyObject *)temp, bits); Py_DECREF(s); Py_DECREF((PyObject*)temp); } } if(options.debug) fprintf(stderr, "anynum2Pympf(%p,%"PY_FORMAT_SIZE_T"d)->%p (%"PY_FORMAT_SIZE_T"d)\n", (void *)obj, bits, (void *)newob, newob != 0 ? newob->rebits : -1); return newob; } /* * coerce any number to a mpz */ int Pympz_convert_arg(PyObject *arg, PyObject **ptr) { PympzObject* newob = Pympz_From_Integer(arg); if(options.debug) fprintf(stderr, "mpz_conv_arg(%p)->%p\n", (void *)arg, (void *)newob); if(newob) { *ptr = (PyObject*)newob; return 1; } else { PyErr_SetString(PyExc_TypeError, "argument can not be converted to mpz"); return 0; } } /* * coerce any number to a mpq */ int Pympq_convert_arg(PyObject *arg, PyObject **ptr) { PympqObject* newob = anyrational2Pympq(arg); if(options.debug) fprintf(stderr, "mpq_conv_arg(%p)->%p\n", (void *)arg, (void *)newob); if(newob) { *ptr = (PyObject*)newob; return 1; } else { if(!PyErr_Occurred()) { PyErr_SetString(PyExc_TypeError, "argument can not be converted to mpq"); } return 0; } } /* * coerce any number to a mpf */ int Pympf_convert_arg(PyObject *arg, PyObject **ptr) { PympfObject* newob = anynum2Pympf(arg,0); if(options.debug) fprintf(stderr, "mpf_conv_arg(%p)->%p\n", (void *)arg, (void *)newob); if(newob) { *ptr = (PyObject*)newob; return 1; } else { PyErr_SetString(PyExc_TypeError, "argument can not be converted to mpf"); return 0; } } /* str and repr implementations for mpz */ static PyObject * Pympz2str(PympzObject *self) { /* base-10, no tag */ return Pympz_ascii(self, 10, 0, 0); } static PyObject * Pympz2repr(PympzObject *self) { /* base-10, with tag */ return Pympz_ascii(self, 10, 1, 0); } /* str and repr implementations for mpq */ static PyObject * Pympq2str(PympqObject *self) { /* base-10, no tag */ return Pympq_ascii(self, 10, 0); } static PyObject * Pympq2repr(PympqObject *self) { /* base-10, with tag */ return Pympq_ascii(self, 10, 1); } /* str and repr implementations for mpz */ static PyObject * Pympf2str(PympfObject *self) { /* base-10, FP for exp -2 to 8, no tag */ return Pympf_ascii(self, 10, 0, -2, 8, 0); } static PyObject * Pympf2repr(PympfObject *self) { /* base-10, always mantissa+exp, with tag */ return Pympf_ascii(self, 10, 0, 0, -1, OP_TAG); } /* * The following functions are located in gmpy_misc.c: * * Pygmpy_get_license(PyObject *self, PyObject *args) * Pygmpy_get_version(PyObject *self, PyObject *args) * Pygmpy_get_cvsid(PyObject *self, PyObject *args) * Pygmpy_get_gmp_version(PyObject *self, PyObject *args) * Pygmpy_get_mpir_version(PyObject *self, PyObject *args) * Pygmpy_get_gmp_limbsize(PyObject *self, PyObject *args) * Pygmpy_get_zcache(PyObject *self, PyObject *args) * Pygmpy_get_qcache(PyObject *self, PyObject *args) * Pygmpy_get_fcache(PyObject *self, PyObject *args) * Pygmpy_set_zcache(PyObject *self, PyObject *args) * Pygmpy_set_qcache(PyObject *self, PyObject *args) * Pygmpy_set_fcache(PyObject *self, PyObject *args) * Pygmpy_set_debug(PyObject *self, PyObject *args) * Pygmpy_set_tagoff(PyObject *self, PyObject *args) * Pygmpy_set_minprec(PyObject *self, PyObject *args) * Pygmpy_set_fcoform(PyObject *self, PyObject *args) * */ #include "gmpy_misc.c" static PyObject * Pympz_copy(PyObject *self, PyObject *args) { PyObject* temp; if(self && Pympz_Check(self)) { if(PyTuple_GET_SIZE(args) != 0) { PyErr_SetString(PyExc_TypeError, "_copy() takes exactly 1 argument"); return NULL; } return (PyObject*)Pympz2Pympz((PympzObject*)self); } else { if(PyTuple_GET_SIZE(args) != 1){ PyErr_SetString(PyExc_TypeError, "_copy() takes exactly 1 argument"); return NULL; } temp = PyTuple_GET_ITEM(args, 0); if(Pympz_Check(temp)) { return (PyObject*)Pympz2Pympz((PympzObject*)temp); } else { PyErr_SetString(PyExc_TypeError, "unsupported operand type for _copy(): mpz required"); return NULL; } } } /* copy mpf object */ static PyObject * Pympf_copy(PyObject *self, PyObject *args) { PyObject *s; size_t bits=0; SELF_MPF_ONE_ARG("|n",&bits); assert(Pympf_Check(self)); if(!bits) bits = ((PympfObject*)self)->rebits; s = (PyObject*)Pympf2Pympf((PympfObject*)self, bits); Py_DECREF(self); return s; } /* copy mpq object */ static PyObject * Pympq_copy(PyObject *self, PyObject *args) { PyObject* temp; if(self && Pympq_Check(self)) { if(PyTuple_GET_SIZE(args) != 0) { PyErr_SetString(PyExc_TypeError, "function takes exactly 1 argument"); return NULL; } return (PyObject*)Pympq2Pympq((PympqObject*)self); } else { if(PyTuple_GET_SIZE(args) != 1){ PyErr_SetString(PyExc_TypeError, "function takes exactly 1 argument"); return NULL; } temp = PyTuple_GET_ITEM(args, 0); if(Pympq_Check(temp)) { return (PyObject*)Pympq2Pympq((PympqObject*)temp); } else { PyErr_SetString(PyExc_TypeError, "unsupported operand type for _qcopy(): mpq required"); return NULL; } } } /* produce portable binary form for mpz object */ static char doc_binarym[]="\ x.binary(): returns a Python string that is a portable binary\n\ representation of x (the string can later be passed to the mpz\n\ constructor function to obtain an exact copy of x's value).\n\ "; static char doc_binaryg[]="\ binary(x): returns a Python string that is a portable binary\n\ representation of x (the string can later be passed to the mpz\n\ constructor function to obtain an exact copy of x's value).\n\ x must be an mpz, or else gets coerced to one.\n\ "; static PyObject * Pympz_binary(PyObject *self, PyObject *args) { PyObject* result; PympzObject* temp; if(self && Pympz_Check(self)) { if(PyTuple_GET_SIZE(args) != 0) { PyErr_SetString(PyExc_TypeError, "function takes exactly 1 argument"); return NULL; } return Pympz2binary((PympzObject*)self); } else { if(PyTuple_GET_SIZE(args) != 1){ PyErr_SetString(PyExc_TypeError, "function takes exactly 1 argument"); return NULL; } temp = Pympz_From_Integer(PyTuple_GET_ITEM(args, 0)); if(!temp) { PyErr_SetString(PyExc_TypeError, "argument is not an integer"); return NULL; } else { result = Pympz2binary((PympzObject*)temp); Py_DECREF((PyObject*)temp); return result; } } } /* produce portable binary form for mpq object */ static char doc_qbinarym[]="\ x.binary(): returns a Python string that is a portable binary\n\ representation of x (the string can later be passed to the mpq\n\ constructor function to obtain an exact copy of x's value).\n\ "; static char doc_qbinaryg[]="\ qbinary(x): returns a Python string that is a portable binary\n\ representation of x (the string can later be passed to the mpq\n\ constructor function to obtain an exact copy of x's value).\n\ x must be an mpq, or else gets coerced to one.\n\ "; static PyObject * Pympq_binary(PyObject *self, PyObject *args) { PyObject *s; SELF_MPQ_NO_ARG; assert(Pympq_Check(self)); s = Pympq2binary((PympqObject*)self); Py_DECREF(self); return s; } /* produce portable binary form for mpf object */ static char doc_fbinarym[]="\ x.binary(): returns a Python string that is a portable binary\n\ representation of x (the string can later be passed to the mpf\n\ constructor function to obtain an exact copy of x's value).\n\ "; static char doc_fbinaryg[]="\ fbinary(f): returns a Python string that is a portable binary\n\ representation of x, which is an mpf or else gets coerced to one.\n\ The string can later be passed to the mpf constructor function\n\ to obtain an exact copy of x's mpf value.\n\ "; static PyObject * Pympf_binary(PyObject *self, PyObject *args) { PyObject *s; SELF_MPF_NO_ARG; assert(Pympf_Check(self)); s = Pympf2binary((PympfObject*)self); Py_DECREF(self); return s; } /* produce digits for an mpz in requested base, default 10 */ static char doc_digitsm[]="\ x.digits([base]): returns Python string representing x in the\n\ given base (2 to 62, default 10 if omitted or 0); leading '-'\n\ is present if x<0, but no leading '+' if x>=0.\n\ "; static char doc_digitsg[]="\ digits(x[,base]): returns Python string representing x in the\n\ given base (2 to 62, default 10 if omitted or 0); leading '-'\n\ present if x<0, but no leading '+' if x>=0. x must be an mpz,\n\ or else gets coerced into one.\n\ "; static PyObject * Pympz_digits(PyObject *self, PyObject *args) { int base = 10; PyObject *s; PARSE_ONE_MPZ_OPT_CLONG(&base, "digits() expects 'mpz',['int'] arguments"); assert(Pympz_Check(self)); s = Pympz_ascii((PympzObject*)self, base, 0, 1); Py_DECREF(self); return s; } /* return number-of-digits for an mpz in requested base, default 10 */ static char doc_numdigitsm[]="\ x.numdigits([base]): returns length of string representing x in\n\ the given base (2 to 62, default 10 if omitted or 0); the value\n\ returned may sometimes be 1 more than necessary; no provision\n\ for any 'sign' character, nor leading '0' or '0x' decoration,\n\ is made in the returned length.\n\ "; static char doc_numdigitsg[]="\ numdigits(x[,base]): returns length of string representing x in\n\ the given base (2 to 62, default 10 if omitted or 0); the value\n\ returned may sometimes be 1 more than necessary; no provision\n\ for any 'sign' character, nor leading '0' or '0x' decoration,\n\ is made in the returned length. x must be an mpz, or else gets\n\ coerced into one.\n\ "; static PyObject * Pympz_numdigits(PyObject *self, PyObject *args) { int base = 10; PyObject *s; PARSE_ONE_MPZ_OPT_CLONG(&base, "numdigits expects 'mpz',[base] arguments"); assert(Pympz_Check(self)); if(base==0) base=10; if((base < 2) || (base > 62)) { PyErr_SetString(PyExc_ValueError, "base must be either 0 or in the interval 2 ... 62"); Py_DECREF(self); return NULL; } s = Py_BuildValue("l", (long) mpz_sizeinbase(Pympz_AS_MPZ(self), base)); Py_DECREF(self); return s; } static char doc_bit_lengthm[]="\ x.bit_length(): returns length of string representing x in base 2\n\ "; static char doc_bit_lengthg[]="\ bit_length(x): returns length of string representing x in base 2\n\ "; static PyObject * Pympz_bit_length(PyObject *self, PyObject *args) { long i = 0; PympzObject* newob; if(self && Pympz_Check(self)) { if(PyTuple_GET_SIZE(args) != 0) { PyErr_SetString(PyExc_TypeError, "bit_length() takes exactly 1 argument"); return NULL; } assert(Pympz_Check(self)); if ((i=mpz_sizeinbase(Pympz_AS_MPZ(self), 2))==1) return Py2or3Int_FromLong((long) mpz_size(Pympz_AS_MPZ(self))); else return Py2or3Int_FromLong(i); } else { if(PyTuple_GET_SIZE(args) != 1){ PyErr_SetString(PyExc_TypeError, "bit_length() takes exactly 1 argument"); return NULL; } newob = Pympz_From_Integer(PyTuple_GET_ITEM(args, 0)); if(newob) { assert(Pympz_Check(newob)); if (mpz_size(Pympz_AS_MPZ(newob))) i = (long) mpz_sizeinbase(Pympz_AS_MPZ(newob), 2); Py_DECREF((PyObject*)newob); return Py2or3Int_FromLong(i); } else { PyErr_SetString(PyExc_TypeError, "unsupported operand type for bit_length: integer required"); return NULL; } } } /* produce digits for an mpq in requested base, default 10 */ static char doc_qdigitsm[]="\ x.digits([base]): returns Python string representing x in the\n\ given base (2 to 36, default 10 if omitted or 0); leading '-'\n\ is present if x<0, but no leading '+' if x>=0.\n\ "; static char doc_qdigitsg[]="\ qdigits(x[,base]): returns Python string representing x in the\n\ given base (2 to 36, default 10 if omitted or 0); leading '-'\n\ present if x<0, but no leading '+' if x>=0. x must be an mpq,\n\ or else gets coerced into one.\n\ "; static PyObject * Pympq_digits(PyObject *self, PyObject *args) { int base = 10; PyObject *s; SELF_MPQ_ONE_ARG("|i",&base); assert(Pympq_Check(self)); s = Pympq_ascii((PympqObject*)self, base, 0); Py_DECREF(self); return s; } /* return scan0/scan1 for an mpz */ static char doc_scan0m[]="\ x.scan0(n=0): returns the bit-index of the first 0-bit of x (that\n\ is at least n); n must be an ordinary Python int, >=0. If no more\n\ 0-bits are in x at or above bit-index n (which can only happen for\n\ x<0, notionally extended with infinite 1-bits), None is returned.\n\ "; static char doc_scan0g[]="\ scan0(x, n=0): returns the bit-index of the first 0-bit of x (that\n\ is at least n); n must be an ordinary Python int, >=0. If no more\n\ 0-bits are in x at or above bit-index n (which can only happen for\n\ x<0, notionally extended with infinite 1-bits), None is returned.\n\ x must be an mpz, or else gets coerced to one.\n\ "; static PyObject * Pympz_scan0(PyObject *self, PyObject *args) { long starting_bit = 0; long maxbit; PyObject *s; PARSE_ONE_MPZ_OPT_CLONG(&starting_bit, "scan0 expects 'mpz',[starting_bit] arguments"); assert(Pympz_Check(self)); if(starting_bit < 0) { PyErr_SetString(PyExc_ValueError, "starting bit must be >= 0"); Py_DECREF(self); return NULL; } maxbit = mpz_sizeinbase(Pympz_AS_MPZ(self), 2); if(starting_bit > maxbit) { int sig = mpz_sgn(Pympz_AS_MPZ(self)); if(options.debug) fprintf(stderr,"scan0 start=%ld max=%ld sig=%d\n", starting_bit, maxbit, sig); if(sig<0) s = Py_BuildValue(""); else s = Py_BuildValue("l", starting_bit); } else { s = Py_BuildValue("l", mpz_scan0(Pympz_AS_MPZ(self), starting_bit)); } Py_DECREF(self); return s; } static char doc_scan1m[]="\ x.scan1(n=0): returns the bit-index of the first 1-bit of x (that\n\ is at least n); n must be an ordinary Python int, >=0. If no more\n\ 1-bits are in x at or above bit-index n (which can only happen for\n\ x>=0, notionally extended with infinite 0-bits), None is returned.\n\ "; static char doc_scan1g[]="\ scan1(x, n=0): returns the bit-index of the first 1-bit of x (that\n\ is at least n); n must be an ordinary Python int, >=0. If no more\n\ 1-bits are in x at or above bit-index n (which can only happen for\n\ x>=0, notionally extended with infinite 0-bits), None is returned.\n\ x must be an mpz, or else gets coerced to one.\n\ "; static PyObject * Pympz_scan1(PyObject *self, PyObject *args) { long starting_bit = 0; long maxbit; PyObject *s; PARSE_ONE_MPZ_OPT_CLONG(&starting_bit, "scan1 expects 'mpz',[starting_bit] arguments"); assert(Pympz_Check(self)); if(starting_bit < 0) { PyErr_SetString(PyExc_ValueError, "starting bit must be >= 0"); Py_DECREF(self); return NULL; } maxbit = mpz_sizeinbase(Pympz_AS_MPZ(self), 2); if(starting_bit >= maxbit) { int sig = mpz_sgn(Pympz_AS_MPZ(self)); if(options.debug) fprintf(stderr,"scan1 start=%ld max=%ld sig=%d\n", starting_bit, maxbit, sig); if(sig>=0) s = Py_BuildValue(""); else s = Py_BuildValue("l", starting_bit); } else { s = Py_BuildValue("l", mpz_scan1(Pympz_AS_MPZ(self), starting_bit)); } Py_DECREF(self); return s; } /* return population-count (# of 1-bits) for an mpz */ static char doc_popcountm[]="\ x.popcount(): returns the number of 1-bits set in x; note that\n\ this is 'infinite' if x<0, and in that case, -1 is returned.\n\ "; static char doc_popcountg[]="\ popcount(x): returns the number of 1-bits set in x; note that\n\ this is 'infinite' if x<0, and in that case, -1 is returned.\n\ x must be an mpz, or else gets coerced to one.\n\ "; static PyObject * Pympz_popcount(PyObject *self, PyObject *args) { PyObject *s; PARSE_ONE_MPZ("popcount expects 'mpz' argument"); assert(Pympz_Check(self)); s = Py_BuildValue("l", mpz_popcount(Pympz_AS_MPZ(self))); Py_DECREF(self); return s; } /* return N lowest bits from an mpz */ static char doc_lowbitsm[]="\ x.lowbits(n): returns the n lowest bits of x; n must be an\n\ ordinary Python int, >0.\n\ "; static char doc_lowbitsg[]="\ lowbits(x,n): returns the n lowest bits of x; n must be an\n\ ordinary Python int, >0; x must be an mpz, or else gets\n\ coerced to one.\n\ "; static PyObject * Pympz_lowbits(PyObject *self, PyObject *args) { long nbits; PympzObject *s; PARSE_ONE_MPZ_REQ_CLONG(&nbits, "lowbits expects 'mpz',nbits arguments"); assert(Pympz_Check(self)); if(nbits <= 0) { PyErr_SetString(PyExc_ValueError, "nbits must be > 0"); Py_DECREF(self); return NULL; } if(!(s = Pympz_new())) { Py_DECREF(self); return NULL; } mpz_fdiv_r_2exp(s->z, Pympz_AS_MPZ(self), nbits); Py_DECREF(self); return (PyObject*)s; } /* get & return one bit from an mpz */ static char doc_getbitm[]="\ x.getbit(n): returns 0 or 1, the bit-value of bit n of x;\n\ n must be an ordinary Python int, >=0.\n\ "; static char doc_getbitg[]="\ getbit(x,n): returns 0 or 1, the bit-value of bit n of x;\n\ n must be an ordinary Python int, >=0; x is an mpz, or else\n\ gets coerced to one.\n\ "; static PyObject * Pympz_getbit(PyObject *self, PyObject *args) { long bit_index; PyObject *s; PARSE_ONE_MPZ_REQ_CLONG(&bit_index, "getbit expects 'mpz',bit_index arguments"); assert(Pympz_Check(self)); if(bit_index < 0) { PyErr_SetString(PyExc_ValueError, "bit_index must be >= 0"); Py_DECREF(self); return NULL; } s = Py_BuildValue("i", mpz_tstbit(Pympz_AS_MPZ(self), bit_index)); Py_DECREF(self); return s; } static char doc_setbitm[]="\ x.setbit(n,v=1): returns a copy of the value of x, with bit n set\n\ to value v; n must be an ordinary Python int, >=0; v, 0 or !=0.\n\ "; static char doc_setbitg[]="\ setbit(x,n,v=1): returns a copy of the value of x, with bit n set\n\ to value v; n must be an ordinary Python int, >=0; v, 0 or !=0;\n\ x must be an mpz, or else gets coerced to one.\n\ "; static PyObject * Pympz_setbit(PyObject *self, PyObject *args) { long bit_index; long bit_value=1; Py_ssize_t argc; PympzObject *s; argc = PyTuple_GET_SIZE(args); if(self && Pympz_Check(self)) { if(argc == 1) { bit_index = clong_From_Integer(PyTuple_GET_ITEM(args, 0)); if(bit_index == -1 && PyErr_Occurred()) { PyErr_SetString(PyExc_TypeError, "setbit() expects 'mpz','int'[,'int'] arguments"); return NULL; } } else if(argc == 2) { bit_index = clong_From_Integer(PyTuple_GET_ITEM(args, 0)); bit_value = clong_From_Integer(PyTuple_GET_ITEM(args, 1)); if((bit_index == -1 || bit_value == -1) && PyErr_Occurred()) { PyErr_SetString(PyExc_TypeError, "setbit() expects 'mpz','int'[,'int'] arguments"); return NULL; } } else { PyErr_SetString(PyExc_TypeError, "setbit() expects 'mpz','int'[,'int'] arguments"); return NULL; } Py_INCREF(self); } else { if(argc == 2) { self = (PyObject*)Pympz_From_Integer(PyTuple_GET_ITEM(args, 0)); bit_index = clong_From_Integer(PyTuple_GET_ITEM(args, 1)); if(!self || (bit_index == -1 && PyErr_Occurred())) { PyErr_SetString(PyExc_TypeError, "setbit() expects 'mpz','int'[,'int'] arguments"); return NULL; } } else if(argc == 3) { self = (PyObject*)Pympz_From_Integer(PyTuple_GET_ITEM(args, 0)); bit_index = clong_From_Integer(PyTuple_GET_ITEM(args, 1)); bit_value = clong_From_Integer(PyTuple_GET_ITEM(args, 2)); if(!self || ((bit_index == -1 || bit_value == -1) && PyErr_Occurred())) { PyErr_SetString(PyExc_TypeError, "setbit() expects 'mpz','int'[,'int'] arguments"); return NULL; } } else { PyErr_SetString(PyExc_TypeError, "setbit() expects 'mpz','int'[,'int'] arguments"); return NULL; } } if(bit_index < 0) { PyErr_SetString(PyExc_ValueError, "bit_index must be >= 0"); Py_DECREF(self); return NULL; } if(!(s = Pympz2Pympz((PympzObject*)self))) { Py_DECREF(self); return NULL; } Py_DECREF(self); if(bit_value) { mpz_setbit(s->z, bit_index); } else { mpz_clrbit(s->z, bit_index); } return (PyObject*)s; } /* return nth-root of an mpz (in a 2-el tuple: 2nd is int, non-0 iff exact) */ static char doc_rootm[]="\ x.root(n): returns a 2-element tuple (y,m), such that y is the\n\ (possibly truncated) n-th root of x; m, an ordinary Python int,\n\ is 1 if the root is exact (x==y**n), else 0. n must be an ordinary\n\ Python int, >=0.\n\ "; static char doc_rootg[]="\ root(x,n): returns a 2-element tuple (y,m), such that y is the\n\ (possibly truncated) n-th root of x; m, an ordinary Python int,\n\ is 1 if the root is exact (x==y**n), else 0. n must be an ordinary\n\ Python int, >=0. x must be an mpz, or else gets coerced to one.\n\ "; static PyObject * Pympz_root(PyObject *self, PyObject *args) { long n; int exact; PympzObject *s; PARSE_ONE_MPZ_REQ_CLONG(&n, "root expects 'mpz',n arguments"); assert(Pympz_Check(self)); if(n <= 0) { PyErr_SetString(PyExc_ValueError, "n must be > 0"); Py_DECREF(self); return NULL; } else if(n>1) { int sign = mpz_sgn(Pympz_AS_MPZ(self)); if(sign<0) { PyErr_SetString(PyExc_ValueError, "root of negative number"); Py_DECREF(self); return NULL; } } if(!(s = Pympz_new())) { Py_DECREF(self); return NULL; } exact = mpz_root(s->z, Pympz_AS_MPZ(self), n); Py_DECREF(self); return Py_BuildValue("(Ni)", s, exact); } /* produce string for an mpf with requested/defaulted parameters */ static char doc_fdigitsm[]="\ x.digits(base=10, digs=0, mine=0, maxe=-1, opts=0): formats x.\n\ \n\ Returns up to digs digits in the given base (if digs is 0, as many\n\ digits as are available), but no more than available given x's\n\ precision; the resulting string is formatted in fixed point\n\ if the exponent is >=mine and <=maxe, else in exponential (the\n\ exponent-separator is 'e' for base up to 10, else '@' -- the\n\ exponent is always output as a signed, base-10 integer). If opts\n\ has bit 1 set, the whole is wrapped in 'gmpy.mpf(...)', to ease\n\ later approximate reconstruction via builtin function eval\n\ (Or, in just mpf(...) if gmpy.set_tagoff(1) was called).\n\ \n\ If opts has bit 2 set, then opts bit 1, mine, and maxe, are\n\ ignored; the result is then a 2-element tuple, first element\n\ the raw string of base-digits without formatting, second the\n\ exponent in base as a Python int.\n\ "; static char doc_fdigitsg[]="\ fdigits(x, base=10, digs=0, mine=0, maxe=-1, opts=0): formats x,\n\ which is an mpf or else gets coerced to one.\n\ \n\ Returns up to digs digits in the given base (if digs is 0, as many\n\ digits as are available), but no more than available given x's\n\ precision; the resulting string is formatted in fixed point\n\ if the exponent is >=mine and <=maxe, else in exponential (the\n\ exponent-separator is 'e' for base up to 10, else '@' -- the\n\ exponent is always output as a signed, base-10 integer). If opts\n\ has bit 1 set, the whole is wrapped in 'gmpy.mpf(...)', to ease\n\ later approximate reconstruction via builtin function eval\n\ (Or, in just mpf(...) if gmpy.set_tagoff(1) was called).\n\ \n\ If opts has bit 2 set, then opts bit 1, mine, and maxe, are\n\ ignored; the result is then a 2-element tuple, first element\n\ the raw string of base-digits without formatting, second the\n\ exponent in base as a Python int.\n\ "; static PyObject * Pympf_digits(PyObject *self, PyObject *args) { int base = 10; int digs = 0; int mine = 0; int maxe = -1; int opts = 0; PyObject *s; if(self && Pympf_Check(self)) { if(!PyArg_ParseTuple(args, "|iiiii", &base, &digs, &mine, &maxe, &opts)) return NULL; Py_INCREF(self); } else { if(!PyArg_ParseTuple(args, "O&|iiiii", Pympf_convert_arg, &self, &base, &digs, &mine, &maxe, &opts)) return NULL; } assert(Pympf_Check(self)); s = Pympf_ascii( (PympfObject *) self, base, digs, mine, maxe, opts); Py_DECREF(self); return s; } static char doc_signm[]="\ x.sign(): returns -1, 0, or +1, if x is negative, 0, positive.\n\ "; static char doc_signg[]="\ sign(x): returns -1, 0, or +1, if x is negative, 0, positive;\n\ x must be an mpz, or else gets coerced to one.\n\ "; static PyObject * Pympz_sign(PyObject *self, PyObject *args) { PyObject *s; PARSE_ONE_MPZ("sign expects 'mpz' argument"); assert(Pympz_Check(self)); s = Py_BuildValue("i", mpz_sgn(Pympz_AS_MPZ(self))); Py_DECREF(self); return s; } static char doc_qsignm[]="\ x.sign(): returns -1, 0, or +1, if x is negative, 0, positive.\n\ "; static char doc_qsigng[]="\ qsign(x): returns -1, 0, or +1, if x is negative, 0, positive;\n\ x must be an mpq, or else gets coerced to one.\n\ "; static PyObject * Pympq_sign(PyObject *self, PyObject *args) { PyObject *s; SELF_MPQ_NO_ARG; assert(Pympq_Check(self)); s = Py_BuildValue("i", mpq_sgn(Pympq_AS_MPQ(self))); Py_DECREF(self); return s; } static char doc_numerm[]="\ x.numer(): returns numerator of x.\n\ "; static char doc_numerg[]="\ numer(x): returns numerator of x;\n\ x must be an mpq, or else gets coerced to one.\n\ "; static PyObject * Pympq_numer(PyObject *self, PyObject *args) { PympzObject *s; if(!(s = Pympz_new())) return NULL; SELF_MPQ_NO_ARG; assert(Pympq_Check(self)); mpz_set(s->z, mpq_numref(Pympq_AS_MPQ(self))); Py_DECREF(self); return (PyObject*)s; } static PyObject * Pympq_getnumer(PympqObject *self, void *closure) { PympzObject *result; if(!(result = Pympz_new())) return NULL; mpz_set(result->z, mpq_numref(Pympq_AS_MPQ(self))); return (PyObject*)result; } static char doc_denomm[]="\ x.denom(): returns denominator of x.\n\ "; static char doc_denomg[]="\ denom(x): returns denominator of x;\n\ x must be an mpq, or else gets coerced to one.\n\ "; static PyObject * Pympq_denom(PyObject *self, PyObject *args) { PympzObject *s; if(!(s = Pympz_new())) return NULL; SELF_MPQ_NO_ARG; assert(Pympq_Check(self)); mpz_set(s->z, mpq_denref(Pympq_AS_MPQ(self))); Py_DECREF(self); return (PyObject*)s; } static PyObject * Pympq_getdenom(PympqObject *self, void *closure) { PympzObject *result; if(!(result = Pympz_new())) return NULL; mpz_set(result->z, mpq_denref(Pympq_AS_MPQ(self))); return (PyObject*)result; } static char doc_qdivm[]="\ x.qdiv(y=1): returns x/y as mpz if possible, or as mpq\n\ if x is not exactly divisible by y.\n\ "; static char doc_qdivg[]="\ qdiv(x,y=1): returns x/y as mpz if possible, or as mpq\n\ if x is not exactly divisible by y.\n\ "; static int isOne(PyObject* obj) { if(!obj) return 1; if(Pympq_Check(obj)) { return (0==mpz_cmp_ui(mpq_denref(Pympq_AS_MPQ(obj)),1)) && (0==mpz_cmp_ui(mpq_numref(Pympq_AS_MPQ(obj)),1)); } else if(Pympz_Check(obj)) { return 0==mpz_cmp_ui(Pympz_AS_MPZ(obj),1); #if PY_MAJOR_VERSION < 3 } else if(PyInt_Check(obj)) { return PyInt_AS_LONG(obj)==1; #endif } else if(Pympf_Check(obj)) { return mpf_get_d(Pympf_AS_MPF(obj))==1.0; } else if(PyFloat_Check(obj)) { return PyFloat_AS_DOUBLE(obj)==1.0; } else if (PyLong_Check(obj)) { return PyLong_AsLong(obj)==1; } return 0; } static PyObject * Pympq_qdiv(PyObject *self, PyObject *args) { PyObject *other = 0; PyObject *s = 0; int wasone; if(self && Pympq_Check(self)) { if(!PyArg_ParseTuple(args, "|O", &other)) return NULL; } else { if(!PyArg_ParseTuple(args, "O|O", &self, &other)) return NULL; } wasone = isOne(other); /* optimize if self must be returned unchanged */ if(Pympq_Check(self) && wasone) { /* optimize if self is mpq and result must==self */ if(mpz_cmp_ui(mpq_denref(Pympq_AS_MPQ(self)), 1) != 0) { Py_INCREF(self); return self; } else { /* denominator is 1, optimize returning an mpz */ s = (PyObject*)Pympz_new(); mpz_set(Pympz_AS_MPZ(s), mpq_numref(Pympq_AS_MPQ(self))); return s; } } else if(Pympz_Check(self) && wasone) { /* optimize if self is mpz and result must==self */ Py_INCREF(self); return self; } /* normal, non-optimized case: must make new object as result */ self = (PyObject*)anyrational2Pympq(self); if(!self) { if(!PyErr_Occurred()) { PyErr_SetString(PyExc_TypeError, "first argument can not be converted to mpq"); } return NULL; } if(wasone) { /* self was mpf, float, int, long... */ s = self; } else { /* other explicitly present and !=1... must compute */ other = (PyObject*)anyrational2Pympq(other); if(!other) { Py_DECREF(self); if(!PyErr_Occurred()) { PyErr_SetString(PyExc_TypeError, "second argument can not be converted to mpq"); } return NULL; } if(mpq_sgn(Pympq_AS_MPQ(other))==0) { PyObject* result = 0; PyErr_SetString(PyExc_ZeroDivisionError,"qdiv: zero divisor"); Py_DECREF(self); Py_DECREF(other); return result; } s = (PyObject*)Pympq_new(); mpq_div(Pympq_AS_MPQ(s), Pympq_AS_MPQ(self), Pympq_AS_MPQ(other)); Py_DECREF(self); Py_DECREF(other); } if(mpz_cmp_ui(mpq_denref(Pympq_AS_MPQ(s)), 1) != 0) { return s; } else { /* denominator is 1, return an mpz */ PyObject* ss = (PyObject*)Pympz_new(); if(ss) mpz_set(Pympz_AS_MPZ(ss), mpq_numref(Pympq_AS_MPQ(s))); Py_DECREF(s); return ss; } } static char doc_f2qm[]="\ x.f2q([err]): returns the 'best' mpq approximating x to\n\ within relative error err (default, x's precision); 'best'\n\ rationals as per Stern-Brocot tree; mpz if denom is 1.\n\ If err<0, error sought is 2.0 ** err.\n\ "; static char doc_f2qg[]="\ f2q(x[,err]): returns the 'best' mpq approximating x to\n\ within relative error err (default, x's precision); 'best'\n\ rationals as per Stern-Brocot tree; mpz if denom is 1.\n\ If err<0, error sought is 2.0 ** err.\n\ "; static PyObject * Pympf_f2q(PyObject *self, PyObject *args) { PympfObject *err = 0; PympfObject *fself; if(options.debug) fprintf(stderr, "Pympf_f2q: %p, %p\n", (void *)self, (void *)args); SELF_MPF_ONE_ARG_CONVERTED_OPT(&err); assert(Pympf_Check(self)); fself = (PympfObject*)self; return f2q_internal(fself, err, fself->rebits, args!=0); } static PyObject * f2q_internal(PympfObject* self, PympfObject* err, size_t bits, int mayz) { PympqObject *res = 0; int i, negative, errsign; mpf_t f, al, a, r1[3], r2[3], minerr, curerr, newerr, temp; assert(!err || Pympf_Check(err)); errsign = err?mpf_sgn(err->f):0; if(errsign == 0) { if(err) { Py_DECREF((PyObject*)err); } if(!(err = Pympf_new(20))) { Py_DECREF((PyObject*)self); return NULL; } mpf_set_si(err->f, 1); mpf_div_2exp(err->f, err->f, bits); } else if(errsign < 0) { long ubits; mpf_floor(err->f, err->f); ubits = mpf_get_d(err->f); mpf_set_si(err->f, 1); mpf_div_2exp(err->f, err->f, -ubits); } if(!(res = Pympq_new())) return NULL; mpf_init2(minerr, 20); mpf_set(minerr, err->f); Py_DECREF((PyObject*)err); mpf_init2(f, bits); if(mpf_sgn(self->f)<0) { negative = 1; mpf_abs(f, self->f); } else { negative = 0; mpf_set(f, self->f); } Py_DECREF((PyObject*)self); mpf_init2(al, bits); mpf_set(al, f); mpf_init2(a, bits); mpf_floor(a, al); mpf_init2(temp, bits); for(i=0; i<3; ++i) { mpf_init2(r1[i], bits); mpf_init2(r2[i], bits); } mpf_set_si(r1[0], 0); mpf_set_si(r1[1], 0); mpf_set_si(r1[2], 1); mpf_set_si(r2[0], 0); mpf_set_si(r2[1], 1); mpf_set(r2[2], a); mpf_init2(curerr, 20); mpf_init2(newerr, 20); mpf_reldiff(curerr, f, a); while(mpf_cmp(curerr, minerr) > 0) { mpf_sub(temp, al, a); mpf_ui_div(al, 1, temp); mpf_floor(a, al); mpf_swap(r1[0], r1[1]); mpf_swap(r1[1], r1[2]); mpf_mul(r1[2], r1[1], a); mpf_add(r1[2], r1[2], r1[0]); mpf_swap(r2[0], r2[1]); mpf_swap(r2[1], r2[2]); mpf_mul(r2[2], r2[1], a); mpf_add(r2[2], r2[2], r2[0]); mpf_div(temp, r2[2], r1[2]); mpf_reldiff(newerr, f, temp); if(mpf_cmp(curerr, newerr) <= 0) { mpf_swap(r1[1],r1[2]); mpf_swap(r2[1],r2[2]); break; } mpf_swap(curerr, newerr); } if(mayz && (mpf_cmp_ui(r1[2],1)==0)) { Py_DECREF((PyObject*)res); res = (PympqObject*)Pympz_new(); mpz_set_f(Pympz_AS_MPZ(res), r2[2]); if(negative) mpz_neg(Pympz_AS_MPZ(res),Pympz_AS_MPZ(res)); } else { mpz_set_f(mpq_numref(res->q), r2[2]); mpz_set_f(mpq_denref(res->q), r1[2]); if(negative) mpz_neg(mpq_numref(res->q),mpq_numref(res->q)); } mpf_clear(minerr); mpf_clear(al); mpf_clear(a); mpf_clear(f); for(i=0; i<3; ++i) { mpf_clear(r1[i]); mpf_clear(r2[i]); } mpf_clear(curerr); mpf_clear(newerr); mpf_clear(temp); return (PyObject*)res; } /* CONSTRUCTORS */ static char doc_mpz[] = "\ mpz(n): builds an mpz object with a numeric value n (truncating n\n\ to its integer part if it's a float or mpf)\n\ mpz(s,base=10): builds an mpz object from a string s made up of\n\ digits in the given base. If base=0, hex and oct Python\n\ strings may also be interpreted (started with '0x' and '0'\n\ respectively), as well as decimal. If base=256, s must be\n\ a gmpy.mpz portable binary representation as built by the\n\ function gmpy.binary (and the .binary method of mpz objects).\n\ "; static PyObject * Pygmpy_mpz(PyObject *self, PyObject *args) { PympzObject *newob; PyObject *obj; Py_ssize_t argc; if(options.debug) fputs("Pygmpy_mpz() called...\n", stderr); assert(PyTuple_Check(args)); argc = PyTuple_Size(args); if((argc < 1) || (argc > 2)) { PyErr_SetString(PyExc_TypeError, "gmpy.mpz() requires 1 or 2 arguments"); return NULL; } obj = PyTuple_GetItem(args, 0); #if PY_MAJOR_VERSION >= 3 if(PyBytes_Check(obj) || PyUnicode_Check(obj)) { #else if(PyString_Check(obj) || PyUnicode_Check(obj)) { #endif /* build-from-string (ascii or binary) */ long base=10; if(argc == 2) { PyObject *pbase = PyTuple_GetItem(args, 1); base = clong_From_Integer(pbase); if(base == -1 && PyErr_Occurred()) { PyErr_SetString(PyExc_TypeError, "gmpy.mpz(): base must be an integer"); return NULL; } if((base!=0) && (base!=256) && ((base<2)||(base>62))) { PyErr_SetString(PyExc_ValueError, "base for gmpy.mpz must be 0, 256, or in the " "interval 2 ... 62 ."); return NULL; } } newob = PyStr2Pympz(obj, base); if (!newob) { return NULL; } } else { if(argc==2) { PyErr_SetString(PyExc_TypeError, "gmpy.mpz() with numeric argument needs exactly 1 argument"); return NULL; } newob = anynum2Pympz(obj); if(!newob) { if (!PyErr_Occurred()) { PyErr_SetString(PyExc_TypeError, "gmpy.mpz() expects numeric or string argument"); } return NULL; } } if(options.debug) fprintf(stderr, "Pygmpy_mpz: created mpz = %ld\n", mpz_get_si(newob->z)); return (PyObject *) newob; } static char doc_mpq[] = "\ mpq(n): builds an mpq object with a numeric value n\n\ mpq(n,m): builds an mpq object with a numeric value n/m\n\ mpq(s,base=10): builds an mpq object from a string s made up of\n\ digits in the given base. s may be made up of two\n\ numbers in the same base separated by a '/' character.\n\ If base=256, s must be a gmpy.mpq portable binary\n\ representation as built by the gmpy.qbinary (and the\n\ .binary method of mpq objects).\n\ "; static PyObject * Pygmpy_mpq(PyObject *self, PyObject *args) { PympqObject *newob; PyObject *obj; int wasnumeric; Py_ssize_t argc; if(options.debug) fputs("Pygmpy_mpq() called...\n", stderr); assert(PyTuple_Check(args)); argc = PyTuple_Size(args); if((argc < 1) || (argc > 2)) { PyErr_SetString(PyExc_TypeError, "gmpy.mpq() requires 1 or 2 arguments"); return NULL; } obj = PyTuple_GetItem(args, 0); #if PY_MAJOR_VERSION >= 3 if(PyBytes_Check(obj) || PyUnicode_Check(obj)) { #else if(PyString_Check(obj) || PyUnicode_Check(obj)) { #endif /* build-from-string (ascii or binary) */ long base=10; wasnumeric=0; if(argc == 2) { PyObject *pbase = PyTuple_GetItem(args, 1); base = clong_From_Integer(pbase); if(base == -1 && PyErr_Occurred()) { PyErr_SetString(PyExc_TypeError, "gmpy.mpq(): base must be an integer"); return NULL; } if((base!=0) && (base!=256) && ((base<2)||(base>36))) { PyErr_SetString(PyExc_ValueError, "base for gmpy.mpq() must be 0, 256, or in the " "interval 2 ... 36 ."); return NULL; } } newob = PyStr2Pympq(obj, base); if (!newob) { return NULL; } } else { wasnumeric=1; newob = anynum2Pympq(obj); if(!newob) { if(!PyErr_Occurred()) { PyErr_SetString(PyExc_TypeError, "gmpy.mpq() expects numeric or string argument"); } return NULL; } } if(options.debug) { fputs("Pygmpy_mpq: created mpq = ", stderr); mpq_out_str(stderr, 10, newob->q); putc('\n', stderr); } if(wasnumeric && argc==2) { PympqObject *denominator; denominator = anynum2Pympq(PyTuple_GET_ITEM(args, 1)); if(!denominator) { PyErr_SetString(PyExc_TypeError, "argument can not be converted to mpq"); Py_DECREF((PyObject*)newob); return NULL; } if(0==mpq_sgn(Pympq_AS_MPQ(denominator))) { PyErr_SetString(PyExc_ZeroDivisionError,"mpq: zero denominator"); Py_DECREF((PyObject*) newob); Py_DECREF((PyObject*)denominator); return NULL; } mpq_div(newob->q, newob->q, denominator->q); Py_DECREF((PyObject*)denominator); } return (PyObject *) newob; } static char doc_mpf[] = "\ mpf(n): builds an mpf object with a numeric value n (n may be any\n\ Python number, or an mpz, mpq, or mpf object) and a default\n\ precision (in bits) depending on the nature of n\n\ mpf(n,bits=0): as above, but with the specified number of bits (0\n\ means to use default precision, as above)\n\ mpf(s,bits=0,base=10): builds an mpf object from a string s made up of\n\ digits in the given base, possibly with fraction-part (with\n\ period as a separator) and/or exponent-part (with exponent\n\ marker 'e' for base<=10, else '@'). If base=256, s must be\n\ a gmpy.mpf portable binary representation as built by the\n\ function gmpy.fbinary (and the .binary method of mpf objects).\n\ The resulting mpf object is built with a default precision (in\n\ bits) if bits is 0 or absent, else with the specified number\n\ of bits.\n\ "; static PyObject * Pygmpy_mpf(PyObject *self, PyObject *args) { PympfObject *newob; PyObject *obj; Py_ssize_t argc; size_t bits=0; if(options.debug) fputs("Pygmpy_mpf() called...\n", stderr); assert(PyTuple_Check(args)); argc = PyTuple_Size(args); if((argc < 1) || (argc > 3)) { PyErr_SetString(PyExc_TypeError, "gmpy.mpf() requires 1 to 3 arguments"); return NULL; } obj = PyTuple_GetItem(args, 0); if(2 <= argc) { long sbits; PyObject *pbits = PyTuple_GetItem(args, 1); sbits = clong_From_Integer(pbits); if(sbits == -1 && PyErr_Occurred()) { PyErr_SetString(PyExc_TypeError, "gmpy.mpf(): bits must be an integer"); return NULL; } if(sbits<0) { PyErr_SetString(PyExc_ValueError, "bits for gmpy.mpf must be >= 0"); return NULL; } bits = sbits; } #if PY_MAJOR_VERSION >= 3 if(PyBytes_Check(obj) || PyUnicode_Check(obj)) { #else if(PyString_Check(obj) || PyUnicode_Check(obj)) { #endif /* build-from-string (ascii or binary) */ long base=10; if(3 == argc) { PyObject *pbase = PyTuple_GetItem(args, 2); base = clong_From_Integer(pbase); if(base == -1 && PyErr_Occurred()) { PyErr_SetString(PyExc_TypeError, "gmpy.mpf(): base must be an integer"); return NULL; } if((base!=0) && (base!=256) && ((base<2)||(base>62))) { PyErr_SetString(PyExc_ValueError, "base for gmpy.mpf must be 0, 256, or in the " "interval 2 ... 62 ."); return NULL; } } newob = PyStr2Pympf(obj, base, bits); if (!newob) { return NULL; } } else { if(argc==3) { PyErr_SetString(PyExc_TypeError, "gmpy.mpf() with numeric 1st argument needs 1 or 2 arguments"); return NULL; } newob = anynum2Pympf(obj, bits); if(!newob) { if(!PyErr_Occurred()) PyErr_SetString(PyExc_TypeError, "gmpy.mpf() expects numeric or string argument"); return NULL; } } if(options.debug) { fputs("Pygmpy_mpf: created mpf = ", stderr); mpf_out_str(stderr, 10, 0, newob->f); fprintf(stderr," bits=%"PY_FORMAT_SIZE_T"d (%"PY_FORMAT_SIZE_T"d)\n", newob->rebits, bits); } return (PyObject *) newob; } /* Pygmpy_mpf() */ /* ARITHMETIC */ /* Include the basic arithmetic operations from gmpy_basic.py. * * The following routines are contained in gmpy_basic.py: * Pympany_add() * Pympany_sub() * Pympany_mul() * Pympany_floordiv() * Pympany_truediv() * Pympany_div2() -- Python 2.x only! * Pympany_divmod() */ #include "gmpy_utility.c" #include "gmpy_basic.c" #ifdef MUTATE #include "gmpy_mpz_mutate.c" #else #include "gmpy_mpz_inplace.c" #endif #define MPZ_BINOP(NAME) \ static PyObject * \ Py##NAME(PyObject *a, PyObject *b) \ { \ PympzObject *r; \ PympzObject *pa = 0; \ PympzObject *pb = 0; \ pa = Pympz_From_Integer(a); \ pb = Pympz_From_Integer(b); \ if(!pa || !pb) { \ PyErr_Clear(); \ Py_XDECREF((PyObject*)pa); \ Py_XDECREF((PyObject*)pb); \ Py_RETURN_NOTIMPLEMENTED; \ } \ if (options.debug) fprintf(stderr, "Py" #NAME ": %p, %p\n", (void *)pa, (void *)pb); \ if (!(r = Pympz_new())) { \ Py_DECREF((PyObject*)pa); \ Py_DECREF((PyObject*)pb); \ return NULL; \ } \ NAME(r->z, pa->z, pb->z); \ Py_DECREF((PyObject*)pa); \ Py_DECREF((PyObject*)pb); \ if (options.debug) fprintf(stderr, "Py" #NAME "-> %p\n", (void *)r); \ return (PyObject *) r; \ } #define MPF_BINOP(NAME) \ static PyObject * \ Py##NAME(PyObject *a, PyObject *b) \ { \ size_t bits, bbits; \ PympfObject *r; \ PympfObject *pa = 0; \ PympfObject *pb = 0; \ if(Pympf_Check(a) && Pympf_Check(b)) { \ bits = ((PympfObject*)a)->rebits; \ bbits = ((PympfObject*)b)->rebits; \ if(bits>bbits) bits=bbits; \ if (!(r = Pympf_new(bits))) { \ return NULL; \ } \ NAME(r->f, ((PympfObject*)a)->f, ((PympfObject*)b)->f); \ if (options.debug) fprintf(stderr, "Py" #NAME "-> %p", (void *)r); \ Pympf_normalize(r); \ return (PyObject *) r; \ } else { \ if(Pympf_Check(a)) { \ bits = ((PympfObject*)a)->rebits; \ } else { \ bits = ((PympfObject*)b)->rebits; \ } \ pa = anynum2Pympf(a, bits); \ pb = anynum2Pympf(b, bits); \ if(!pa || !pb) { \ PyObject *r = Py_NotImplemented; \ Py_XDECREF((PyObject*)pa); \ Py_XDECREF((PyObject*)pb); \ Py_INCREF(r); \ return r; \ } \ if (options.debug) fprintf(stderr, "Py" #NAME ": %p, %p", (void *)pa, (void *)pb); \ if (!(r = Pympf_new(bits))) { \ Py_DECREF((PyObject*)pa); \ Py_DECREF((PyObject*)pb); \ return NULL; \ } \ NAME(r->f, pa->f, pb->f); \ Py_DECREF((PyObject*)pa); \ Py_DECREF((PyObject*)pb); \ if (options.debug) fprintf(stderr, "Py" #NAME "-> %p", (void *)r); \ Pympf_normalize(r); \ return (PyObject *) r; \ } \ } #define MPQ_BINOP(NAME) \ static PyObject * \ Py##NAME(PyObject *a, PyObject *b) \ { \ PympqObject *r; \ PympqObject *pa = 0; \ PympqObject *pb = 0; \ pa = anyrational2Pympq(a); \ pb = anyrational2Pympq(b); \ if(!pa || !pb) { \ PyObject *r = Py_NotImplemented; \ Py_XDECREF((PyObject*)pa); \ Py_XDECREF((PyObject*)pb); \ Py_INCREF((PyObject*)r); \ return r; \ } \ if (options.debug) fprintf(stderr, "Py" #NAME ": %p, %p", (void *)pa, (void *)pb); \ if (!(r = Pympq_new())) { \ Py_DECREF((PyObject*)pa); \ Py_DECREF((PyObject*)pb); \ return NULL; \ } \ NAME(r->q, pa->q, pb->q); \ Py_DECREF((PyObject*)pa); \ Py_DECREF((PyObject*)pb); \ if (options.debug) fprintf(stderr, "Py" #NAME "-> %p", (void *)r); \ return (PyObject *) r; \ } MPF_BINOP(mpf_reldiff) #define MPZ_MONOP(NAME) \ static PyObject * \ Py##NAME(PympzObject *x) \ { \ PympzObject *r; \ if (options.debug) fprintf(stderr, "Py" #NAME ": %p\n", (void *)x); \ if (!(r = Pympz_new())) return NULL; \ NAME(r->z, x->z); \ if (options.debug) fprintf(stderr, "Py" #NAME "-> %p\n", (void *)r); \ return (PyObject *) r; \ } #define MPF_MONOP(NAME) \ static PyObject * \ Py##NAME(PympfObject *x) \ { \ PympfObject *r; \ if (options.debug) fprintf(stderr, "Py" #NAME ": %p\n", (void *)x); \ if (!(r = Pympf_new(x->rebits))) return NULL; \ NAME(r->f, x->f); \ if (options.debug) fprintf(stderr, "Py" #NAME "-> %p\n", (void *)r); \ return (PyObject *) r; \ } #define MPQ_MONOP(NAME) \ static PyObject * \ Py##NAME(PympqObject *x) \ { \ PympqObject *r; \ if (options.debug) fprintf(stderr, "Py" #NAME ": %p\n", (void *)x); \ if (!(r = Pympq_new())) return NULL; \ NAME(r->q, x->q); \ if (options.debug) fprintf(stderr, "Py" #NAME "-> %p\n", (void *)r); \ return (PyObject *) r; \ } MPZ_MONOP(mpz_abs) MPZ_MONOP(mpz_neg) /* MPQ_MONOP(mpq_inv) */ MPQ_MONOP(mpq_neg) static PyObject * Pympq_abs(PympqObject *x) { PympqObject *r; if (options.debug) fprintf(stderr, "Pympq_abs: %p\n", (void *)x); if (!(r = Pympq_new())) return NULL; mpq_set(r->q, x->q); mpz_abs(mpq_numref(r->q),mpq_numref(r->q)); if (options.debug) fprintf(stderr, "Pympq_abs-> %p\n", (void *)r); return (PyObject *) r; } MPF_MONOP(mpf_abs) MPF_MONOP(mpf_neg) static PyObject * Pympz_pos(PympzObject *x) { Py_INCREF((PyObject*)x); return (PyObject *) x; } static PyObject * Pympq_pos(PympqObject *x) { Py_INCREF((PyObject*)x); return (PyObject *) x; } static PyObject * Pympf_pos(PympfObject *x) { Py_INCREF((PyObject*)x); return (PyObject *) x; } /* Pympz_pow is called by Pympany_pow after verifying that all the * arguments are integers, but not necessarily mpz. */ static PyObject * Pympz_pow(PyObject *in_b, PyObject *in_e, PyObject *in_m) { PympzObject *r, *b, *e, *m; b = Pympz_From_Integer(in_b); e = Pympz_From_Integer(in_e); /* m will either be an number or Py_None. */ if(in_m != Py_None) { m = Pympz_From_Integer(in_m); } else { m = (PympzObject*) in_m; Py_INCREF((PyObject*)m); } if(!b || !e || (!m && ((PyObject*)m != Py_None))) { PyErr_Clear(); Py_XDECREF((PyObject*)b); Py_XDECREF((PyObject*)e); Py_XDECREF((PyObject*)m); Py_RETURN_NOTIMPLEMENTED; } if(options.debug) fprintf(stderr, "Pympz_pow: %p, %p, %p\n", (void *)b, (void *)e, (void *)m); if(mpz_sgn(e->z) < 0) { PyErr_SetString(PyExc_ValueError, "mpz.pow with negative power"); Py_XDECREF((PyObject*)b); Py_XDECREF((PyObject*)e); Py_XDECREF((PyObject*)m); return NULL; } if((PyObject*)in_m == Py_None) { /* When no modulo is present, the exponent must fit in C ulong */ unsigned long el; if(!mpz_fits_slong_p(e->z)) { PyErr_SetString(PyExc_ValueError, "mpz.pow outrageous exponent"); Py_XDECREF((PyObject*)b); Py_XDECREF((PyObject*)e); Py_XDECREF((PyObject*)m); return NULL; } el = mpz_get_ui(e->z); if(!(r = Pympz_new())) { Py_XDECREF((PyObject*)b); Py_XDECREF((PyObject*)e); Py_XDECREF((PyObject*)m); return NULL; } mpz_pow_ui(r->z, b->z, el); if(options.debug) fprintf(stderr, "Pympz_pow (ui) -> %p\n", (void *)r); } else { /* Modulo exponentiation */ int sign; mpz_t mm; sign = mpz_sgn(m->z); if(sign == 0) { PyErr_SetString(PyExc_ValueError, "mpz.pow divide by zero"); Py_XDECREF((PyObject*)b); Py_XDECREF((PyObject*)e); Py_XDECREF((PyObject*)m); return NULL; } if(!(r = Pympz_new())) { Py_XDECREF((PyObject*)b); Py_XDECREF((PyObject*)e); Py_XDECREF((PyObject*)m); return NULL; } mpz_inoc(mm); mpz_abs(mm, m->z); mpz_powm(r->z, b->z, e->z, mm); mpz_cloc(mm); if((sign<0) && (mpz_sgn(r->z) > 0)) { /* Python uses a rather peculiar convention for negative modulos * If the modulo is negative, result should be in the interval * m < r <= 0 . */ mpz_add(r->z, r->z, m->z); } if(options.debug) fprintf(stderr, "Pympz_pow -> %p\n", (void *)r); } Py_XDECREF((PyObject*)b); Py_XDECREF((PyObject*)e); Py_XDECREF((PyObject*)m); return (PyObject*)r; } static PyObject * Pympq_pow(PyObject *in_b, PyObject *in_e, PyObject *m) { PympqObject *r; PympqObject *b = anyrational2Pympq(in_b); PympqObject *e = anyrational2Pympq(in_e); int esign; unsigned long ultem; assert(Pympq_Check(b)); assert(Pympq_Check(e)); if(!b || !e) { PyObject *r; Py_XDECREF((PyObject*)b); Py_XDECREF((PyObject*)e); r = Py_NotImplemented; Py_INCREF(r); return r; } if(options.debug) fprintf(stderr, "Pympq_pow: %p, %p, %p\n", (void *)b, (void *)e, (void *)m); if((PyObject*)m != Py_None) { PyErr_SetString(PyExc_ValueError, "mpq.pow no modulo allowed"); Py_DECREF((PyObject*)b); Py_DECREF((PyObject*)e); return NULL; } if(!mpz_fits_slong_p(mpq_numref(e->q))) { PyErr_SetString(PyExc_ValueError, "mpq.pow outrageous exp num"); Py_DECREF((PyObject*)b); Py_DECREF((PyObject*)e); return NULL; } if(!mpz_fits_slong_p(mpq_denref(e->q))) { PyErr_SetString(PyExc_ValueError, "mpq.pow outrageous exp den"); Py_DECREF((PyObject*)b); Py_DECREF((PyObject*)e); return NULL; } if(!(r = Pympq_new())) { Py_DECREF((PyObject*)b); Py_DECREF((PyObject*)e); return NULL; } esign = mpq_sgn(e->q); if(esign == 0) { if(options.debug) fprintf(stderr, "Pympq_pow (ui,0) -> %p\n", (void *)r); mpq_set_si(r->q, 1, 1); Py_DECREF((PyObject*)b); Py_DECREF((PyObject*)e); return (PyObject*)r; } else if(esign < 0) { int bsign = mpq_sgn(b->q); if(bsign == 0) { PyObject* result = 0; PyErr_SetString(PyExc_ZeroDivisionError,"mpq.pow 0 base to <0 exponent"); Py_DECREF((PyObject*)r); Py_DECREF((PyObject*)b); Py_DECREF((PyObject*)e); return result; } if(bsign < 0) { mpz_neg(mpq_numref(r->q), mpq_denref(b->q)); } else { mpz_set(mpq_numref(r->q), mpq_denref(b->q)); } mpz_abs(mpq_denref(r->q), mpq_numref(b->q)); ultem = -mpz_get_si(mpq_numref(e->q)); } else { mpq_set(r->q, b->q); ultem = mpz_get_ui(mpq_numref(e->q)); } if(ultem>1) { mpz_pow_ui(mpq_numref(r->q), mpq_numref(r->q), ultem); mpz_pow_ui(mpq_denref(r->q), mpq_denref(r->q), ultem); } ultem = mpz_get_ui(mpq_denref(e->q)); if(ultem>1) { static char* msgi = "mpq.pow fractional exponent, inexact-root"; char* msg = msgi; int exact=0; if(mpq_sgn(r->q)<0) { static char* msgi = "mpq.pow fractional exponent, nonreal-root"; msg = msgi; } else { mpz_t temp; /* workaround mpz_root bug in GMP 3.1.1 */ mpz_inoc(temp); exact = mpz_root(temp, mpq_numref(r->q), ultem); if(exact) { mpz_set(mpq_numref(r->q), temp); exact = mpz_root(temp, mpq_denref(r->q), ultem); mpz_set(mpq_denref(r->q), temp); } } if(!exact) { Py_DECREF((PyObject*)r); PyErr_SetString(PyExc_ValueError, msg); Py_DECREF((PyObject*)b); Py_DECREF((PyObject*)e); return NULL; } } if(options.debug) fprintf(stderr, "Pympq_pow (ui) -> %p\n", (void *)r); Py_DECREF((PyObject*)b); Py_DECREF((PyObject*)e); return (PyObject*)r; } static PyObject * Pympf_pow(PyObject *xb, PyObject *xe, PyObject *m) { PympqObject *qb, *qe; PyObject *r; size_t bits; int iexpo; PympfObject *b = 0, *e = 0; if((PyObject*)m != Py_None) { PyErr_SetString(PyExc_ValueError, "mpf.pow no modulo allowed"); return NULL; } if((Pympf_Check(xb) && Pympf_Check(xe))) { b = anynum2Pympf(xb, 0); e = anynum2Pympf(xe, 0); } else { if(Pympf_Check(xb)) { b = anynum2Pympf(xb, 0); e = anynum2Pympf(xe, ((PympfObject*)xb)->rebits); } if(Pympf_Check(xe)) { b = anynum2Pympf(xb, ((PympfObject*)xe)->rebits); e = anynum2Pympf(xe, 0); } } if(!e || !b) { PyObject *r = Py_NotImplemented; Py_INCREF(r); Py_XDECREF((PyObject*)e); Py_XDECREF((PyObject*)b); return r; } bits = b->rebits; if(bits > e->rebits) bits = e->rebits; if(options.debug) fprintf(stderr, "Pympf_pow(%"PY_FORMAT_SIZE_T"d): %p, %p, %p\n", bits, (void *)b, (void *)e, (void *)m); iexpo = (int)mpf_get_d(e->f); if(iexpo>0 && 0==mpf_cmp_si(e->f, iexpo)) { r = (PyObject*)Pympf_new(b->rebits); if(!r) { Py_DECREF((PyObject*)e); Py_DECREF((PyObject*)b); return 0; } mpf_pow_ui(Pympf_AS_MPF(r), b->f, iexpo); } else { qb = Pympf2Pympq((PyObject*)b); qe = Pympf2Pympq((PyObject*)e); r = Pympq_pow((PyObject*)qb, (PyObject*)qe, (PyObject*)m); Py_DECREF((PyObject*)qb); Py_DECREF((PyObject*)qe); if(!r || !Pympq_Check(r)) { Py_DECREF((PyObject*)e); Py_DECREF((PyObject*)b); return r; } qb = (PympqObject*)r; r = (PyObject*)Pympq2Pympf((PyObject*)qb, bits); Py_DECREF((PyObject*)qb); } Pympf_normalize((PympfObject*)r); Py_DECREF((PyObject*)e); Py_DECREF((PyObject*)b); return r; } static PyObject * Pympany_pow(PyObject *in_b, PyObject *in_e, PyObject *in_m) { PyObject *r; PyObject *temp_b = 0, *temp_e = 0, *temp_r = 0, *res = 0; if(isInteger(in_b) && isInteger(in_e)) { return Pympz_pow(in_b, in_e, in_m); } else if((PyFloat_Check(in_b) && Pympz_Check(in_e)) || \ (PyFloat_Check(in_e) && Pympz_Check(in_b))) { if(in_m != Py_None) { PyErr_SetString(PyExc_TypeError, "3rd argument not allowed"); return NULL; } else { if(Pympz_Check(in_b)) { temp_b = Pympz2PyFloat((PympzObject*)in_b); } else if(Pympq_Check(in_b)) { temp_b = Pympq2PyFloat((PympqObject*)in_b); } else if(Pympz_Check(in_b)) { temp_b = Pympf2PyFloat((PympfObject*)in_b); } else if(PyFloat_Check(in_b)) { temp_b = in_b; Py_INCREF(temp_b); } if(!temp_b) { r = Py_NotImplemented; Py_INCREF(r); return r; } if(Pympz_Check(in_e)) { temp_e = Pympz2PyFloat((PympzObject*)in_e); } else if(Pympq_Check(in_e)) { temp_e = Pympq2PyFloat((PympqObject*)in_e); } else if(Pympz_Check(in_e)) { temp_e = Pympf2PyFloat((PympfObject*)in_e); } else if(PyFloat_Check(in_e)) { temp_e = in_e; Py_INCREF(temp_e); } if(!temp_e) { r = Py_NotImplemented; Py_DECREF((PyObject*)temp_b); Py_INCREF(r); return r; } temp_r = PyNumber_Power(temp_b, temp_e, Py_None); Py_DECREF((PyObject*)temp_b); Py_DECREF((PyObject*)temp_e); if(!temp_r) { return NULL; } res = (PyObject *)PyFloat2Pympf(temp_r, 0); Py_DECREF((PyObject*)temp_r); return (PyObject *)res; } } else if(isRational(in_b) && isRational(in_e)) { return Pympq_pow(in_b, in_e, in_m); } else if(isNumber(in_b) && isNumber(in_e)) { return Pympf_pow(in_b, in_e, in_m); } r = Py_NotImplemented; Py_INCREF(r); return r; } /* COMPARING */ static PyObject *_cmp_to_object(int c, int op) { PyObject *result; switch (op) { case Py_LT: c = c < 0; break; case Py_LE: c = c <= 0; break; case Py_EQ: c = c == 0; break; case Py_NE: c = c != 0; break; case Py_GT: c = c > 0; break; case Py_GE: c = c >= 0; break; } result = c ? Py_True : Py_False; Py_INCREF(result); return result; } static PyObject * mpany_richcompare(PyObject *a, PyObject *b, int op) { int c; long temp; PyObject *tempa = 0, *tempb = 0, *result = 0; if(options.debug) { fprintf(stderr, "rich_compare: type(a) is %s\n", Py_TYPE(a)->tp_name); fprintf(stderr, "rich_compare: type(b) is %s\n", Py_TYPE(b)->tp_name); } #if PY_MAJOR_VERSION == 3 if(Pympz_Check(a) && PyLong_Check(b)) { #else if(Pympz_Check(a) && (PyInt_Check(b) || PyLong_Check(b))) { #endif if(options.debug) fprintf(stderr, "compare (mpz,small_int)\n"); temp = clong_From_Integer(b); if(options.debug) fprintf(stderr,"temp is %ld\n", temp); if(temp==-1 && PyErr_Occurred()) { PyErr_Clear(); if(options.debug) fprintf(stderr, "clearing error\n"); } else { if(options.debug) fprintf(stderr, "temp: %ld\n", temp); return _cmp_to_object(mpz_cmp_si(Pympz_AS_MPZ(a), temp), op); } } if(Pympz_Check(a) && Pympz_Check(b)) { if(options.debug) fprintf(stderr, "compare (mpz,mpz)\n"); return _cmp_to_object(mpz_cmp(Pympz_AS_MPZ(a), Pympz_AS_MPZ(b)), op); } if(Pympq_Check(a) && Pympq_Check(b)) { if(options.debug) fprintf(stderr, "compare (mpq,mpq)\n"); return _cmp_to_object(mpq_cmp(Pympq_AS_MPQ(a), Pympq_AS_MPQ(b)), op); } if(Pympf_Check(a) && Pympf_Check(b)) { if(options.debug) fprintf(stderr, "compare (mpf,mpf)\n"); return _cmp_to_object(mpf_cmp(Pympf_AS_MPF(a), Pympf_AS_MPF(b)), op); } if(isInteger(a) && isInteger(b)) { if(options.debug) fprintf(stderr, "compare (mpz,int)\n"); tempa = (PyObject*)Pympz_From_Integer(a); tempb = (PyObject*)Pympz_From_Integer(b); c = mpz_cmp(Pympz_AS_MPZ(tempa), Pympz_AS_MPZ(tempb)); Py_DECREF(tempa); Py_DECREF(tempb); return _cmp_to_object(c, op); } if(isRational(a) && isRational(b)) { if(options.debug) fprintf(stderr, "compare (mpq,rational)\n"); tempa = (PyObject*)anyrational2Pympq(a); tempb = (PyObject*)anyrational2Pympq(b); c = mpq_cmp(Pympq_AS_MPQ(tempa), Pympq_AS_MPQ(tempb)); Py_DECREF(tempa); Py_DECREF(tempb); return _cmp_to_object(c, op); } if(isNumber(a) && isNumber(b)) { if(options.debug) fprintf(stderr, "compare (mpf,float)\n"); /* Handle non-numbers separately. */ if(PyFloat_Check(b)) { double d = PyFloat_AS_DOUBLE(b); if(isnan(d)) { result = (op == Py_NE) ? Py_True : Py_False; Py_INCREF(result); return result; } else if (isinf(d)) { if(d < 0) { return _cmp_to_object(1, op); } else { return _cmp_to_object(-1, op); } } } tempa = (PyObject*)anynum2Pympf(a,0); tempb = (PyObject*)anynum2Pympf(b,0); c = mpf_cmp(Pympf_AS_MPF(tempa), Pympf_AS_MPF(tempb)); Py_DECREF(tempa); Py_DECREF(tempb); return _cmp_to_object(c, op); } result = Py_NotImplemented; Py_INCREF(result); return result; } static int Pympz_nonzero(PympzObject *x) { return mpz_sgn(x->z) != 0; } static int Pympq_nonzero(PympqObject *x) { return mpq_sgn(x->q) != 0; } static int Pympf_nonzero(PympfObject *x) { return mpf_sgn(x->f) != 0; } /* float-truncations (return still a float!) */ #define MPF_UNIOP(NAME) \ static PyObject * \ Py##NAME(PyObject* self, PyObject *args) \ { \ PympfObject *r; \ if(self && Pympf_Check(self)) { \ if(args && !PyArg_ParseTuple(args, "")) return NULL; \ Py_INCREF(self); \ } else { \ if(!PyArg_ParseTuple(args, "O&", Pympf_convert_arg, &self)) return NULL; \ } \ assert(Pympf_Check(self)); \ if (options.debug) fprintf(stderr, "Py" #NAME ": %p\n", (void *)self); \ if (!(r = Pympf_new(((PympfObject*)self)->rebits))) return NULL; \ NAME(r->f, Pympf_AS_MPF(self)); \ if (options.debug) fprintf(stderr, "Py" #NAME "-> %p\n", (void *)r); \ Py_DECREF(self); \ Pympf_normalize(r); \ return (PyObject *) r; \ } static char doc_ceilm[]="\ x.ceil(): returns an mpf that is the smallest integer >= x\n\ "; static char doc_ceilg[]="\ ceil(x): returns an mpf that is the smallest integer >= x\n\ x must be an mpf, or else gets coerced to one.\n\ "; MPF_UNIOP(mpf_ceil) static char doc_floorm[]="\ x.floor(): returns an mpf that is the smallest integer <= x\n\ "; static char doc_floorg[]="\ floor(x): returns an mpf that is the smallest integer <= x\n\ x must be an mpf, or else gets coerced to one.\n\ "; MPF_UNIOP(mpf_floor) static char doc_truncm[]="\ x.trunc(): returns an mpf that is x truncated towards 0\n\ (same as x.floor() if x>=0, x.ceil() if x<0).\n\ "; static char doc_truncg[]="\ trunc(x): returns an mpf that is x truncated towards 0\n\ (same as x.floor() if x>=0, x.ceil() if x<0).\n\ x must be an mpf, or else gets coerced to one.\n\ "; MPF_UNIOP(mpf_trunc) /* BIT OPERATIONS (mpz-only) */ MPZ_MONOP(mpz_com) MPZ_BINOP(mpz_and) MPZ_BINOP(mpz_ior) MPZ_BINOP(mpz_xor) static PyObject * Pympz_rshift(PyObject *a, PyObject *b) { PympzObject *rz, *pa, *pb; long count; #if PY_MAJOR_VERSION == 3 int overflow; #endif if(!(rz = Pympz_new())) return NULL; /* Try to make mpz >> Python int/long as fast as possible. */ if(Pympz_Check(a)) { #if PY_MAJOR_VERSION == 2 if(PyInt_Check(b)) { if((count = PyInt_AS_LONG(b)) >= 0) { mpz_fdiv_q_2exp(rz->z, Pympz_AS_MPZ(a), count); return (PyObject *)rz; } else { PyErr_SetString(PyExc_ValueError, "negative shift count"); Py_DECREF((PyObject*)rz); return NULL; } } #endif if(PyLong_Check(b)) { #if PY_MAJOR_VERSION == 3 count = PyLong_AsLongAndOverflow(b, &overflow); if(overflow) { #else count = PyLong_AsLong(b); if(PyErr_Occurred()) { #endif PyErr_SetString(PyExc_ValueError, "outrageous shift count"); Py_DECREF((PyObject*)rz); return NULL; } else if(count >= 0) { mpz_fdiv_q_2exp(rz->z, Pympz_AS_MPZ(a), count); return (PyObject *)rz; } else { PyErr_SetString(PyExc_ValueError, "negative shift count"); Py_DECREF((PyObject*)rz); return NULL; } } } pa = Pympz_From_Integer(a); pb = Pympz_From_Integer(b); if(!pb || !pa) { PyErr_Clear(); Py_DECREF((PyObject*)rz); Py_XDECREF((PyObject*)pa); Py_XDECREF((PyObject*)pb); Py_RETURN_NOTIMPLEMENTED; } if(mpz_sgn(Pympz_AS_MPZ(pb)) < 0) { PyErr_SetString(PyExc_ValueError, "negative shift count"); Py_DECREF((PyObject*)rz); Py_DECREF((PyObject*)pa); Py_DECREF((PyObject*)pb); return NULL; } if(!mpz_fits_slong_p(pb->z)) { PyErr_SetString(PyExc_OverflowError, "outrageous shift count"); Py_DECREF((PyObject*)rz); Py_DECREF((PyObject*)pa); Py_DECREF((PyObject*)pb); return NULL; } count = mpz_get_si(pb->z); mpz_fdiv_q_2exp(rz->z, pa->z, count); Py_DECREF((PyObject*)pa); Py_DECREF((PyObject*)pb); return (PyObject*)rz; } static PyObject * Pympz_lshift(PyObject *a, PyObject *b) { PympzObject *rz, *pa, *pb; long count; #if PY_MAJOR_VERSION == 3 int overflow; #endif if(!(rz = Pympz_new())) return NULL; /* Try to make mpz >> Python int/long as fast as possible. */ if(Pympz_Check(a)) { #if PY_MAJOR_VERSION == 2 if(PyInt_Check(b)) { if((count = PyInt_AS_LONG(b)) >= 0) { mpz_mul_2exp(rz->z, Pympz_AS_MPZ(a), count); return (PyObject *)rz; } else { PyErr_SetString(PyExc_ValueError, "negative shift count"); Py_DECREF((PyObject*)rz); return NULL; } } #endif if(PyLong_Check(b)) { #if PY_MAJOR_VERSION == 3 count = PyLong_AsLongAndOverflow(b, &overflow); if(overflow) { #else count = PyLong_AsLong(b); if(PyErr_Occurred()) { #endif PyErr_SetString(PyExc_ValueError, "outrageous shift count"); Py_DECREF((PyObject*)rz); return NULL; } else if(count >= 0) { mpz_mul_2exp(rz->z, Pympz_AS_MPZ(a), count); return (PyObject *)rz; } else { PyErr_SetString(PyExc_ValueError, "negative shift count"); Py_DECREF((PyObject*)rz); return NULL; } } } pa = Pympz_From_Integer(a); pb = Pympz_From_Integer(b); if(!pb || !pa) { PyErr_Clear(); Py_DECREF((PyObject*)rz); Py_XDECREF((PyObject*)pa); Py_XDECREF((PyObject*)pb); Py_RETURN_NOTIMPLEMENTED; } if(mpz_sgn(Pympz_AS_MPZ(pb)) < 0) { PyErr_SetString(PyExc_ValueError, "negative shift count"); Py_DECREF((PyObject*)rz); Py_DECREF((PyObject*)pa); Py_DECREF((PyObject*)pb); return NULL; } if(!mpz_fits_slong_p(pb->z)) { PyErr_SetString(PyExc_OverflowError, "outrageous shift count"); Py_DECREF((PyObject*)rz); Py_DECREF((PyObject*)pa); Py_DECREF((PyObject*)pb); return NULL; } count = mpz_get_si(pb->z); mpz_mul_2exp(rz->z, pa->z, count); Py_DECREF((PyObject*)pa); Py_DECREF((PyObject*)pb); return (PyObject*)rz; } #if PY_MAJOR_VERSION < 3 /* hex/oct formatting (mpz-only) */ static PyObject * Pympz_oct(PympzObject *self) { return Pympz_ascii(self, 8, 0, 0); } static PyObject * Pympz_hex(PympzObject *self) { return Pympz_ascii(self, 16, 0, 0); } #endif /* hashing */ #ifndef _PyHASH_MODULUS static Py_hash_t dohash(PyObject* tempPynum) { Py_hash_t hash; if(!tempPynum) return -1; hash = PyObject_Hash(tempPynum); Py_DECREF(tempPynum); return hash; } #endif static Py_hash_t Pympz_hash(PympzObject *self) { #ifdef _PyHASH_MODULUS Py_hash_t hash = 0; hash = (Py_hash_t)mpn_mod_1(self->z->_mp_d, mpz_size(self->z), _PyHASH_MODULUS); if(mpz_sgn(self->z)<0) hash = -hash; if(hash==-1) hash = -2; return hash; #else return mpz_pythonhash(Pympz_AS_MPZ(self)); #endif } static Py_hash_t Pympf_hash(PympfObject *self) { #ifdef _PyHASH_MODULUS Py_uhash_t hash = 0; Py_ssize_t exp = 0; size_t mbits = 0; mpz_t hack; int sign; /* Calculate the hash of the mantissa. */ if(self->f->_mp_size>0) { hash = (Py_hash_t)mpn_mod_1(self->f->_mp_d, self->f->_mp_size, _PyHASH_MODULUS); sign = 1; } else if(self->f->_mp_size<0) { hash = mpn_mod_1(self->f->_mp_d, -(self->f->_mp_size), _PyHASH_MODULUS); sign = -1; } else { return 0; } /* Get the number of bits in the mantissa. Ugly hack. */ hack->_mp_size = self->f->_mp_size; hack->_mp_d = self->f->_mp_d; mbits = mpz_sizeinbase(hack, 2); /* Get the exponent as a power of 2. */ mpf_get_d_2exp(&exp, self->f); /* Calculate the final hash. */ exp -= (Py_ssize_t)mbits; exp = exp >= 0 ? exp % _PyHASH_BITS : _PyHASH_BITS-1-((-1-exp) % _PyHASH_BITS); hash = ((hash << exp) & _PyHASH_MODULUS) | hash >> (_PyHASH_BITS - exp); hash = (Py_hash_t)hash * sign; if(hash==(Py_uhash_t)-1) hash = (Py_uhash_t)-2; return (Py_hash_t)hash; #else double temp; temp = mpf_get_d(self->f); return _Py_HashDouble(temp); #endif } static Py_hash_t Pympq_hash(PympqObject *self) { #ifdef _PyHASH_MODULUS Py_hash_t hash = 0; mpz_t temp, temp1, mask; mpz_inoc(temp); mpz_inoc(temp1); mpz_inoc(mask); mpz_set_si(mask, 1); mpz_mul_2exp(mask, mask, _PyHASH_BITS); mpz_sub_ui(mask, mask, 1); if (!mpz_invert(temp, mpq_denref(self->q), mask)) { mpz_cloc(temp); mpz_cloc(temp1); mpz_cloc(mask); hash = _PyHASH_INF; if (mpz_sgn(mpq_numref(self->q))<0) hash = -hash; return hash; } mpz_set(temp1, mask); mpz_sub_ui(temp1, temp1, 2); mpz_powm(temp, mpq_denref(self->q), temp1, mask); mpz_tdiv_r(temp1, mpq_numref(self->q), mask); mpz_mul(temp, temp, temp1); hash = (Py_hash_t)mpn_mod_1(temp->_mp_d, mpz_size(temp), _PyHASH_MODULUS); if (mpz_sgn(mpq_numref(self->q))<0) hash = -hash; if (hash==-1) hash = -2; mpz_cloc(temp); mpz_cloc(temp1); mpz_cloc(mask); return hash; #else return dohash(Pympq2PyFloat(self)); #endif } /* Miscellaneous gmpy functions */ static char doc_gcd[]="\ gcd(a,b): returns the greatest common denominator of numbers a and b\n\ (which must be mpz objects, or else get coerced to mpz)\n\ "; static PyObject * Pygmpy_gcd(PyObject *self, PyObject *args) { PympzObject *result; PyObject *other; PARSE_TWO_MPZ(other, "gcd() expects 'mpz','mpz' arguments"); if(!(result = Pympz_new())) { Py_DECREF(self); Py_DECREF(other); return NULL; } mpz_gcd(result->z, Pympz_AS_MPZ(self), Pympz_AS_MPZ(other)); Py_DECREF(self); Py_DECREF(other); return (PyObject*)result; } static char doc_lcm[]="\ lcm(a,b): returns the lowest common multiple of numbers a and b\n\ (which must be mpz objects, or else get coerced to mpz)\n\ "; static PyObject * Pygmpy_lcm(PyObject *self, PyObject *args) { PympzObject *result; PyObject *other; PARSE_TWO_MPZ(other, "lcm() expects 'mpz','mpz' arguments"); if(!(result = Pympz_new())) { Py_DECREF(self); Py_DECREF(other); return NULL; } mpz_lcm(result->z, Pympz_AS_MPZ(self), Pympz_AS_MPZ(other)); Py_DECREF(self); Py_DECREF(other); return (PyObject*)result; } static char doc_gcdext[]="\ gcdext(a,b): returns a 3-element tuple (g,s,t) such that\n\ g==gcd(a,b) and g == a*s + b*t\n\ (a and b must be mpz objects, or else get coerced to mpz)\n\ "; static PyObject * Pygmpy_gcdext(PyObject *self, PyObject *args) { PympzObject *g=0, *s=0, *t=0; PyObject *result, *other; PARSE_TWO_MPZ(other, "gcdext() expects 'mpz','mpz' arguments"); g = Pympz_new(); s = Pympz_new(); t = Pympz_new(); if(!g||!s||!t) { Py_DECREF(self); Py_DECREF(other); Py_XDECREF((PyObject*)g); Py_XDECREF((PyObject*)s); Py_XDECREF((PyObject*)t); return NULL; } mpz_gcdext(g->z, s->z, t->z, Pympz_AS_MPZ(self), Pympz_AS_MPZ(other)); Py_DECREF(self); Py_DECREF(other); result = Py_BuildValue("(NNN)", g, s, t); /* Does NOT increment refcounts! */ return (PyObject *) result; } static char doc_divm[]="\ divm(a,b,m): returns x such that b*x==a modulo m, or else raises\n\ a ZeroDivisionError exception if no such value x exists\n\ (a, b and m must be mpz objects, or else get coerced to mpz)\n\ "; static PyObject * Pygmpy_divm(PyObject *self, PyObject *args) { PympzObject *num, *den, *mod, *res; mpz_t numz, denz, modz, gcdz; int ok; if(!PyArg_ParseTuple(args, "O&O&O&", Pympz_convert_arg, &num, Pympz_convert_arg, &den, Pympz_convert_arg, &mod)) { return NULL; } if(!(res = Pympz_new())) { Py_DECREF((PyObject*)num); Py_DECREF((PyObject*)den); Py_DECREF((PyObject*)mod); return NULL; } mpz_inoc(numz); mpz_inoc(denz); mpz_inoc(modz); mpz_set(numz, num->z); mpz_set(denz, den->z); mpz_set(modz, mod->z); if(mpz_invert(res->z, denz, modz)) { /* inverse exists */ ok = 1; } else { /* last-ditch attempt: do num, den AND mod have a gcd>1 ? */ mpz_inoc(gcdz); mpz_gcd(gcdz, numz, denz); mpz_gcd(gcdz, gcdz, modz); mpz_divexact(numz, numz, gcdz); mpz_divexact(denz, denz, gcdz); mpz_divexact(modz, modz, gcdz); mpz_cloc(gcdz); ok = mpz_invert(res->z, denz, modz); } if (ok) { mpz_mul(res->z, res->z, numz); mpz_mod(res->z, res->z, modz); mpz_cloc(numz); mpz_cloc(denz); mpz_cloc(modz); Py_DECREF((PyObject*)num); Py_DECREF((PyObject*)den); Py_DECREF((PyObject*)mod); return (PyObject*)res; } else { PyObject* result = 0; PyErr_SetString(PyExc_ZeroDivisionError, "not invertible"); mpz_cloc(numz); mpz_cloc(denz); mpz_cloc(modz); Py_DECREF((PyObject*)num); Py_DECREF((PyObject*)den); Py_DECREF((PyObject*)mod); Py_DECREF((PyObject*)res); return result; } } static char doc_fac[]="\ fac(n): returns the factorial of n; takes O(n) time; n must be\n\ an ordinary Python int, >=0.\n\ "; static PyObject * Pygmpy_fac(PyObject *self, PyObject *args) { PympzObject *fac; long n; ONE_ARG("fac", "l", &n); if(n < 0) { PyErr_SetString(PyExc_ValueError, "factorial of negative number"); return NULL; } if(!(fac = Pympz_new())) return NULL; mpz_fac_ui(fac->z, n); return (PyObject *) fac; } static char doc_fib[]="\ fib(n): returns the n-th Fibonacci number; takes O(n) time; n must be\n\ an ordinary Python int, >=0.\n\ "; static PyObject * Pygmpy_fib(PyObject *self, PyObject *args) { PympzObject *fib; long n; ONE_ARG("fib", "l", &n); if(n < 0) { PyErr_SetString(PyExc_ValueError, "Fibonacci of negative number"); return NULL; } if(!(fib = Pympz_new())) return NULL; mpz_fib_ui(fib->z, n); return (PyObject *) fib; } static char doc_pi[]="\ pi(n): returns pi with n bits of precision in an mpf object\n\ "; /* This function was originally from netlib, package bmp, by * Richard P. Brent. Paulo Cesar Pereira de Andrade converted * it to C and used it in his LISP interpreter. * * Original comments: * * sets mp pi = 3.14159... to the available precision. * uses the gauss-legendre algorithm. * this method requires time o(ln(t)m(t)), so it is slower * than mppi if m(t) = o(t**2), but would be faster for * large t if a faster multiplication algorithm were used * (see comments in mpmul). * for a description of the method, see - multiple-precision * zero-finding and the complexity of elementary function * evaluation (by r. p. brent), in analytic computational * complexity (edited by j. f. traub), academic press, 1976, 151-176. * rounding options not implemented, no guard digits used. */ static PyObject * Pygmpy_pi(PyObject *self, PyObject *args) { PympfObject *pi; int precision; mpf_t r_i2, r_i3, r_i4; mpf_t ix; ONE_ARG("pi", "i", &precision); if(!(pi = Pympf_new(precision))) { return NULL; } mpf_set_si(pi->f, 1); mpf_init(ix); mpf_set_ui(ix, 1); mpf_init2(r_i2, precision); mpf_init2(r_i3, precision); mpf_set_d(r_i3, 0.25); mpf_init2(r_i4, precision); mpf_set_d(r_i4, 0.5); mpf_sqrt(r_i4, r_i4); for (;;) { mpf_set(r_i2, pi->f); mpf_add(pi->f, pi->f, r_i4); mpf_div_ui(pi->f, pi->f, 2); mpf_mul(r_i4, r_i2, r_i4); mpf_sub(r_i2, pi->f, r_i2); mpf_mul(r_i2, r_i2, r_i2); mpf_mul(r_i2, r_i2, ix); mpf_sub(r_i3, r_i3, r_i2); mpf_sqrt(r_i4, r_i4); mpf_mul_ui(ix, ix, 2); /* Check for convergence */ if (!(mpf_cmp_si(r_i2, 0) && mpf_get_prec(r_i2) >= (unsigned)precision)) { mpf_mul(pi->f, pi->f, r_i4); mpf_div(pi->f, pi->f, r_i3); break; } } mpf_clear(ix); mpf_clear(r_i2); mpf_clear(r_i3); mpf_clear(r_i4); Pympf_normalize(pi); return (PyObject*)pi; } static char doc_bincoefm[]="\ x.bincoef(n): returns the 'binomial coefficient' that is 'x\n\ over n'; n is an ordinary Python int, >=0.\n\ "; static char doc_bincoefg[]="\ bincoef(x,n): returns the 'binomial coefficient' that is 'x\n\ over n'; n is an ordinary Python int, >=0; x must be an mpz,\n\ or else gets converted to one.\n\ "; static char doc_combm[]="\ x.comb(n): returns the 'number of combinations' of 'x things,\n\ taken n at a time'; n is an ordinary Python int, >=0.\n\ "; static char doc_combg[]="\ comb(x,n): returns the 'number of combinations' of 'x things,\n\ taken n at a time'; n is an ordinary Python int, >=0; x must be\n\ an mpz, or else gets converted to one.\n\ "; static PyObject * Pympz_bincoef(PyObject *self, PyObject *args) { PympzObject *bincoef; long k; PARSE_ONE_MPZ_REQ_CLONG(&k, "bincoef() expects 'mpz','int' arguments"); if(k < 0) { PyErr_SetString(PyExc_ValueError, "binomial coefficient with negative k"); Py_DECREF(self); return NULL; } if(!(bincoef = Pympz_new())) { Py_DECREF(self); return NULL; } mpz_bin_ui(bincoef->z, Pympz_AS_MPZ(self), k); Py_DECREF(self); return (PyObject*)bincoef; } static char doc_fsqrtm[]="\ x.fsqrt(): returns the square root of x. x must be >= 0.\n\ "; static char doc_fsqrtg[]="\ fsqrt(x): returns the square root of x. x must be an mpf, or\n\ else gets coerced to one; further, x must be >= 0.\n\ "; static PyObject * Pympf_sqrt(PyObject *self, PyObject *args) { PympfObject *root; SELF_MPF_NO_ARG; assert(Pympf_Check(self)); if(mpf_sgn(Pympf_AS_MPF(self)) < 0) { PyErr_SetString(PyExc_ValueError, "sqrt of negative number"); Py_DECREF(self); return NULL; } if(!(root = Pympf_new(((PympfObject*)self)->rebits))) { Py_DECREF(self); return NULL; } mpf_sqrt(root->f, Pympf_AS_MPF(self)); Py_DECREF(self); Pympf_normalize(root); return (PyObject *) root; } static char doc_sqrtm[]="\ x.sqrt(): returns the integer, truncated square root of x, i.e. the\n\ largest y such that x>=y*y. x must be >= 0.\n\ "; static char doc_sqrtg[]="\ sqrt(x): returns the integer, truncated square root of x, i.e. the\n\ largest y such that x>=y*y. x must be an mpz, or else gets coerced\n\ to one; further, x must be >= 0.\n\ "; static PyObject * Pympz_sqrt(PyObject *self, PyObject *args) { PympzObject *root; PARSE_ONE_MPZ("sqrt() expects 'mpz' argument"); assert(Pympz_Check(self)); if(mpz_sgn(Pympz_AS_MPZ(self)) < 0) { PyErr_SetString(PyExc_ValueError, "sqrt of negative number"); Py_DECREF(self); return NULL; } if(!(root = Pympz_new())) { Py_DECREF(self); return NULL; } mpz_sqrt(root->z, Pympz_AS_MPZ(self)); Py_DECREF(self); return (PyObject *) root; } static char doc_sqrtremm[]="\ x.sqrtrem(): returns a 2-element tuple (s,t), such that\n\ s==x.sqrt() and x==s*s+t. x must be >= 0.\n\ "; static char doc_sqrtremg[]="\ sqrtrem(x): returns a 2-element tuple (s,t), such that\n\ s==sqrt(x) and x==s*s+t. x must be an mpz, or else gets\n\ coerced to one; further, x must be >= 0.\n\ "; static PyObject * Pympz_sqrtrem(PyObject *self, PyObject *args) { PympzObject *root=0, *rem=0; PyObject *result; PARSE_ONE_MPZ("sqrtrem() expects 'mpz' argument"); if(mpz_sgn(Pympz_AS_MPZ(self)) < 0) { PyErr_SetString(PyExc_ValueError, "sqrt of negative number"); Py_DECREF(self); return NULL; } root = Pympz_new(); rem = Pympz_new(); result = PyTuple_New(2); if(!root || !rem || !result) { Py_XDECREF((PyObject*)rem); Py_XDECREF((PyObject*)root); Py_XDECREF(result); Py_DECREF((PyObject*)self); return NULL; } mpz_sqrtrem(root->z, rem->z, Pympz_AS_MPZ(self)); Py_DECREF(self); PyTuple_SET_ITEM(result, 0, (PyObject*)root); PyTuple_SET_ITEM(result, 1, (PyObject*)rem); return result; } static char doc_removem[]="\ x.remove(f): returns a 2-element tuple (y,m) such that\n\ x==y*(f**m), and y%f==0; i.e., y is x with any factor f\n\ removed, and m (an ordinary Python int) is the multiplicity\n\ of the factor f in x (m=0, and y=x, unless x%f==0). f must\n\ be > 0.\n\ "; static char doc_removeg[]="\ remove(x,f): returns a 2-element tuple (y,m) such that\n\ x==y*(f**m), and y%f==0; i.e., y is x with any factor f\n\ removed, and m (an ordinary Python int) is the multiplicity\n\ of the factor f in x (m=0, and y=x, unless x%f==0). x must\n\ be an mpz, or else gets coerced to one; f must be > 0.\n\ "; static PyObject * Pympz_remove(PyObject *self, PyObject *args) { PympzObject *result; PyObject *factor; unsigned long multiplicity; PARSE_TWO_MPZ(factor, "remove() expects 'mpz','mpz' arguments"); if(mpz_cmp_si(Pympz_AS_MPZ(factor), 2) < 0) { PyErr_SetString(PyExc_ValueError, "factor must be > 1"); Py_DECREF(self); Py_DECREF(factor); return NULL; } if(!(result = Pympz_new())) { Py_DECREF(self); Py_DECREF(factor); return NULL; } multiplicity = mpz_remove(result->z, Pympz_AS_MPZ(self), Pympz_AS_MPZ(factor)); Py_DECREF(self); Py_DECREF(factor); return Py_BuildValue("(Nk)", result, multiplicity); } static char doc_invertm[]="\ x.invert(m): returns the inverse of x modulo m, i.e., that y\n\ such that x*y==1 modulo m, or 0 if no such y exists.\n\ m must be an ordinary Python int, !=0.\n\ "; static char doc_invertg[]="\ invert(x,m): returns the inverse of x modulo m, i.e., that y\n\ such that x*y==1 modulo m, or 0 if no such y exists.\n\ m must be an ordinary Python int, !=0; x must be an mpz,\n\ or else gets converted to one.\n\ "; static PyObject * Pympz_invert(PyObject *self, PyObject *args) { PympzObject *result; PyObject *modulo; int success; PARSE_TWO_MPZ(modulo, "invert() expects 'mpz','mpz' arguments"); if(!(result = Pympz_new())) { Py_DECREF(self); Py_DECREF(modulo); return NULL; } success = mpz_invert(result->z, Pympz_AS_MPZ(self), Pympz_AS_MPZ(modulo)); if(!success) mpz_set_ui(result->z, 0); Py_DECREF(self); Py_DECREF(modulo); return (PyObject*)result; } static char doc_hamdistm[]="\ x.hamdist(y): returns the Hamming distance (number of bit-positions\n\ where the bits differ) between x and y. y must be an mpz, or else\n\ gets coerced to one.\n\ "; static char doc_hamdistg[]="\ hamdist(x,y): returns the Hamming distance (number of bit-positions\n\ where the bits differ) between x and y. x and y must be mpz, or else\n\ get coerced to mpz.\n\ "; static PyObject * Pympz_hamdist(PyObject *self, PyObject *args) { PyObject *result, *other; PARSE_TWO_MPZ(other, "hamdist() expects 'mpz','mpz' arguments"); result = Py2or3Int_FromLong( mpz_hamdist(Pympz_AS_MPZ(self),Pympz_AS_MPZ(other))); Py_DECREF(self); Py_DECREF(other); return (PyObject*)result; } static char doc_divexactg[]="\ divexact(x,y): returns the quotient of x divided by y. Faster than\n\ standard division but requires the remainder is zero! x and y must\n\ be mpz, or else get coerced to mpz.\n\ "; static PyObject * Pympz_divexact(PyObject *self, PyObject *args) { PyObject *other; PympzObject *result; PARSE_TWO_MPZ(other, "divexact() expects 'mpz','mpz' arguments"); if(mpz_sgn(Pympz_AS_MPZ(other)) == 0) { PyErr_SetString(PyExc_ZeroDivisionError, "divexact() division by 0"); Py_DECREF(self); Py_DECREF(other); return NULL; } if(!(result = Pympz_new())) { Py_DECREF(self); Py_DECREF(other); return NULL; } mpz_divexact(result->z,Pympz_AS_MPZ(self),Pympz_AS_MPZ(other)); Py_DECREF(self); Py_DECREF(other); return (PyObject*)result; } static char doc_cdivmodg[]="\ cdivmod(x,y): returns the quotient of x divided by y. The quotient\n\ is rounded towards +Inf and the remainder will have the opposite\n\ sign to y. x and y must be mpz, or else get coerced to mpz.\n\ "; static PyObject * Pympz_cdivmod(PyObject *self, PyObject *args) { PyObject *other, *result; PympzObject *quot, *rem; PARSE_TWO_MPZ(other, "cdivmod() expects 'mpz','mpz' arguments"); if(mpz_sgn(Pympz_AS_MPZ(other)) == 0) { PyErr_SetString(PyExc_ZeroDivisionError, "cdivmod() division by 0"); Py_DECREF(self); Py_DECREF(other); return NULL; } quot = Pympz_new(); rem = Pympz_new(); result = PyTuple_New(2); if(!quot || !rem || !result) { Py_XDECREF((PyObject*)result); Py_XDECREF((PyObject*)quot); Py_XDECREF((PyObject*)rem); Py_DECREF(self); Py_DECREF(other); return NULL; } mpz_cdiv_qr(quot->z, rem->z, Pympz_AS_MPZ(self), Pympz_AS_MPZ(other)); Py_DECREF(self); Py_DECREF(other); PyTuple_SET_ITEM(result, 0, (PyObject*)quot); PyTuple_SET_ITEM(result, 1, (PyObject*)rem); return result; } static char doc_fdivmodg[]="\ fdivmod(x,y): returns the quotient of x divided by y. The quotient\n\ is rounded towards -Inf and the remainder will have the same sign\n\ as y. x and y must be mpz, or else get coerced to mpz.\n\ "; static PyObject * Pympz_fdivmod(PyObject *self, PyObject *args) { PyObject *other, *result; PympzObject *quot, *rem; PARSE_TWO_MPZ(other, "fdivmod() expects 'mpz','mpz' arguments"); if(mpz_sgn(Pympz_AS_MPZ(other)) == 0) { PyErr_SetString(PyExc_ZeroDivisionError, "fdivmod() division by 0"); Py_DECREF(self); Py_DECREF(other); return NULL; } quot = Pympz_new(); rem = Pympz_new(); result = PyTuple_New(2); if(!quot || !rem || !result) { Py_XDECREF((PyObject*)result); Py_XDECREF((PyObject*)quot); Py_XDECREF((PyObject*)rem); Py_DECREF(self); Py_DECREF(other); return NULL; } mpz_fdiv_qr(quot->z, rem->z, Pympz_AS_MPZ(self), Pympz_AS_MPZ(other)); Py_DECREF(self); Py_DECREF(other); PyTuple_SET_ITEM(result, 0, (PyObject*)quot); PyTuple_SET_ITEM(result, 1, (PyObject*)rem); return result; } static char doc_tdivmodg[]="\ tdivmod(x,y): returns the quotient of x divided by y. The quotient\n\ is rounded towards zero and the remaider will have the same sign\n\ as x. x and y must be mpz, or else get coerced to mpz.\n\ "; static PyObject * Pympz_tdivmod(PyObject *self, PyObject *args) { PyObject *other, *result; PympzObject *quot, *rem; PARSE_TWO_MPZ(other, "tdivmod() expects 'mpz','mpz' arguments"); if(mpz_sgn(Pympz_AS_MPZ(other)) == 0) { PyErr_SetString(PyExc_ZeroDivisionError, "tdivmod() division by 0"); Py_DECREF(self); Py_DECREF(other); return NULL; } quot = Pympz_new(); rem = Pympz_new(); result = PyTuple_New(2); if(!quot || !rem || !result) { Py_XDECREF((PyObject*)result); Py_XDECREF((PyObject*)quot); Py_XDECREF((PyObject*)rem); Py_DECREF(self); Py_DECREF(other); return NULL; } mpz_tdiv_qr(quot->z, rem->z, Pympz_AS_MPZ(self), Pympz_AS_MPZ(other)); Py_DECREF(self); Py_DECREF(other); PyTuple_SET_ITEM(result, 0, (PyObject*)quot); PyTuple_SET_ITEM(result, 1, (PyObject*)rem); return result; } /* Include helper functions for mpmath. */ #include "gmpy_mpmath.c" static char doc_is_squarem[]="\ x.is_square(): returns 1 if x is a perfect square, else 0.\n\ "; static char doc_is_squareg[]="\ is_square(x): returns 1 if x is a perfect square, else 0.\n\ x must be an mpz, or else gets coerced to one.\n\ "; static PyObject * Pympz_is_square(PyObject *self, PyObject *args) { long i; PARSE_ONE_MPZ("is_square() expects 'mpz' argument"); i = (long) mpz_perfect_square_p(Pympz_AS_MPZ(self)); Py_DECREF(self); return Py2or3Int_FromLong(i); } static char doc_is_powerm[]="\ x.is_power(): returns 1 if x is a perfect power, i.e., there exist\n\ y, and n>1, such that x==y**n; else, 0.\n\ "; static char doc_is_powerg[]="\ is_power(x): returns 1 if x is a perfect power, i.e., there exist\n\ y, and n>1, such that x==y**n; else, 0. x must be an mpz, or else\n\ gets coerced to one.\n\ "; static PyObject * Pympz_is_power(PyObject *self, PyObject *args) { long i; PARSE_ONE_MPZ("is_power() expects 'mpz' argument"); i = (long) mpz_perfect_power_p(Pympz_AS_MPZ(self)); Py_DECREF(self); return Py2or3Int_FromLong(i); } static char doc_is_primem[]="\ x.is_prime(n=25): returns 2 if x is _certainly_ prime, 1 if x is\n\ _probably_ prime (probability > 1 - 1/2**n), 0 if x is composite.\n\ If x<0, GMP considers x 'prime' iff -x is prime; gmpy reflects this\n\ GMP design choice.\n\ "; static char doc_is_primeg[]="\ is_prime(x,n=25): returns 2 if x is _certainly_ prime, 1 if x is\n\ _probably_ prime (probability > 1 - 1/2**n), 0 if x is composite.\n\ If x<0, GMP considers x 'prime' iff -x is prime; gmpy reflects this\n\ GMP design choice. x must be an mpz, or else gets coerced to one.\n\ "; static PyObject * Pympz_is_prime(PyObject *self, PyObject *args) { long i; int reps = 25; PARSE_ONE_MPZ_OPT_CLONG(&reps, "is_prime() expects 'mpz',[reps] arguments"); if(reps <= 0) { PyErr_SetString(PyExc_ValueError, "repetition count for is_prime must be positive"); Py_DECREF(self); return NULL; } i = (long) mpz_probab_prime_p(Pympz_AS_MPZ(self), reps); Py_DECREF(self); return Py2or3Int_FromLong(i); } static char doc_next_primem[]="\ x.next_prime(): returns the smallest prime number > x. Note that\n\ GMP may use a probabilistic definition of 'prime', and also that\n\ if x<0 GMP considers x 'prime' iff -x is prime; gmpy reflects these\n\ GMP design choices.\n\ "; static char doc_next_primeg[]="\ next_prime(x): returns the smallest prime number > x. Note that\n\ GMP may use a probabilistic definition of 'prime', and also that\n\ if x<0 GMP considers x 'prime' iff -x is prime; gmpy reflects these\n\ GMP design choices. x must be an mpz, or else gets coerced to one.\n\ "; static PyObject * Pympz_next_prime(PyObject *self, PyObject *args) { PympzObject *res; PARSE_ONE_MPZ("next_prime() expects 'mpz' argument"); assert(Pympz_Check(self)); if(!(res = Pympz_new())) { Py_DECREF(self); return NULL; } mpz_nextprime(res->z, Pympz_AS_MPZ(self)); Py_DECREF(self); return (PyObject*)res; } static char doc_jacobim[]="\ x.jacobi(y): returns the Jacobi symbol (x|y) (y should be odd\n\ and must be positive).\n\ "; static char doc_jacobig[]="\ jacobi(x,y): returns the Jacobi symbol (x|y) (y should be odd and\n\ must be positive); x and y must be mpz, or else get coerced to mpz.\n\ "; static PyObject * Pympz_jacobi(PyObject *self, PyObject *args) { PyObject* other; long i; PARSE_TWO_MPZ(other, "jacobi() expects 'mpz','mpz' arguments"); if(mpz_sgn(Pympz_AS_MPZ(other))<=0) { PyErr_SetString(PyExc_ValueError, "jacobi's y must be odd prime > 0"); Py_DECREF(self); Py_DECREF(other); return NULL; } i =(long) (mpz_jacobi(Pympz_AS_MPZ(self), Pympz_AS_MPZ(other))); Py_DECREF(self); Py_DECREF(other); return Py2or3Int_FromLong(i); } static char doc_legendrem[]="\ x.legendre(y): returns the Legendre symbol (x|y) (y should be odd\n\ and must be positive).\n\ "; static char doc_legendreg[]="\ legendre(x,y): returns the Legendre symbol (x|y) (y should be odd\n\ and must be positive); x must be an mpz, or else gets coerced to one.\n\ "; static PyObject * Pympz_legendre(PyObject *self, PyObject *args) { PyObject* other; long i; PARSE_TWO_MPZ(other, "legendre() expects 'mpz','mpz' arguments"); if(mpz_sgn(Pympz_AS_MPZ(other))<=0) { PyErr_SetString(PyExc_ValueError, "legendre's y must be odd and > 0"); Py_DECREF(self); Py_DECREF(other); return NULL; } i = (long) mpz_legendre(Pympz_AS_MPZ(self), Pympz_AS_MPZ(other)); Py_DECREF(self); Py_DECREF(other); return Py2or3Int_FromLong(i); } static char doc_kroneckerm[]="\ x.kronecker(y): returns the Kronecker-Jacobi symbol (x|y).\n\ (At least one of x and y must fit in a plain int).\n\ "; static char doc_kroneckerg[]="\ kronecker(x,y): returns the Kronecker-Jacobi symbol (x|y).\n\ x and y must be mpz, or else get coerced to mpz (at least\n\ one of x and y, however, must also fit in a plain int).\n\ "; static PyObject * Pympz_kronecker(PyObject *self, PyObject *args) { PyObject* other; int ires; PARSE_TWO_MPZ(other, "kronecker() expects 'mpz','mpz' arguments"); if(mpz_fits_ulong_p(Pympz_AS_MPZ(self))) { ires = mpz_ui_kronecker( mpz_get_ui(Pympz_AS_MPZ(self)),Pympz_AS_MPZ(other)); } else if(mpz_fits_ulong_p(Pympz_AS_MPZ(other))) { ires = mpz_kronecker_ui( Pympz_AS_MPZ(self),mpz_get_ui(Pympz_AS_MPZ(other))); } else if(mpz_fits_slong_p(Pympz_AS_MPZ(self))) { ires = mpz_si_kronecker( mpz_get_si(Pympz_AS_MPZ(self)),Pympz_AS_MPZ(other)); } else if(mpz_fits_slong_p(Pympz_AS_MPZ(other))) { ires = mpz_kronecker_si( Pympz_AS_MPZ(self),mpz_get_si(Pympz_AS_MPZ(other))); } else { PyErr_SetString(PyExc_ValueError, "Either arg in Kronecker must fit in an int"); Py_DECREF(self); Py_DECREF(other); return NULL; } Py_DECREF(self); Py_DECREF(other); return Py2or3Int_FromLong(ires); } static char doc_getprecm[]="\ x.getprec(): returns the number of bits of precision in x.\n\ "; static char doc_getprecg[]="\ getprec(x): returns the number of bits of precision in x,\n\ which must be an mpf or else gets coerced to one.\n\ "; static PyObject * Pympf_getprec(PyObject *self, PyObject *args) { long precres; SELF_MPF_NO_ARG; assert(Pympf_Check(self)); precres = (long) mpf_get_prec(Pympf_AS_MPF(self)); Py_DECREF(self); return Py2or3Int_FromLong(precres); } static char doc_getrprecm[]="\ x.getrprec(): returns the number of bits of precision in x\n\ _that were requested_ (.getprec may return a higher value).\n\ "; static char doc_getrprecg[]="\ getrprec(x): returns the number of bits of precision in x,\n\ _that were requested_ (getprec may return a higher value).\n\ x must be an mpf, or else gets coerced to one.\n\ "; static PyObject * Pympf_getrprec(PyObject *self, PyObject *args) { long precres; SELF_MPF_NO_ARG; assert(Pympf_Check(self)); precres = (long) ((PympfObject*)self)->rebits; Py_DECREF(self); return Py2or3Int_FromLong(precres); } static char doc_setprecm[]="\ x.setprec(n): sets the number of bits of precision in x to\n\ be _at least_ n (n>0). ***note that this alters x***!!!\n\ Please use x.round(); it returns a new value instead of\n\ altering the existing value. setprec() will be removed in a\n\ future release.\n\ "; static PyObject * Pympf_setprec(PyObject *self, PyObject *args) { long precres; assert(self); /* exists _as method, ONLY_ */ assert(Pympf_Check(self)); if(PyErr_Warn(PyExc_DeprecationWarning, "setprec() will be removed, use round() instead")) { return NULL; } ONE_ARG("setprec", "l", &precres); if(precres<0) { PyErr_SetString(PyExc_ValueError, "n must be >=0"); return NULL; } mpf_set_prec(Pympf_AS_MPF(self), precres); ((PympfObject*)self)->rebits = precres; Pympf_normalize((PympfObject*)self); return Py_BuildValue(""); } static char doc_froundm[] = "\ x.round(n): returns x rounded to least n bits. Actual precision will\n\ be a multiple of gmp_limbsize().\n\ "; static char doc_froundg[] = "\ fround(x, n): returns x rounded to least n bits. Actual precision will\n\ be a multiple of gmp_limbsize(). x an mpf or coerced to an mpf.\n\ "; static PyObject * Pympf_round(PyObject *self, PyObject *args) { /* Should really get default precision. */ long prec = 64; PyObject *s; SELF_MPF_ONE_ARG("|l",&prec); assert(Pympf_Check(self)); s = (PyObject*)Pympf2Pympf((PympfObject*)self, prec); Py_DECREF(self); return s; } static char doc_reldiffm[] = "\ x.reldiff(y): returns the relative difference between x and y,\n\ where y can be any number and gets coerced to an mpf; result is\n\ a non-negative mpf roughly equal to abs(x-y)/((abs(x)+abs(y))/2).\n\ "; static char doc_reldiffg[] = "\ reldiff(x,y): returns the relative difference between x and y,\n\ where x and y can be any numbers and get coerced to mpf; result is\n\ a non-negative mpf roughly equal to abs(x-y)/((abs(x)+abs(y))/2).\n\ "; static PyObject * Pympf_doreldiff(PyObject *self, PyObject *args) { PympfObject *op; PyObject *res; SELF_MPF_ONE_ARG_CONVERTED(&op); assert(Pympf_Check(self)); res = Pympf_reldiff((PyObject*)self, (PyObject*)op); Py_DECREF(self); Py_DECREF((PyObject*)op); return res; } static char doc_fsignm[]="\ x.sign(): returns -1, 0, or +1, if x is negative, 0, positive.\n\ "; static char doc_fsigng[]="\ fsign(x): returns -1, 0, or +1, if x is negative, 0, positive;\n\ x must be an mpf, or else gets coerced to one.\n\ "; static PyObject * Pympf_sign(PyObject *self, PyObject *args) { long sign; SELF_MPF_NO_ARG; assert(Pympf_Check(self)); sign = (long) mpf_sgn(Pympf_AS_MPF(self)); Py_DECREF(self); return Py2or3Int_FromLong(sign); } /* random-number issues -- TODO: repackage as separate functions */ static char doc_rand[]="\ rand(opt[,arg]): expose various GMP random-number operations,\n\ depending on value of parameter 'opt' (a string) -- arg is\n\ normally an int or mpz (or else gets coerced to mpz), but\n\ must be a Python mutable sequence when opt is 'shuf':\n\ 'init': initialize random-state to support arg bits of 'good\n\ randomness', for arg between 1 and 128 (default 32).\n\ May be called again to change this 'random-quality'.\n\ 'qual': returns the number-of-bits-of-good-randomness (0 if\n\ the random-generator not yet initialized), arg ignored.\n\ 'seed': set/reset random-state's seed to arg.\n\ 'save': get random-state seed (for saving) - arg is ignored.\n\ 'next': get random mpz, 0 (included) to arg (excluded)\n\ (default range is 0..2**31).\n\ 'floa': get random mpf, range 0<=x<1, with arg meaningful bits\n\ (default, if arg missing or 0, is current 'random quality').\n\ 'shuf': random shuffle of Python list (or other mutable\n\ sequence) 'arg'; shuffle is in-place, None returned.\n\ "; static gmp_randstate_t randstate; static int randinited=0; static int randquality=0; #if ((__GNU_MP_VERSION==5) || ((__GNU_MP_VERSION==4) && (__GNU_MP_VERSION_MINOR>=2))) # define do_randinit(state, size) gmp_randinit_lc_2exp_size(state, size) # define SEEDOF(x) ( *(mpz_t*)((x)->_mp_seed->_mp_d) ) #else # define do_randinit(state, size) gmp_randinit(state, GMP_RAND_ALG_LC, size) # if (__GNU_MP_VERSION>=4) # define SEEDOF(x) ((x)->_mp_seed) # else # define SEEDOF(x) ((x)->seed) # endif #endif static int randbits(PyObject* arg) { int req = arg?mpz_get_si(Pympz_AS_MPZ(arg)):0; return req?req:randquality; } static int randinit(int size) { if(size==-1) size = 32; if(size<=0 || size>128) { PyErr_SetString(PyExc_ValueError, "size must be in 1..128"); return 0; } if(randinited) gmp_randclear(randstate); do_randinit(randstate, size); randquality = size; randinited = 1; return 1; } static PyObject *random_shuffle(PyObject* seq) { Py_ssize_t i, j; Py_ssize_t len = PySequence_Length(seq); PyObject* result; mpz_t temp1, temp2; mpz_inoc(temp1); mpz_inoc(temp2); mpz_set_si(temp1,len); result = Py_BuildValue(""); for(i=0; i<(len-1); ++i) { mpz_urandomm(temp2, randstate, temp1); j = mpz_get_si(temp2); if(j!=0) { int rc; PyObject* temp = PySequence_GetItem(seq, i); rc = PySequence_SetItem(seq, i, PySequence_GetItem(seq, i+j)); if(!rc) { rc = PySequence_SetItem(seq, i+j, temp); } if(rc) { Py_DECREF(result); result = 0; break; } } mpz_sub_ui(temp1, temp1, 1); } mpz_cloc(temp1); mpz_cloc(temp2); return result; } static PyObject * Pygmpy_rand(PyObject *self, PyObject *args) { char* opt; int iseq=0; PyObject* arg=0; PyObject* result=0; if(!PyArg_ParseTuple(args, "s|O&", &opt, Pympz_convert_arg, &arg)) { int retry = PyArg_ParseTuple(args, "sO", &opt, &arg); if(retry && 0==strncmp(opt,"shuf",4) && PySequence_Check(arg)) { PyErr_Clear(); iseq=1; Py_INCREF(arg); } else { return 0; } } assert(!arg || iseq || Pympz_Check(arg)); if(0==strncmp(opt,"init",4)) { int ok = randinit(arg?mpz_get_si(Pympz_AS_MPZ(arg)):-1); if(ok) result = Py_BuildValue(""); } else if(0==strncmp(opt,"qual",4)) { result = Py_BuildValue("i", randquality); } else if(0==strncmp(opt,"seed",4)) { int ok=1; if(!randinited) { ok = randinit(-1); } if(ok) { if(arg) gmp_randseed(randstate, Pympz_AS_MPZ(arg)); else gmp_randseed_ui(randstate, rand()); result = Py_BuildValue(""); } } else if(0==strncmp(opt,"save",4)) { if(!randinited) { PyErr_SetString(PyExc_RuntimeError, "can't save before init"); } else { PympzObject *resob = Pympz_new(); if(resob) { mpz_set(resob->z, SEEDOF(randstate)); result = (PyObject*)resob; } } } else if(0==strncmp(opt,"next",4)) { int ok=1; if(!randinited) { ok = randinit(-1); } if(ok) { PympzObject *resob = Pympz_new(); if(resob) { if(arg) mpz_urandomm(resob->z, randstate, Pympz_AS_MPZ(arg)); else mpz_urandomb(resob->z, randstate, 31); result = (PyObject*)resob; } } } else if(0==strncmp(opt,"floa",4)) { int ok=1; if(!randinited) { ok = randinit(-1); } if(ok) { int bits = randbits(arg); PympfObject *resob = Pympf_new(bits); if(bits>0 && resob) { mpf_urandomb(resob->f, randstate, bits); Pympf_normalize(resob); result = (PyObject*)resob; } else if(bits<=0) { if(resob) mpf_clear(resob->f); PyErr_SetString(PyExc_ValueError, "'floa' needs arg>=0"); } } } else if(0==strncmp(opt,"shuf",4)) { if(!iseq) { PyErr_SetString(PyExc_TypeError, "'shuf' needs mutable sequence"); } else { int ok=1; if(!randinited) { ok = randinit(-1); } if(ok) { result = random_shuffle(arg); } } } else { char buff[128]; sprintf(buff,"unknown option '%s'",opt); PyErr_SetString(PyExc_ValueError, buff); } if(arg) { Py_DECREF(arg); } return result; } /* method-tables */ #if PY_MAJOR_VERSION >= 3 static PyNumberMethods mpz_number_methods = { (binaryfunc) Pympany_add, /* binaryfunc nb_add; */ (binaryfunc) Pympany_sub, /* binaryfunc nb_subtract; */ (binaryfunc) Pympany_mul, /* binaryfunc nb_multiply; */ (binaryfunc) Pympany_rem, /* binaryfunc nb_remaider; */ (binaryfunc) Pympany_divmod, /* binaryfunc nb_divmod; */ (ternaryfunc) Pympany_pow, /* ternaryfunc nb_power; */ (unaryfunc) Pympz_neg, /* unaryfunc nb_negative; */ (unaryfunc) Pympz_pos, /* unaryfunc nb_positive; */ (unaryfunc) Pympz_abs, /* unaryfunc nb_absolute; */ (inquiry) Pympz_nonzero, /* inquiry nb_bool; */ (unaryfunc) Pympz_com, /* unaryfunc nb_invert; */ (binaryfunc) Pympz_lshift, /* binaryfunc nb_lshift; */ (binaryfunc) Pympz_rshift, /* binaryfunc nb_rshift; */ (binaryfunc) Pympz_and, /* binaryfunc nb_and; */ (binaryfunc) Pympz_xor, /* binaryfunc nb_xor; */ (binaryfunc) Pympz_ior, /* binaryfunc nb_or; */ (unaryfunc) Pympz2PyLong, /* unaryfunc nb_int */ 0, /* void *nb_reserved; */ (unaryfunc) Pympz2PyFloat, /* unaryfunc nb_float; */ (binaryfunc) Pympz_inplace_add, /* binaryfunc nb_inplace_add; */ (binaryfunc) Pympz_inplace_sub, /* binaryfunc nb_inplace_subtract; */ (binaryfunc) Pympz_inplace_mul, /* binaryfunc nb_inplace_multiply; */ (binaryfunc) Pympz_inplace_rem, /* binaryfunc nb_inplace_remainder; */ (ternaryfunc) Pympz_inplace_pow, /* ternaryfunc nb_inplace_power; */ (binaryfunc) Pympz_inplace_lshift, /* binaryfunc nb_inplace_lshift; */ (binaryfunc) Pympz_inplace_rshift, /* binaryfunc nb_inplace_rshift; */ 0, /* binaryfunc nb_inplace_and; */ 0, /* binaryfunc nb_inplace_xor; */ 0, /* binaryfunc nb_inplace_or; */ (binaryfunc) Pympany_floordiv, /* binaryfunc nb_floor_divide; */ (binaryfunc) Pympany_truediv, /* binaryfunc nb_true_divide; */ (binaryfunc) Pympz_inplace_floordiv, /* binaryfunc nb_inplace_floor_divide; */ 0, /* binaryfunc nb_inplace_true_divide; */ (unaryfunc) Pympz_To_Integer, /* unaryfunc nb_index; */ }; #else static PyNumberMethods mpz_number_methods = { (binaryfunc) Pympany_add, (binaryfunc) Pympany_sub, (binaryfunc) Pympany_mul, (binaryfunc) Pympany_div2, (binaryfunc) Pympany_rem, (binaryfunc) Pympany_divmod, (ternaryfunc) Pympany_pow, (unaryfunc) Pympz_neg, (unaryfunc) Pympz_pos, /* nb_positive */ (unaryfunc) Pympz_abs, (inquiry) Pympz_nonzero, (unaryfunc) Pympz_com, (binaryfunc) Pympz_lshift, (binaryfunc) Pympz_rshift, (binaryfunc) Pympz_and, (binaryfunc) Pympz_xor, (binaryfunc) Pympz_ior, (coercion) 0, (unaryfunc) Pympz_To_Integer, (unaryfunc) Pympz2PyLong, (unaryfunc) Pympz2PyFloat, (unaryfunc) Pympz_oct, (unaryfunc) Pympz_hex, (binaryfunc) Pympz_inplace_add, /* binaryfunc nb_inplace_add; */ (binaryfunc) Pympz_inplace_sub, /* binaryfunc nb_inplace_subtract; */ (binaryfunc) Pympz_inplace_mul, /* binaryfunc nb_inplace_multiply; */ 0, /* binaryfunc nb_inplace_divide; */ (binaryfunc) Pympz_inplace_rem, /* binaryfunc nb_inplace_remainder; */ (ternaryfunc) Pympz_inplace_pow, /* ternaryfunc nb_inplace_power; */ (binaryfunc) Pympz_inplace_lshift, /* binaryfunc nb_inplace_lshift; */ (binaryfunc) Pympz_inplace_rshift, /* binaryfunc nb_inplace_rshift; */ 0, /* binaryfunc nb_inplace_and; */ 0, /* binaryfunc nb_inplace_xor; */ 0, /* binaryfunc nb_inplace_or; */ (binaryfunc) Pympany_floordiv, /* binaryfunc nb_floor_divide; */ (binaryfunc) Pympany_truediv, /* binaryfunc nb_true_divide; */ (binaryfunc) Pympz_inplace_floordiv, /* binaryfunc nb_inplace_floor_divide; */ 0, /* binaryfunc nb_inplace_true_divide; */ #if Py_TPFLAGS_HAVE_INDEX (unaryfunc) Pympz_To_Integer, /* unaryfunc nb_index; */ #endif }; #endif #if PY_MAJOR_VERSION >= 3 static PyNumberMethods mpq_number_methods = { (binaryfunc) Pympany_add, /* binaryfunc nb_add; */ (binaryfunc) Pympany_sub, /* binaryfunc nb_subtract; */ (binaryfunc) Pympany_mul, /* binaryfunc nb_multiply; */ (binaryfunc) Pympany_rem, /* binaryfunc nb_remaider; */ (binaryfunc) Pympany_divmod, /* binaryfunc nb_divmod; */ (ternaryfunc) Pympany_pow, /* ternaryfunc nb_power; */ (unaryfunc) Pympq_neg, /* unaryfunc nb_negative; */ (unaryfunc) Pympq_pos, /* unaryfunc nb_positive; */ (unaryfunc) Pympq_abs, /* unaryfunc nb_absolute; */ (inquiry) Pympq_nonzero, /* inquiry nb_bool; */ 0, /* unaryfunc nb_invert; */ 0, /* binaryfunc nb_lshift; */ 0, /* binaryfunc nb_rshift; */ 0, /* binaryfunc nb_and; */ 0, /* binaryfunc nb_xor; */ 0, /* binaryfunc nb_or; */ (unaryfunc) Pympq2PyLong, /* unaryfunc nb_int */ 0, /* void *nb_reserved; */ (unaryfunc) Pympq2PyFloat, /* unaryfunc nb_float; */ 0, /* binaryfunc nb_inplace_add; */ 0, /* binaryfunc nb_inplace_subtract; */ 0, /* binaryfunc nb_inplace_multiply; */ 0, /* binaryfunc nb_inplace_remainder; */ 0, /* ternaryfunc nb_inplace_power; */ 0, /* binaryfunc nb_inplace_lshift; */ 0, /* binaryfunc nb_inplace_rshift; */ 0, /* binaryfunc nb_inplace_and; */ 0, /* binaryfunc nb_inplace_xor; */ 0, /* binaryfunc nb_inplace_or; */ (binaryfunc) Pympany_floordiv, /* binaryfunc nb_floor_divide; */ (binaryfunc) Pympany_truediv, /* binaryfunc nb_true_divide; */ 0, /* binaryfunc nb_inplace_floor_divide; */ 0, /* binaryfunc nb_inplace_true_divide; */ 0, /* unaryfunc nb_index; */ }; #else static PyNumberMethods mpq_number_methods = { (binaryfunc) Pympany_add, (binaryfunc) Pympany_sub, (binaryfunc) Pympany_mul, (binaryfunc) Pympany_div2, (binaryfunc) Pympany_rem, (binaryfunc) Pympany_divmod, (ternaryfunc) Pympany_pow, (unaryfunc) Pympq_neg, (unaryfunc) Pympq_pos, /* nb_positive */ (unaryfunc) Pympq_abs, (inquiry) Pympq_nonzero, (unaryfunc) 0, /* no bit-complement */ (binaryfunc) 0, /* no left-shift */ (binaryfunc) 0, /* no right-shift */ (binaryfunc) 0, /* no bit-and */ (binaryfunc) 0, /* no bit-xor */ (binaryfunc) 0, /* no bit-ior */ (coercion) 0, (unaryfunc) Pympq2PyInt, (unaryfunc) Pympq2PyLong, (unaryfunc) Pympq2PyFloat, (unaryfunc) 0, /* no oct */ (unaryfunc) 0, /* no hex */ 0, /* binaryfunc nb_inplace_add; */ 0, /* binaryfunc nb_inplace_subtract; */ 0, /* binaryfunc nb_inplace_multiply; */ 0, /* binaryfunc nb_inplace_divide; */ 0, /* binaryfunc nb_inplace_remainder; */ 0, /* ternaryfunc nb_inplace_power; */ 0, /* binaryfunc nb_inplace_lshift; */ 0, /* binaryfunc nb_inplace_rshift; */ 0, /* binaryfunc nb_inplace_and; */ 0, /* binaryfunc nb_inplace_xor; */ 0, /* binaryfunc nb_inplace_or; */ (binaryfunc) Pympany_floordiv, /* binaryfunc nb_floor_divide; */ (binaryfunc) Pympany_truediv, /* binaryfunc nb_true_divide; */ 0, /* binaryfunc nb_inplace_floor_divide; */ 0, /* binaryfunc nb_inplace_true_divide; */ }; #endif static PyGetSetDef Pympq_getseters[] = { { "numerator", (getter)Pympq_getnumer, NULL, "numerator", NULL }, { "denominator", (getter)Pympq_getdenom, NULL, "denominator", NULL }, {NULL} }; #if PY_MAJOR_VERSION >= 3 static PyNumberMethods mpf_number_methods = { (binaryfunc) Pympany_add, /* binaryfunc nb_add; */ (binaryfunc) Pympany_sub, /* binaryfunc nb_subtract; */ (binaryfunc) Pympany_mul, /* binaryfunc nb_multiply; */ (binaryfunc) Pympany_rem, /* binaryfunc nb_remaider; */ (binaryfunc) Pympany_divmod, /* binaryfunc nb_divmod; */ (ternaryfunc) Pympany_pow, /* ternaryfunc nb_power; */ (unaryfunc) Pympf_neg, /* unaryfunc nb_negative; */ (unaryfunc) Pympf_pos, /* unaryfunc nb_positive; */ (unaryfunc) Pympf_abs, /* unaryfunc nb_absolute; */ (inquiry) Pympf_nonzero, /* inquiry nb_bool; */ 0, /* unaryfunc nb_invert; */ 0, /* binaryfunc nb_lshift; */ 0, /* binaryfunc nb_rshift; */ 0, /* binaryfunc nb_and; */ 0, /* binaryfunc nb_xor; */ 0, /* binaryfunc nb_or; */ (unaryfunc) Pympf2PyLong, /* unaryfunc nb_int */ 0, /* void *nb_reserved; */ (unaryfunc) Pympf2PyFloat, /* unaryfunc nb_float; */ 0, /* binaryfunc nb_inplace_add; */ 0, /* binaryfunc nb_inplace_subtract; */ 0, /* binaryfunc nb_inplace_multiply; */ 0, /* binaryfunc nb_inplace_remainder; */ 0, /* ternaryfunc nb_inplace_power; */ 0, /* binaryfunc nb_inplace_lshift; */ 0, /* binaryfunc nb_inplace_rshift; */ 0, /* binaryfunc nb_inplace_and; */ 0, /* binaryfunc nb_inplace_xor; */ 0, /* binaryfunc nb_inplace_or; */ (binaryfunc) Pympany_floordiv, /* binaryfunc nb_floor_divide; */ (binaryfunc) Pympany_truediv, /* binaryfunc nb_true_divide; */ 0, /* binaryfunc nb_inplace_floor_divide; */ 0, /* binaryfunc nb_inplace_true_divide; */ 0, /* unaryfunc nb_index; */ }; #else static PyNumberMethods mpf_number_methods = { (binaryfunc) Pympany_add, (binaryfunc) Pympany_sub, (binaryfunc) Pympany_mul, (binaryfunc) Pympany_div2, (binaryfunc) Pympany_rem, (binaryfunc) Pympany_divmod, (ternaryfunc) Pympany_pow, (unaryfunc) Pympf_neg, (unaryfunc) Pympf_pos, /* nb_positive */ (unaryfunc) Pympf_abs, (inquiry) Pympf_nonzero, (unaryfunc) 0, /* no bit-complement */ (binaryfunc) 0, /* no left-shift */ (binaryfunc) 0, /* no right-shift */ (binaryfunc) 0, /* no bit-and */ (binaryfunc) 0, /* no bit-xor */ (binaryfunc) 0, /* no bit-ior */ (coercion) 0, /* was coerce */ (unaryfunc) Pympf2PyInt, (unaryfunc) Pympf2PyLong, (unaryfunc) Pympf2PyFloat, (unaryfunc) 0, /* no oct */ (unaryfunc) 0, /* no hex */ 0, /* binaryfunc nb_inplace_add; */ 0, /* binaryfunc nb_inplace_subtract; */ 0, /* binaryfunc nb_inplace_multiply; */ 0, /* binaryfunc nb_inplace_divide; */ 0, /* binaryfunc nb_inplace_remainder; */ 0, /* ternaryfunc nb_inplace_power; */ 0, /* binaryfunc nb_inplace_lshift; */ 0, /* binaryfunc nb_inplace_rshift; */ 0, /* binaryfunc nb_inplace_and; */ 0, /* binaryfunc nb_inplace_xor; */ 0, /* binaryfunc nb_inplace_or; */ (binaryfunc) Pympany_floordiv, /* binaryfunc nb_floor_divide; */ (binaryfunc) Pympany_truediv, /* binaryfunc nb_true_divide; */ 0, /* binaryfunc nb_inplace_floor_divide; */ 0, /* binaryfunc nb_inplace_true_divide; */ }; #endif static PyMethodDef Pygmpy_methods [] = { { "version", Pygmpy_get_version, 1, doc_version }, { "_cvsid", Pygmpy_get_cvsid, 1, doc_cvsid }, { "gmp_version", Pygmpy_get_gmp_version, 1, doc_gmp_version }, { "mpir_version", Pygmpy_get_mpir_version, 1, doc_mpir_version }, { "license", Pygmpy_get_license, 1, doc_license }, { "gmp_limbsize", Pygmpy_get_gmp_limbsize, 1, doc_gmp_limbsize }, { "set_debug", Pygmpy_set_debug, 1, doc_set_debug }, { "set_minprec", Pygmpy_set_minprec, 1, doc_set_minprec }, { "set_tagoff", Pygmpy_set_tagoff, 1, doc_set_tagoff }, { "set_fcoform", Pygmpy_set_fcoform, 1, doc_set_fcoform }, { "get_cache", Pygmpy_get_cache, 1, doc_get_cache }, { "set_cache", Pygmpy_set_cache, 1, doc_set_cache }, { "mpz", Pygmpy_mpz, 1, doc_mpz }, { "mpq", Pygmpy_mpq, 1, doc_mpq }, { "mpf", Pygmpy_mpf, 1, doc_mpf }, { "gcd", Pygmpy_gcd, 1, doc_gcd }, { "gcdext", Pygmpy_gcdext, 1, doc_gcdext }, { "lcm", Pygmpy_lcm, 1, doc_lcm }, { "divm", Pygmpy_divm, 1, doc_divm }, { "fac", Pygmpy_fac, 1, doc_fac }, { "fib", Pygmpy_fib, 1, doc_fib }, { "pi", Pygmpy_pi, 1, doc_pi }, { "rand", Pygmpy_rand, 1, doc_rand }, { "sqrt", Pympz_sqrt, 1, doc_sqrtg }, { "sqrtrem", Pympz_sqrtrem, 1, doc_sqrtremg }, { "is_square", Pympz_is_square, 1, doc_is_squareg }, { "is_power", Pympz_is_power, 1, doc_is_powerg }, { "is_prime", Pympz_is_prime, 1, doc_is_primeg }, { "next_prime", Pympz_next_prime, 1, doc_next_primeg }, { "jacobi", Pympz_jacobi, 1, doc_jacobig }, { "legendre", Pympz_legendre, 1, doc_legendreg }, { "kronecker", Pympz_kronecker, 1, doc_kroneckerm }, { "binary", Pympz_binary, 1, doc_binaryg }, { "digits", Pympz_digits, 1, doc_digitsg }, { "numdigits", Pympz_numdigits, 1, doc_numdigitsg }, { "bit_length", Pympz_bit_length, 1, doc_bit_lengthg }, { "lowbits", Pympz_lowbits, 1, doc_lowbitsg }, { "getbit", Pympz_getbit, 1, doc_getbitg }, { "setbit", Pympz_setbit, 1, doc_setbitg }, { "popcount", Pympz_popcount, 1, doc_popcountg }, { "hamdist", Pympz_hamdist, 1, doc_hamdistg }, { "divexact", Pympz_divexact, 1, doc_divexactg }, { "cdivmod", Pympz_cdivmod, 1, doc_cdivmodg }, { "fdivmod", Pympz_fdivmod, 1, doc_fdivmodg }, { "tdivmod", Pympz_tdivmod, 1, doc_tdivmodg }, { "scan0", Pympz_scan0, 1, doc_scan0g }, { "scan1", Pympz_scan1, 1, doc_scan1g }, { "root", Pympz_root, 1, doc_rootg }, { "bincoef", Pympz_bincoef, 1, doc_bincoefg }, { "comb", Pympz_bincoef, 1, doc_combg }, { "remove", Pympz_remove, 1, doc_removeg }, { "invert", Pympz_invert, 1, doc_invertg }, { "_copy", Pympz_copy, 1 }, { "sign", Pympz_sign, 1, doc_signg }, { "fsqrt", Pympf_sqrt, 1, doc_fsqrtg }, { "qsign", Pympq_sign, 1, doc_qsigng }, { "numer", Pympq_numer, 1, doc_numerg }, { "denom", Pympq_denom, 1, doc_denomg }, { "qbinary", Pympq_binary, 1, doc_qbinaryg }, { "qdigits", Pympq_digits, 1, doc_qdigitsg }, { "_qcopy", Pympq_copy, 1 }, { "qsign", Pympq_sign, 1, doc_qsigng }, { "qdiv", Pympq_qdiv, 1, doc_qdivg }, { "reldiff", Pympf_doreldiff, 1, doc_reldiffg }, { "fbinary", Pympf_binary, 1, doc_fbinaryg }, { "fdigits", Pympf_digits, 1, doc_fdigitsg }, { "fround", Pympf_round, 1, doc_froundg }, { "getprec", Pympf_getprec, 1, doc_getprecg }, { "getrprec", Pympf_getrprec, 1, doc_getrprecg }, { "_fcopy", Pympf_copy, 1 }, { "fsign", Pympf_sign, 1, doc_fsigng }, { "f2q", Pympf_f2q, 1, doc_f2qg }, { "ceil", Pympf_ceil, 1, doc_ceilg }, { "floor", Pympf_floor, 1, doc_floorg }, { "trunc", Pympf_trunc, 1, doc_truncg }, { "_mpmath_normalize", Pympz_mpmath_normalize, 1, doc_mpmath_normalizeg }, { "_mpmath_create", Pympz_mpmath_create, 1, doc_mpmath_createg }, { "_mpmath_trim", Pympz_mpmath_trim, 1, doc_mpmath_trimg }, { "_mpmath_add", Pympz_mpmath_add, 1, doc_mpmath_addg }, { "_mpmath_mult", Pympz_mpmath_mult, 1, doc_mpmath_multg }, { "_mpmath_div", Pympz_mpmath_div, 1, doc_mpmath_divg }, { "_mpmath_sqrt", Pympz_mpmath_sqrt, 1, doc_mpmath_sqrtg }, { NULL, NULL, 1} }; static PyMethodDef Pympz_methods [] = { { "sqrt", Pympz_sqrt, 1, doc_sqrtm }, { "sqrtrem", Pympz_sqrtrem, 1, doc_sqrtremm }, { "is_square", Pympz_is_square, 1, doc_is_squarem }, { "is_power", Pympz_is_power, 1, doc_is_powerm }, { "is_prime", Pympz_is_prime, 1, doc_is_primem }, { "next_prime", Pympz_next_prime, 1, doc_next_primem }, { "jacobi", Pympz_jacobi, 1, doc_jacobim }, { "legendre", Pympz_legendre, 1, doc_legendrem }, { "kronecker", Pympz_kronecker, 1, doc_kroneckerg }, { "binary", Pympz_binary, 1, doc_binarym }, { "digits", Pympz_digits, 1, doc_digitsm }, { "numdigits", Pympz_numdigits, 1, doc_numdigitsm }, { "bit_length", Pympz_bit_length, 1, doc_bit_lengthm }, { "lowbits", Pympz_lowbits, 1, doc_lowbitsm }, { "getbit", Pympz_getbit, 1, doc_getbitm }, { "setbit", Pympz_setbit, 1, doc_setbitm }, { "popcount", Pympz_popcount, 1, doc_popcountm }, { "hamdist", Pympz_hamdist, 1, doc_hamdistm }, { "scan0", Pympz_scan0, 1, doc_scan0m }, { "scan1", Pympz_scan1, 1, doc_scan1m }, { "root", Pympz_root, 1, doc_rootm }, { "bincoef", Pympz_bincoef, 1, doc_bincoefm }, { "comb", Pympz_bincoef, 1, doc_combm }, { "remove", Pympz_remove, 1, doc_removem }, { "invert", Pympz_invert, 1, doc_invertm }, { "_copy", Pympz_copy, 1 }, { "sign", Pympz_sign, 1, doc_signm }, { "qdiv", Pympq_qdiv, 1, doc_qdivm }, { NULL, NULL, 1 } }; static PyMethodDef Pympq_methods [] = { { "sign", Pympq_sign, 1, doc_qsignm }, { "numer", Pympq_numer, 1, doc_numerm }, { "denom", Pympq_denom, 1, doc_denomm }, { "_copy", Pympq_copy, 1 }, { "binary", Pympq_binary, 1, doc_qbinarym }, { "digits", Pympq_digits, 1, doc_qdigitsm }, { "qdiv", Pympq_qdiv, 1, doc_qdivm }, { NULL, NULL, 1 } }; static PyMethodDef Pympf_methods [] = { { "reldiff", Pympf_doreldiff, 1, doc_reldiffm }, { "binary", Pympf_binary, 1, doc_fbinarym }, { "digits", Pympf_digits, 1, doc_fdigitsm }, { "round", Pympf_round, 1, doc_froundm }, { "getprec", Pympf_getprec, 1, doc_getprecm }, { "getrprec", Pympf_getrprec, 1, doc_getrprecm }, { "setprec", Pympf_setprec, 1, doc_setprecm }, { "_copy", Pympf_copy, 1 }, { "sign", Pympf_sign, 1, doc_fsignm }, { "sqrt", Pympf_sqrt, 1, doc_fsqrtm }, { "qdiv", Pympq_qdiv, 1, doc_qdivm }, { "f2q", Pympf_f2q, 1, doc_f2qm }, { "ceil", Pympf_ceil, 1, doc_ceilm }, { "floor", Pympf_floor, 1, doc_floorm }, { "trunc", Pympf_trunc, 1, doc_truncm }, { NULL, NULL, 1 } }; static PyTypeObject Pympz_Type = { /* PyObject_HEAD_INIT(&PyType_Type) */ #if PY_MAJOR_VERSION >= 3 PyVarObject_HEAD_INIT(0, 0) #else PyObject_HEAD_INIT(0) 0, /* ob_size */ #endif "mpz", /* tp_name */ sizeof(PympzObject), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ (destructor) Pympz_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_reserved */ (reprfunc) Pympz2repr, /* tp_repr */ &mpz_number_methods, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ #ifdef MUTATE 0, /* tp_hash */ #else (hashfunc) Pympz_hash, /* tp_hash */ #endif 0, /* tp_call */ (reprfunc) Pympz2str, /* tp_str */ 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ #if PY_MAJOR_VERSION >= 3 Py_TPFLAGS_DEFAULT, /* tp_flags */ #else Py_TPFLAGS_HAVE_INDEX|Py_TPFLAGS_HAVE_RICHCOMPARE| \ Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_CLASS| \ Py_TPFLAGS_HAVE_INPLACEOPS, #endif "GNU Multi Precision signed integer", /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ (richcmpfunc)&mpany_richcompare,/* tp_richcompare */ 0, /* tp_weaklistoffset*/ 0, /* tp_iter */ 0, /* tp_iternext */ Pympz_methods, /* tp_methods */ }; static PyTypeObject Pympq_Type = { /* PyObject_HEAD_INIT(&PyType_Type) */ #if PY_MAJOR_VERSION >= 3 PyVarObject_HEAD_INIT(NULL, 0) #else PyObject_HEAD_INIT(0) 0, /* ob_size */ #endif "mpq", /* tp_name */ sizeof(PympqObject), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ (destructor) Pympq_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_reserved */ (reprfunc) Pympq2repr, /* tp_repr */ &mpq_number_methods, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ (hashfunc) Pympq_hash, /* tp_hash */ 0, /* tp_call */ (reprfunc) Pympq2str, /* tp_str */ (getattrofunc) 0, /* tp_getattro */ (setattrofunc) 0, /* tp_setattro */ 0, /* tp_as_buffer */ #if PY_MAJOR_VERSION >= 3 Py_TPFLAGS_DEFAULT, /* tp_flags */ #else Py_TPFLAGS_HAVE_RICHCOMPARE | Py_TPFLAGS_CHECKTYPES, /* tp_flags */ #endif "GNU Multi Precision rational number", /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ (richcmpfunc)&mpany_richcompare, /* tp_richcompare */ 0, /* tp_weaklistoffset*/ 0, /* tp_iter */ 0, /* tp_iternext */ Pympq_methods, /* tp_methods */ 0, /* tp_members */ Pympq_getseters, /* tp_getset */}; static PyTypeObject Pympf_Type = { /* PyObject_HEAD_INIT(&PyType_Type) */ #if PY_MAJOR_VERSION >= 3 PyVarObject_HEAD_INIT(NULL, 0) #else PyObject_HEAD_INIT(0) 0, /* ob_size */ #endif "mpf", /* tp_name */ sizeof(PympfObject), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ (destructor) Pympf_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_reserved */ (reprfunc) Pympf2repr, /* tp_repr */ &mpf_number_methods, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ (hashfunc) Pympf_hash, /* tp_hash */ 0, /* tp_call */ (reprfunc) Pympf2str, /* tp_str */ (getattrofunc) 0, /* tp_getattro */ (setattrofunc) 0, /* tp_setattro */ 0, /* tp_as_buffer */ #if PY_MAJOR_VERSION >= 3 Py_TPFLAGS_DEFAULT, /* tp_flags */ #else Py_TPFLAGS_HAVE_RICHCOMPARE|Py_TPFLAGS_CHECKTYPES, /* tp_flags */ #endif "GNU Multi Precision floating point", /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ (richcmpfunc)&mpany_richcompare, /* tp_richcompare */ 0, /* tp_weaklistoffset*/ 0, /* tp_iter */ 0, /* tp_iternext */ Pympf_methods, /* tp_methods */ }; /* Find out how many bits are significant in a double */ static unsigned get_precision(void) { #if defined(DBL_MANT_BITS) return DBL_MANT_BITS; #elif !defined(FLT_RADIX) || (FLT_RADIX!=2) # error "FLT_RADIX undefined or != 2, pls set DBL_MANT_BITS" #elif !defined(DBL_MANT_DIG) # error "DBL_MANT_DIG undefined, pls set DBL_MANT_BITS" #else return DBL_MANT_DIG; #endif #if 0 int bit; double eps; for(bit = 0, eps = 1.0; 1.0 != (1.0 + eps); bit++) eps /= 2; return bit; #endif } static void _PyInitGMP(void) { double_mantissa = get_precision(); options.minprec = double_mantissa; set_zcache(); set_qcache(); set_fcache(); set_pympzcache(); set_pympqcache(); } static char _gmpy_docs[] = "\ gmpy 1.17 - General Multiprecision arithmetic for Python:\n\ exposes functionality from the GMP or MPIR library to Python 2.4+\n\ and 3.1+.\n\ \n\ Allows creation of multiprecision integer (mpz), float (mpf),\n\ and rational (mpq) numbers, conversion between them and to/from\n\ Python numbers/strings, arithmetic, bitwise, and some other\n\ higher-level mathematical operations; also, pretty good-quality\n\ linear-congruential random number generation and shuffling.\n\ \n\ mpz has comparable functionality to Python's builtin longs, but\n\ can be faster for some operations (particularly multiplication\n\ and raising-to-power) and has many further useful and speedy\n\ functions (prime testing and generation, factorial, fibonacci,\n\ binary-coefficients, gcd, lcm, square and other roots, ...).\n\ \n\ mpf and mpq only offer basic arithmetic abilities, but they\n\ do add the ability to have floating-point numbers ensuring at\n\ least a predefined number of bits' worth of precision (and with\n\ potentially-huge or extremely-tiny magnitudes), as well as\n\ unlimited-precision rationals, with reasonably-fast operations,\n\ which are not built-in features of Python.\n\ "; /* Notes on Python 3.x support: Full support for PEP-3121 has not been * implemented. No per-module state has been defined. */ #if PY_MAJOR_VERSION >= 3 #define INITERROR return NULL static struct PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, "gmpy", _gmpy_docs, -1, /*sizeof(struct module_state) */ Pygmpy_methods, NULL, NULL, /* gmpy_traverse */ NULL, /* gmpy_clear */ NULL }; #ifdef _MSC_VER __declspec(dllexport) #endif PyObject * PyInit_gmpy(void) #else #define INITERROR return DL_EXPORT(void) initgmpy(void) #endif { PyObject* copy_reg_module = NULL; char *do_debug = getenv("GMPY_DEBUG"); #if PY_MAJOR_VERSION >= 3 static void *Pygmpy_API[Pygmpy_API_pointers]; PyObject *c_api_object; #endif if (PyType_Ready(&Pympz_Type) < 0) INITERROR; if (PyType_Ready(&Pympq_Type) < 0) INITERROR; if (PyType_Ready(&Pympf_Type) < 0) INITERROR; if (do_debug) sscanf(do_debug, "%d", &options.debug); if (options.debug) fputs( "initgmpy() called...\n", stderr ); _PyInitGMP(); #if PY_MAJOR_VERSION >= 3 gmpy_module = PyModule_Create(&moduledef); #else gmpy_module = Py_InitModule3("gmpy", Pygmpy_methods, _gmpy_docs); #endif /* Todo: Add error checking for status of gmpy_module returned above. */ #if PY_MAJOR_VERSION < 3 export_gmpy(gmpy_module); #else /* Initialize the C API pointer array */ Pygmpy_API[Pympz_Type_NUM] = (void*)&Pympz_Type; Pygmpy_API[Pympq_Type_NUM] = (void*)&Pympq_Type; Pygmpy_API[Pympf_Type_NUM] = (void*)&Pympf_Type; Pygmpy_API[Pympz_new_NUM] = (void*)Pympz_new; Pygmpy_API[Pympz_dealloc_NUM] = (void*)Pympz_dealloc; Pygmpy_API[Pympz_convert_arg_NUM] = (void*)Pympz_convert_arg; Pygmpy_API[Pympq_new_NUM] = (void*)Pympq_new; Pygmpy_API[Pympq_dealloc_NUM] = (void*)Pympq_dealloc; Pygmpy_API[Pympq_convert_arg_NUM] = (void*)Pympq_convert_arg; Pygmpy_API[Pympf_new_NUM] = (void*)Pympf_new; Pygmpy_API[Pympf_dealloc_NUM] = (void*)Pympf_dealloc; Pygmpy_API[Pympf_convert_arg_NUM] = (void*)Pympf_convert_arg; /* Create a Capsule containing the API pointer array's address */ c_api_object = PyCapsule_New((void *)Pygmpy_API, "gmpy._C_API", NULL); if (c_api_object != NULL) PyModule_AddObject(gmpy_module, "_C_API", c_api_object); #endif if (options.debug) fprintf(stderr, "gmpy_module at %p\n", (void *)gmpy_module); /* Add support for pickling. */ #if PY_MAJOR_VERSION >= 3 copy_reg_module = PyImport_ImportModule("copyreg"); if (copy_reg_module) { char* enable_pickle = "def mpz_reducer(an_mpz): return (gmpy.mpz, (an_mpz.binary(), 256))\n" "def mpq_reducer(an_mpq): return (gmpy.mpq, (an_mpq.binary(), 256))\n" "def mpf_reducer(an_mpf): return (gmpy.mpf, (an_mpf.binary(), 0, 256))\n" "copyreg.pickle(type(gmpy.mpz(0)), mpz_reducer)\n" "copyreg.pickle(type(gmpy.mpq(0)), mpq_reducer)\n" "copyreg.pickle(type(gmpy.mpf(0)), mpf_reducer)\n" ; PyObject* namespace = PyDict_New(); PyObject* result = NULL; if (options.debug) fprintf(stderr, "gmpy_module imported copyreg OK\n"); PyDict_SetItemString(namespace, "copyreg", copy_reg_module); PyDict_SetItemString(namespace, "gmpy", gmpy_module); PyDict_SetItemString(namespace, "type", (PyObject*)&PyType_Type); result = PyRun_String(enable_pickle, Py_file_input, namespace, namespace); if (result) { if (options.debug) fprintf(stderr, "gmpy_module enable pickle OK\n"); } else { if (options.debug) fprintf(stderr, "gmpy_module could not enable pickle\n"); PyErr_Clear(); } Py_DECREF(namespace); Py_XDECREF(result); } else { PyErr_Clear(); if (options.debug) fprintf(stderr, "gmpy_module could not import copyreg\n"); } #else copy_reg_module = PyImport_ImportModule("copy_reg"); if (copy_reg_module) { char* enable_pickle = "def mpz_reducer(an_mpz): return (gmpy.mpz, (an_mpz.binary(), 256))\n" "def mpq_reducer(an_mpq): return (gmpy.mpq, (an_mpq.binary(), 256))\n" "def mpf_reducer(an_mpf): return (gmpy.mpf, (an_mpf.binary(), 0, 256))\n" "copy_reg.pickle(type(gmpy.mpz(0)), mpz_reducer)\n" "copy_reg.pickle(type(gmpy.mpq(0)), mpq_reducer)\n" "copy_reg.pickle(type(gmpy.mpf(0)), mpf_reducer)\n" ; PyObject* namespace = PyDict_New(); PyObject* result = NULL; if (options.debug) fprintf(stderr, "gmpy_module imported copy_reg OK\n"); PyDict_SetItemString(namespace, "copy_reg", copy_reg_module); PyDict_SetItemString(namespace, "gmpy", gmpy_module); PyDict_SetItemString(namespace, "type", (PyObject*)&PyType_Type); result = PyRun_String(enable_pickle, Py_file_input, namespace, namespace); if (result) { if (options.debug) fprintf(stderr, "gmpy_module enable pickle OK\n"); } else { if (options.debug) fprintf(stderr, "gmpy_module could not enable pickle\n"); PyErr_Clear(); } Py_DECREF(namespace); Py_XDECREF(result); } else { PyErr_Clear(); if (options.debug) fprintf(stderr, "gmpy_module could not import copy_reg\n"); } #endif #if PY_MAJOR_VERSION >= 3 return gmpy_module; #endif } gmpy-1.17/doc/0000755000000000000000000000000012543053022011655 5ustar rootrootgmpy-1.17/doc/index.html0000666000000000000000000002211012174774726013677 0ustar rootroot Welcome to General Multiprecision PYthon Last updated on: 2008, June 22; for GMPY release: 1.04 Go to Google Code gmpy page

GMPY Project goals and strategies

The General Multiprecision PYthon project (GMPY) focuses on Python-usable modules providing multiprecision arithmetic functionality to Python programmers. The project mission includes both C and C++ Python-modules (for speed) and pure Python modules (for flexibility and convenience); it potentially includes integral, rational and floating-point arithmetic in any base. Only cross-platform functionality is of interest, at least for now.

As there are many good existing free C and C++ libraries that address these issues, it is expected that most of the work of the GMPY project will involve wrapping, and exposing to Python, exactly these existing libraries (possibly with additional "convenience" wrappers written in Python itself). For starters, we've focused on the popular (and excellent) GNU Multiple Precision library, GMP, exposing its functionality through module gmpy.

The GMPY Module

Python modules older than GMPY exposes a subset of the integral-MP (MPZ) functionality of earlier releases of the GMP library. The first GMPY goal (currently nearly reached) was to develop the gmpy module into a complete exposure of MPZ, MPF (floating-point), and MPQ (rational) functionality of current GMP (release 4), as well as auxiliary functionality such as random number generation, with full support for current Python releases (2.3 and up) and the Python 'distutils' (and also support for a "C API" allowing some level of interoperation with other C-written extension modules for Python).

Note: the module's ability to be used as a "drop-in replacement" for Python's own implementation of longs, to rebuild Python from sources in a version using GMP, was a characteristic of the gmp-module we started from, but is not a target of the gmpy project, and we have no plans to support it.

This first GMPY module is called gmpy, just like the whole project.

The extended MP floating-point facilities of MPFR will later also be considered for inclusion in gmpy (either within the same module, or as a further, separate add-on module). [[ Rooting for MPFR to be merged with GMP so we can avoid some awkwardness (but seeing no movement on this front so far) ]].

Mutability... but not for now

Early tests have shown that supporting Python 2's "in-place operation" functionality (by making MPZ, MPF and MPQ Python objects mutable) would offer a substantial performance boost.

Despite this, widespread feeling among Python cognoscenti appears to be against exposing such "mutable numbers". As a consequence, our current aim is for a first release of GMPY without mutability, to be followed at some later time by one which will also fully support in-place-mutable versions of number objects (as well as the default immutable ones), but only when explicitly and deliberately requested by a user (who can then be presumed to know what he or she is doing). Meanwhile, caching strategies are used to ameliorate performance issues, and appear to be reasonably worthwhile (so far, only MPZ and MPQ objects are subject to this caching).

We've tended to solve other debatable design issues in a similar vein, i.e., by trying to work "like Python's built-in numbers" when there was a choice and two or more alternatives made sense.

Project Status and near-future plans

The gmpy module's current release (latest current release as of 2008/10/16: 1.04) is available for download in both source and Windows-binary form, and Mac-binary form too. gmpy 1.04 exposes all of the mpz, mpq and mpf functionality that was already available in GMP 3.1, and most of the random-number generation functionality (there are no current plans to extend gmpy to expose other such functionality, although the currently experimental way in which it is architected is subject to possible future changes).

On most platforms, you will need to separately procure and install the GMP library itself to be able to build and use GMPY. Note that 4.0.1 or better is needed; take care: some Linux releases come bundled with older GMP versions, such as GMP 3, and you may have to install the latest GMP version instead -- beware also of /usr/lib vs /usr/local/lib issues.

Please read the file "windows_build.txt" for detailed instructions on compiling GMP and GMPY using the freely available MinGW tools.

[[ OLD: The exception to this need is under (32-bit) Windows, where binary-accompanied releases are the norm, and builds of GMP usable with MS VC++ 6 (the main C compiler used for Python on this platform) are traditionally hard to come by.

We started the GMPY project using a VC++ port of GMP.LIB "just found on the net", and later a port by Jorgen Lundman, but are currently relying on other volunteers to build Windows binaries since we don't have any Windows machine any more. This site does appear to offer all needed files and instructions for Windows developers who want to re-build the gmpy module from sources; the gmpy project itself just supplies a separate 'binary module' package is supplied, containing only the pre-built GMPY.PYD, for those who do not want to re-build from sources. ]]

Do note, however, that all gmpy users should download the gmpy source-package as well, as currently that is the one including gmpy documentation and unit-tests!

Currently-open issues

A still-weakish point is with the output-formatting of mpf numbers; sometimes, this formatting ends up providing a few more digits than a given number's accuracy would actually warrant (a few noise digits after a long string of trailing '0' or '9' digits), particularly when the mpf number is built from a Python float -- the accuracy situation is quite a bit better when the mpf number is built from a string.

Because of this, since release 0.6, gmpy introduced an optional 'floating-conversion format string' module-level setting: if present, float->mpf conversion goes through an intermediate formatted string (by default, it still proceeds directly, at least for now); this does ameliorate things a bit, as does the better tracking done (since 0.6, with further enhancements in 0.7) of the 'requested' precision for an mpf (as opposed to the precision the underlying GMP actually 'assigns' to it); but the issue cannot yet be considered fully solved, and may well still need some design changes in the output formatting functionality.

Unit tests are not considered a weak point any more; the over 1000 unit-tests now being run provide a decent cover of 93+% SLOC for gmpy.c, up from 72% in 0.7. The non-covered SLOCs (about 150 of gmpy.c's current 2311 executable lines out of 6205 total) are mostly disaster-tests to handle out-of-memory situations, a smattering of 'defensive programming' cases (to handle situations that 'should never happen, but'...) and some cases of the new experimental 'callbacks' facility (mostly provided for the specific use of PySymbolic, and intended to be tested by that package). We'll have to do better, eventually (presumably with some mocking approach e.g. to simulate out-of-memory situations), but, for now, this can be considered OK.

In the attempt to make gmpy as useful as can be for both stand-alone use, and also in the context of PySymbolic, a tad too many design decisions have been delayed/postponed by introducing module-level flags, letting us 'have it both ways' in the current gmpy 1.04; this has produced a somewhat unwieldy mix of module-level flag-setting and call-back functions. This whole area's architecture will neet to be revisited, including other such design-decisions yet.

Near-future plans

Future releases may have changes including: re-architecting the module-level setting functions; more elegantly formatted documentation; more timing-measurement scripts and usage-examples. Some of the currently experimental 'callbacks' will also be removed, having been proven unnecessary. All relevant GMP 4 functionality will be exposed.

No predictions on timing, though. gmpy 1.04 meets all current needs of the main author, so his motivation to work more on it is low:-). So, don't hold your breath (pitching in and helping it happen, on the other hand, _might_ be advisable, and will surely yield results:-).

Project page on code.google.com Go to Google Code gmpy page gmpy-1.17/doc/gmpydoc.txt0000666000000000000000000011112112174774726014106 0ustar rootrootgmpy module -- a complete Python 2.4+ and 3.x interface for GMP/MPIR. *Notes on history of file gmpydoc.txt* Notes for version 0.1 (pre-alpha), first one placed on sourceforge -- A. Martelli, aleaxit@yahoo.com, 00/11/06. Edited for version 0.2 (still pre-alpha), bugfixes & minor performance tweaks, 00/11/15 -- many thanks to Pearu Peterson for his contributions re 0.1 -> 0.2! Edited for version 0.3 (ditto) -- cleanup, exposing more mpz functions (almost all there...!), large performance-tweaks via caching (tx to PP for the inspiration!), some unit-tests -- **NEED MANY MORE TESTS FOR 0.4**!!! -- 00/11/18. Small edits for version 0.4 (ditto) -- just a couple more functions, and minor error-corrections -- 11/24. (Added docstrings in 0.4; would be nice to build a doc of some kind automatically from ONE place...). Edited for version 0.5 (ditto) -- documented the new functionality (mostly mpq; also: random, jacobi/legendre/ kronecker), minor cleanups & corrections -- 11/30. Editing for versions 0.6 (12/07), 0.7 (12/16), 0.8 (12/26): documented new functionalities, and performed minor cleanups & corrections, each time. Very minor editing for version 0.9 (2001/01/25). Minor editing for version 0.9b (2002/02/28). Minor editing for version 0.9c (2002/03/05). Minor editing for version 1.0 (2003/08/08). Minor editing for version 1.01 (2005/11/12); maintainer's preferred email changed to aleaxit@gmail.com . Minor editing for version 1.02 (2007/02/19). Minor editing for version 1.03 (2008/06/22). Minor editing for version 1.04 (2008/10/16). Minor editing for version 1.10 (2009/10/18) *Acknowledgments* gmpy 0.1 was based on previous versions of gmpmodule.c (for earlier Python and GMP releases) by AMK and Niels Möller (only removed feature: conditional possibility to substitute this implementation in place of Python's built-in longs; lots and lots of added features). Special thanks are due to Pearu Peterson for his MANY important inputs on design aspects, performance tweak suggestions, and bug discoveries. Thanks also to Keith Briggs for his precious feedback, and to Tim Peters, Fredrik Lundh, "and a cast of thousands" (posters to c.l.py and, in some few cases, gmpy's sf discussion groups) for their suggestions. Furthermore, thanks to Case Van Horsen, who provided the Windows binary installers for gmpy 1.01. Chip Turner and Daniel Lord helped with the changes leading to version 1.02, so, thanks to them as well! Case Van Horsen has done almost all of the work leading to version 1.03, so, SUPER thanks!-) (He's also pointed out the issues requiring the enhancements in 1.04, mainly rich comparisons, and done other changes leading from 1.03 to 1.04). *Installation and testing* Pre-requisites: Python 2.4+ or 3.x, and recent versions of GMP (http://gmplib.org) or MPIR (http://www.mpir.org). gmpy has been tested with GMP version 4.2+ and MPIR 1.2+. To build gmpy from sources, get the sources from svn (or a sources zipfile, such as gmpy-1.10.zip) from http://code.google.com/p/gmpy/source. Place the source code into a new, dedicated directory, cd to that directory (from any shell on Unix/Linux, or from Terminal on Mac OS X), and run: python setup.py install The DistUtils that come with Python take over and build and install the gmpy module for you (you may need to use 'sudo' or 'su' appropriately to actually perform the isntallation, depending on the permissions you're using on Python's site-packages). Detailed instructions for building on Windows are included in "windows_build.txt" and "win_x64_sdk_build.txt". "windows_build.txt" describes the build process using Mingw32 and MSYS and was used to build the 32-bit Windows binaries. "win_x64_sdk_build.txt" describes the build process using the Microsoft Platform SDK and was used to build the 64-bit Windows binaries. The MPIR library offers better support for Windows and is recommended. The file "mac_build.txt" contains detailed instructions for compiling GMP and GMPY on MacOSX (or getting GMP via mactools/darwintools). The sources zipfile also contains this file (gmpydoc.txt), an example C source file for a separate module that uses the C-API of gmpy to interoperate with it, a copy of the index.html for the gmpy sourceforge site, and python scripts that exemplify, show the performance of, and test, some functionality of the gmpy module. To test the installation, cd to the directory where you unpacked the gmpy sources, and run, at the command prompt: cd test (Note: use "cd test3" if you are using Python 3.x.) and then, at the next prompt: python gmpy_test.py Expected output is something like (details may differ!): """ Unit tests for gmpy 1.02 release candidate on Python 2.5 (r25:51918, Sep 19 2006, 08:49:13) [GCC 4.0.1 (Apple Computer, Inc. build 5341)] Testing gmpy 1.02 (GMP 4.2), default caching (20, 20, -2..11) gmpy_test_cvr 270 tests, 0 failures gmpy_test_rnd 26 tests, 0 failures gmpy_test_mpf 155 tests, 0 failures gmpy_test_mpq 264 tests, 0 failures gmpy_test_mpz 386 tests, 0 failures gmpy_test_dec 16 tests, 0 failures 7 items had no tests: [[ snip snip ]] 31 items passed all tests: [[ snip snip ]] 1117 tests in 38 items. 1117 passed and 0 failed. Test passed. """ Should you wish to test some specific portion, please note that each of the various modules listed at the start can also be run independently, if so desired: python gmpy_test_mpq.py python gmpy_test_mpz.py and so on, expecting output analogous to the above example. You may also run, for example, python gmpy_test_mpq.py -v to get very verbose and detailed output. However, in any case, the key issue is the 'Test passed' line at the end of each run! *PLEASE* report any failures to gmpy's maintainers, with all details you can supply on your machine, on your OS, and on your installation of GMP 4, gmpy 1.04, Python 2.3, 2.4, 2.5, or 2.6, and any other relevant issue (your C/C++ compiler & libraries, &c). *THANKS* in advance -- bug reporting and feedback is your key contribution to the gmpy project! (Reports of any _successful_ installations will also be welcome, if it's accompanied by enough details -- again, THANKS in advance!). The best way to report bugs (including unit-test failures) is via the Google Code issue tracker. *General notes on gmpy* gmpy exposes to Python three types of numbers that are implemented in GMP and MPIR: mpz unlimited-precision integers mpq unlimited-precision rationals mpf extended-precision floats See GMP documentation for general descriptions of them! GNU MP Home Page: http://gmplib.org The MPIR documentation is available from: MPIR Home Page: http://www.mpir.org Licensing: gmpy is licensed under LGPL v2 or later. MPIR is also licensed under LGPL v2 or later. GMP converted to LGPL v3 beginning with version 4.2.2. IANAL, but, summarizing, this means: other _libraries_ that are derived from gmpy must also be distributed under the LPGL (or full-GPL), as must any modifications/additions to gmpy; but, no such restriction applies on code that just _uses_ these modules/libraries (such gmpy-using code may thus be licensed in whatever way is desired). Warranty: NONE -- as usual for open-source software (see the detailed disclaimers in GMP's license)! *gmpy.mpz -- unlimited-precision integral numbers* gmpy.mpz objects have the full arithmetic abilities of Python longs (in the future, there may also be mutable versions of them [for performance], but NOT yet). Specifically, arithmetic operators + and - (unary and binary), *, / (truncating), %, **, bitwise operators such as &, |, ^, <<, >>, ~, and builtin Python functions such as divmod and pow, all work as expected on mpz objects (basically, the same way as on builtin Python longs, except that the speed can be quite different -- from 'a bit slower' for some things, up to much faster for others [such as multiplication of huge numbers]). Mixed-operand arithmetic is supported: the other operand (which must be a number of some kind) is coerced to a gmpy.mpz, unless it's of a floating type, in which case both operands are coerced into a gmpy.mpf object. Instances of the decimal.Decimal class are coerced into gmpy.mpf also. Instances of the fractions.Fraction class are coerced int gmpy.mpq. An mpz object can be built by passing to the gmpy.mpz constructor function any Python built-in, non-complex number, another mpz (this *shares* object identity, does *not* copy it -- which should be indifferent, since such objects are in any case immutable), a mpq or mpf (which gets truncated, as also a Python float does), or a string (representing the number in base 10). gmpy.mpz can also be called with TWO arguments: the first one a string representing the number in some base N, the second one, the integer N. N can be between 2 and 36, or it can be 256, which implies that the string is the _portable binary gmpy representation_ of the mpz (as produced by method .binary() of mpz objects, and function gmpy.binary() of the module). An N of 0 is also accepted, and means the string is interpreted as decimal, unless it starts with 0x (then, hexadecimal) or 0 (then, octal). When N=16 a starting a leading '0x' is also accepted, but not required; leading 0's are always accepted and ignored (they do NOT mean the rest is taken as octal!) if the base N is explicitly given as a Python int, or if it's omitted (and defaults to 10). *NOTE* that the trailing-L in a Python's "long" string representation is NOT accepted in the string argument to gmpy.mpz()! (Please note that all from-string transformations are performed by GMP or MPIR, and thus may follow slightly different conventions from normal Python ones). An mpz object can be transformed into a Python number by passing it as the argument of a call to Python's built-in number types (int, long, float, complex); it can also be formatted as an octal or hex string with Python built-in functions oct and hex. mpz objects also support the hash built-in function, and can thus be used as dictionary keys; for any Python int or long N, hash(mpz(n)) and hash(n) are equal. Other operations on mpz objects are all exposed as functions of module gmpy, and some, also, as methods of mpz objects. Unless otherwise noted, arguments to the following gmpy module functions are coerced to mpz (unless already of mpz type), and values returned from either functions or methods are also of mpz type. gmpy.binary(x) or x.binary(): returns a portable binary representation (base-256 little endian) of an mpz object, suitable for saving into a file (or db, whatever) -- this string can later be passed as the first argument to function gmpy.mpz (with a second argument with value 256) to reconstruct a copy of the original mpz object. *NOTE*: the binary format used by gmpy release 0.7 and later is not compatible with that of 0.6 and earlier, as the latter, as a design limitation, could not represent any mpz number that was < 0. gmpy.digits(x[,base]) or x.digits([base]): returns a string representing x in the given base (between 2 and 36, defaulting to 10 if omitted or zero); a leading '-' will be present if x<0, but no leading '+' if x>=0. If base is 8 or 16, a decoration of a leading '0' (or, respectively, '0x') is present (after the '-' sign, if the number is negative). gmpy.numdigits(x[,base]) or x.numdigits([base]): returns an approximation to the number of digits for x in the given base (result is either exact [guaranteed if base is a power or 2] or 1 more than actual length; space for a "sign", or leading decorations of '0' or '0x', is NOT considered). Base must be between 2 and 36, defaulting to 10 if omitted or zero. gmpy.sign(x) or x.sign(): -1, 0, or 1, depending on whether x is negative, zero, or positive. gmpy.divm(a, b, M): x such that b*x == a modulo M (will raise a ZeroDivisionError exception if no such x exists). gmpy.fac(x): factorial of x (takes O(x) time; x must be an ordinary Python non-negative integer!) gmpy.fib(x): x-th Fibonacci number (takes O(x) time; x must be an ordinary Python non-negative integer). gmpy.gcd(a,b): greatest common divisor of a and b (an mpz, >= 0). gmpy.gcdext(a, b): a tuple (g,s,t) such that g==gmpy.gcd(a,b) and g == a*s + b*t (g, s and t are all mpz). gmpy.lcm(a,b): least common multiple of a and b (an mpz, >= 0). gmpy.is_square(x) or x.is_square(): 1 iff x is a perfect square, else 0 (returns Python int). gmpy.is_power(x) or x.is_power(): 1 iff x is a perfect power (i.e., there exist a, b such that a**b==x and b>1), else 0 (returns Python int). gmpy.is_prime(x [, count]) or x.is_prime([count]): 2 if x is _certainly_ prime, 1 if x is _probably_ prime, 0 if x is _certainly_ composite; count defaults to 25 (probability of non-primality, if is_prime returns 1, is guaranteed to be no higher than 1 in 2**count). Returns Python int. NOTE: GMP believes negative numbers can be primes, and gmpy just reflects this stance (cfr discussion at http://www.utm.edu/research/primes/notes/faq/negative_primes.html) gmpy.next_prime(x) or x.next_prime(): returns mpz that is the lowest prime > x; *probabilistic* algorithm for prime-determination (see is_prime). gmpy.sqrt(x) or x.sqrt(): integer square-root of non negative number (truncating, unless is_square(x)). gmpy.sqrtrem(x) or x.sqrtrem(): tuple (s,t) such that s==gmpy.sqrt(x) and x==s*s+t. (s and t are mpz, >= 0). gmpy.root(x,n) or x.root(n): tuple (s,b) such that s is the truncated nth-root of x, b!=0 if s is the _exact_ root (i.e. x==s**n); n must be an ordinary Python int, >0. (s is an mpz, b a Python int). gmpy.bincoef(x, N) or x.bincoef(N): binomial coefficient "x over N"; N must be an ordinary Python int, >=0! (x may be < 0 , see Knuth vol 1, sect 1.2.6, part G). [Also known as: gmpy.comb(x, N) or x.comb(N), since the binomial coefficient is also the number of different combinations of x objects taken N at a time, with ordering ignored]. gmpy.remove(x, f) or x.remove(f): "remove factors": returns a two-element tuple (y,m), where y, an mpz, is x without any factor of f, and m (an ordinary Python int) is the multiplicity of f in x (e.g.: m==0 and y==x unless x%f==0; and in any case, it's ensured that x==y*(f**m) and that y%f!=0). gmpy.invert(x, m) or x.invert(m): modulo-inverse; returns an y such that x*y mod m = 1, if one exists, else 0 (returns an mpz in either case). gmpy.lowbits(x, n) or x.lowbits(n): returns the n lowest bits of x (n must be an ordinary Python int, >0; returns an mpz, >= 0). Note that x<0 is assumed to be in 2's complement notation (i.e., "extended on the left" with infinite 1-bits); so, for example, for any n>0, gmpy.lowbits(-1,n) returns an mpz>0 with the lowest n bits set to 1, i.e., (2**n)-1. gmpy.setbit(x, n, v) or x.setbit(n, v), n being a bitindex (0 and up, ordinary Python int) and v an int value (0 or 1, default 1): returns a copy of x with bit n set to v (mpz's are not mutable -- yet...!). [Any value v != 0 is equivalent to v=1, i.e., the bit is 'set'; so, for example, gmpy.setbit(0,n,-4) for any n>=0 returns an mpz worth 2**n]. gmp.getbit(x, n) or x.getbit(n), n being a bitindex (0 and up, ordinary Python int): returns an int which is 0 or 1, same as the value of bit n of x. (See note on gmpy.lowbits for x<0). gmpy.scan0(x [, n]) or x.scan0([n]): returns the bit index of the next 0-bit starting at bit n (default 0); n must be an ordinary Python int, >=0; returns a Python int (-1 if there is no such bit-index, which can only happen for an x<0, which notionally is extended with infinite 1-bits). gmpy.scan1(x [, n]) or x.scan1([n]): returns the bit index of the next 1-bit starting at bit n (default 0); n must be an ordinary Python int, >=0; returns a Python int (-1 if there is no such bit-index, which can only happen for an x>=0, which notionally is extended with infinite 0-bits). gmpy.popcount(x) or x.popcount(): returns the "population count" (number of bits set to 1) of x; note that this is 'infinite' for x<0 (-1 is then returned). Returns a Python int. gmpy.hamdist(x,y) or x.hamdist(y): returns the Hamming-distance |x,y| if both >=0 or both < 0 (returns -1 if one but not both are <0) (the hamming distance is defined as: the number of bit-positions in which the two numbers differ). Returns a Python int. Same as gmpy.popcount(x^y). gmpy._copy(x) or x._copy(): provide a separate copy of x (only relevant for future mutability of mpz... currently useless!). gmpy.divexact(x,y): returns the quotient of x divided by y. It uses a fasterr division algorithm but requires that the remainder is 0. It will return garbage if the remainder is not 0! (New in 1.04.) *gmpy module-level setting functions* [NOTE: the overall architecture of these functions is due to be reworked sooner or later, NOT backwards-compatibly]. gmpy.set_debug(flag): turns on/off debugging output from the gmpy module (returns previous setting). [Only of interest to develop/debug gmpy itself!] Argument must be an ordinary Python int: debug is set on if flag!=0, off if flag==0. Returns a Python int (0 or 1, the _previous_ setting). gmpy.set_tagoff(flag): turns off/on the 'gmpy.' prefix to the "tag" that repr() places around the string-representation of gmpy objects (returns a Python int, 0 or 1, the previous setting). gmpy. get_zcache(), set_zcache(N), get_zconst(), set_zconst(N,M), get_qcache(), set_qcache(N)...: *internal tweaks/experimental stuff*, please don't use them unless you've read the C sources and understand what they do! Not further documented here (docstrings for these functions in gmpy may give a little more detail). *gmpy.mpq -- unlimited-precision rational numbers* gmpy.mpq objects have a subset of the arithmetic abilities of Python floats (in the future, mutable versions will also be supplied, but, NOT YET!), but represent arbitrary rational numbers with no loss of precision whatsoever. [Note, in particular, that raising-to-power works only without a modulo, and, if the exponent is a fraction with a denominator D (or gets converted to one), the base must be an exact D-th power, or the operation fails raising a ValueError exception]. Mixed-operand arithmetic is supported: the other operand is coerced to a gmpy.mpq. NOTE: the % operator and the divmod built-in function are NOT supported. mpq objects also support the hash built-in function, and can thus be used as dictionary keys; for any Python int or long N, hash(mpq(n)) and hash(n) are equal. A mpq object has a _numerator_ and a _denominator_; they can be obtained by calling on an mpq object the methods .numer() and .denom() -- each method has no arguments and returns an mpz (the denominator will always be >0; the numerator can be any; also, the numerator and denominator never have any common factors; mpq corresponding to integers, including 0, always have a denominator of exactly 1). An mpq is built by passing to the gmpy.mpq constructor function any Python number, another mpq (this *shares* object identity, does *not* copy it), a mpf or mpz, or a string (representing the number in base 10). [If an mpf or float argument is passed, the mpq is built from it with an 'optimal' approach based on a Stern-Brocot tree; see also the f2q method of mpf objects, and gmpy.f2q module-level function, which differ from explicit mpq-construction in that it can return an mpz if the mpq's denominator would be 1]. gmpy.mpq can also be called with TWO arguments: the first one a string representing the number in base N, the second one, the integer N. N can be between 2 and 36, or, it can be 256, which implies that the string is the _portable binary gmpy representation_ of the mpq (as produced by method .binary() of mpq objects, and function gmpy.qbinary() of the module). gmpy.mpq is typically called with a string that contains a '/' character: the digits before it will then be taken as the numerator, those after it, as the denominator (the resulting number is normalized: denominator>0, no common factors). A ZeroDivisionError is raised if the denominator thus supplied is zero; a ValueError, if the string is otherwise invalid (e.g., '/3' or '3/'). Hex and octal representations are supported if the base N is given as 0; see above gmpy.mpz; for example, mpq('0x13/011',0) is the same as mpq(19,9). gmpy.mpq can also be called with two number arguments: the first one is taken as the numerator, the second one as the denominator (the resulting number is normalized: denominator>0, no common factors). A ZeroDivisionError is raised if the denominator thus supplied is zero. Other operations on mpq objects are all exposed as functions of modules gmpy, and some, also, as methods of mpq objects: gmpy.qbinary(x) or x.binary(): returns a portable binary representation of any mpq object. gmpy.qsign(x) or x.sign(): -1, 0, or 1, depending on whether x is negative, zero, or positive. gmpy.qdiv(x[,y]) or x.qdiv([y]), which is _also_ supplied as a method on mpz and mpf objects (which are implicitly converted to mpq's in this case): return x/y (or just x, if y is absent), as an mpz if possible (==if a resulting mpq would have a denominator of 1), else as an mpq (with a denominator > 1). The functions are optimized, so that, if x is an mpz and y is absent or 1, or if x is an mpq with a denom>1 and y is absent or 1, then the same object-identity as x is returned, so that the operation is very fast. In other words, gmpy.qdiv only ever takes substantial time if it DOES have an important job to perform, and can thus be called rather freely, even in loops, to 'normalize' numeric results. Specifically, please note that, for an x that is an mpq, x.qdiv() returns either x, if x.denom()==1, or else the same mpz as x.numer() would return; if x is an mpz, x.qdiv() returns x (so it can be used polymorphically on an x that can be either, without any performance hit). *gmpy.mpf -- variable-precision floating numbers* gmpy.mpf objects have a subset of the arithmetic abilities of Python floats (in the future, mutable versions will also be supplied, but, NOT YET!). Mixed-operand arithmetic is supported: the other operand is coerced to a gmpy.mpf, except that, if the other operand is an mpq, then both are coerced to mpq. NOTE: trigonometric and exponential functionalities on mpf objects are NOT currently supported [GMP 3.1.1 had none; waiting to expose the MPFR extensions to GMP.] mpf objects also support the hash built-in function, and can thus be used as dictionary keys; for any Python float X, hash(mpf(x)) and hash(x) are equal. Each mpf object has a _precision_ -- a number of bits of precision to which values are stored in it. The precision of all newly generated mpf's is at least that set at module level via module function gmpy.set_minprec(n); a specific mpf's precision can be set to >= n bits by x.setprec(n); it can be queried (the exact current number of bits of precision is returned) by x.getprec() or gmpy.getprec(x). The granularity of precision of current MPF's is rough; exact precision setting is one of MPFR's enhancements. To get the actual precision that was _requested_ for a given mpf object, x.getrprec() and gmpy.getrprec(x) are also supplied -- the value returned from getprec will always be greater than, or equal to, the one returned from getrprec. ** The following behavior is in new in gmpy 1.04. ** GMP only guarantees that the precision of a result is greater than or equal to the requested precision. But comparisons would use all the bits computed, regardless of whether they are accurate. This leads to situations where mpf('1.1') * mpf('1') != mpf('1.1'). Beginning with gmpy 1.04, the results of all mpf calculations are rounded to the requested precision. Note: GMP uses radix 2**32 (or 2**64) arithmetic and rounding is done on those boundaries. Let's assume we request 53 bits of precision on a 32-bit system. GMP rounds the requested precision up to 64 bits and then allocates three 32-bit words to store the mantissa. GMP also allocates one additional 32-bit word to simplify their internal operations. The additional word may or may not be present on any particular result. So in our scenario, GMP can return a mantissa with anywhere between 65 and 128 bits. The presence of the additional word caused the strange behavior with comparisons. If the additional word is present, the mantissa is rounded and the additional word is set to 0 so the effective precision is between 65 and 96 bits. ** End new section. ** An mpf is built by passing to the gmpy.mpf constructor function any Python built-in number, another mpf (this *shares* object identity, does *not* copy it -- unless specific precision is requested for the resulting mpf, see later), a mpq or mpz, or a string (representing the number in base 10, possibly with decimal point and/or exponent). If gmpy.mpf is called with a float argument, the exact steps used in conversion depend on the setting of module level option fcoform (set by gmpy.set_fcoform()). If fcoform is None, the float number is converted 'exactly' to an mpf (which often leaves spurious trailing bits from literals). If fcoform is a string, it's used as the format (left operand of %) in a formatting operation (with the float being transformed as the right operand), and the resulting intermediate string is the one that actually gets transformed to mpf (this normally gives good results with formats somewhere between '%.12e' and '%.16e', depending on the actual precision of the float being transformed). fcoform also applies to _implicit_ conversions of float to mpf, as invoked for mixed-mode arithmetic or when gmpy functions expecting an mpf argument are called with a float argument (a string could not be passed _explicitly_ here -- an explicit mpz() around it would be needed -- but it's OK if a float gets _implicitly_ converted-to-mpf-via-string in these cases, through the fcoform mechanism). An optional second argument can always be supplied to gmpy.mpf, whether the first argument is a numner or a string; if supplied, it must be a Python int, >=0. If absent or 0, the precision of the mpf that is generated is determined by default depending on the input argument (in many cases, it's the number of significant bits in machine-floats; e.g., 53 on machines using IEEE 64-bit floating point). If the second argument is supplied and > 0, it's used as the requested-precision for the resulting mpf, ignoring the bits-of-precision held or implied by the first argument. Note, that if x is an mpf with n bits of precision, gmpy.mpf(x,m) will be able to return the same object identity as x if, and only if, m==n; else, a new mpf object of the requested precision will be generated. Note that, in arithmetic operations, the bits of precision of the result are generally set to the _lowest_ number of bits-of-precision of all the operands involved. gmpy.mpf can also be called with *3* arguments: the first one a string representing the number in base N, the second one the bits of precision requested (or 0 to accept the default determination of the bits), the third one, the integer N. N can be between 2 and 36, or, it can be 256, which implies that the string is the _portable binary gmpy representation_ of the mpf (as produced by method .binary() of mpf objects, and function gmpy.fbinary() of the module). (Hex and octal decorations are *not* supported here; an N of 0 is totally equivalent to one of 10). Note that therefore, if a reasonable fcoform is set, two constructor calls such as gmpy.mpf(3.4) and gmpy.mpf('3.4') will produce the same mpf object, although the second way is faster (and does not depend on the module-level fcoform setting) and recommended as preferable to the first one. Other operations on mpf objects are all exposed as functions of modules gmpy, and some, also, as methods of mpf objects: gmpy.fbinary(x) or x.binary(): returns a portable binary representation of any mpf object. gmpy.fdigits(x[,args...]) or x.digits([args]): returns a string representing x. Arguments (must currently be passed positionally, if at all -- keywords NOT accepted!) are...: base: number-base (between 2 and 36), default 10 digits: how many digits are requested (default 0, "all of them" within x's precision; fewer than requested may be obtained, if fewer available) minexp: minimum exponent for which the number is still to be formatted in integer.fraction form (it's formatted as fraction-exponent form if exponent is lower than minexp), default 0 maxexp: maximum exponent for which the number is still to be formatted in integer.fraction form (it's formatted as fraction-exponent form if exponent is higher than maxexp), default -1 option: bitmask argument, default 0 (no options) Note that, by default, the formating is in fraction-and-exponent form: []. sign is '-' if x is negative, omitted if x>=0 is 'e' for base<=10, otherwise '@' the signed exponent (sign omitted if exponent>=0) is always expressed in base 10, whatever the base used for the significand's digits. If option's bit 1 is set, the whole result string is enclosed between "gmpy.mpf('" at the start and "')" at the end, so it can be subject to eval to recover an approximation of the original number (depending on the settings of gmpy.set_tagoff(), the starting tag may actually be shortened to just "mpf('"). The precision, in bits, is also output in this case, just before the ')', separated from the "first argument to gmpy.mpf" by a comma character (it is the same number as returned by .getrprec). If option's bit 2 is set, then minexp, maxexp, and option's bit 1, are ignored: the result is a tuple of 2 objects: first, a string made up of all the digits (and maybe a leading - sign) and nothing else; second, an integer that is the exponent to use. This can be used by Python code that wants finer-grained control on resulting string format. gmp.reldiff(x,y) or x.reldiff(y): returns the relative difference between x and y, a non-negative mpf roughly equal to abs(x-y)/((abs(x)+abs(y))/2). gmpy._fcopy(x) or x._copy(): provide a separate copy of x (only relevant for future mutability of mpf..!). gmpy.fsign(x) or x.sign(): -1, 0, or 1, depending on whether x is negative, zero, or positive. gmpy.f2q(x) or x.f2q(): like gmpy.mpq(x), but, like qdiv, will return an mpz (instead of, as normally, an mpq), if the mpq's denominator would be 1. gmpy.fsqrt(x) or x.sqrt(): square-root of non negative number x. gmpy.set_fcoform([x]): sets or resets the format with which to build the intermediate-string to be used for float->mpf conversion. If x is None, or is absent, then the format is reset, and such conversions proceed 'directly'. If x is a Python int, it must be between 1 and 30, and is used as the number of digits in the format string '%.e' (for example, set_fcoform(12) will set the format string for float-conversion to '%.12e'). Else, x must be a Python string usable as: x%f to format a float object f in some suitable way. set_fcoform also returns the previous setting of this option, None or a string. (See also the paragraph above about the float->mpf conversion mechanics, which gives more details about the way in which this format string is used by gmpy). *Experimental: function gmpy.rand* Since gmpy 0.5, the linear congruential random number generator of GMP is exposed via gmpy (with some modest added-value functionality) through function gmpy.rand. A couple options were added in 0.6. This will be refactored into separate functions in some future release. Its first parameter is a string 'opt' (4-characters, lowercase) which determines the exact functionality; it normally has a second paramenter 'arg' (which is optional for most values of 'opt') and may return either None or a significant value (an mpz, except for opt='floa', when an mpf is returned). gmpy.rand('init') Initialize the random-generator state (this is _implicitly_ called by other options of gmpy.rand, if needed, but should be explicitly called) to ensure 32 bits' randomness per each generation ('throw'). Returns None. gmpy.rand('init', arg) ditto, but ensure 'arg' bits of randomness (arg being an int between 1 and 128). This tweaks the linear congruential parameters according to the number of needed bits (it may be faster to generate just the needed number of 'good' bits). Returns None. gmpy.rand('qual') returns the current 'quality of random numbers' (the arg value passed to 'init', with a default of 32), or 0 if random number generation is not inited yet. [ignores arg, if present] gmpy.rand('seed', arg) set the current random-seed to 'arg', an mpz (or coerced to mpz). Returns None. gmpy.rand('seed') set the current random-seed 'randomly' in its turn (uses C-level function 'rand()'). Returns None. gmpy.rand('save') returns the current random-seed (an mpz) so that it can be saved (e.g. for program checkpointing) and later restored via a gmpy.rand('seed', x) call. [ignores arg, if present] gmpy.rand('next') returns a uniformly distributed random number in the range 0:2**31 (note that the UPPER end is EXCLUDED) and advances the random-number gneration by 1 step. (Basically, returns '31 random bits', if the current quality of the generator is at least 31; for lower-quality generators, upper bits tend to be "better" than less significant ones). gmpy.rand('next',arg) returns a uniformly distributed random number in the range 0:arg (note that the UPPER end is EXCLUDED) and advances the random-number generation by 1 step. Value returned is integral (mpz). gmpy.rand('floa',arg) returns a uniformly distributed random number in the range 0:1 (note that the UPPER end is EXCLUDED), with arg meaningful bits (default, if arg is 0, is current 'quality'), and advances the random-number generation by 1 step. Value returned is floating-point (mpf). gmpy.rand('floa') returns a uniformly distributed random number in the range 0:1 (note that the UPPER end is EXCLUDED), with as many meaningful bits as the current 'quality', and advances random-number generation by 1 step. Value returned is floating-point (mpf). gmpy.rand('shuf',arg) randomly shuffles mutable-sequence 'arg' (normally a list), in a way that ensures all permutations are equally likely. It advances random-number generation by len(arg)-1 steps. Returns None. *Experimental: the callbacks-facility* The "callback" facilities were removed in gmpy 1.10. The documentation is left as-is for historical reference. Since gmpy 0.8, gmpy exposes 'callback' facilities to help client-code customize the handling of what, in pure-gmpy, would be error-cases. This is mostly intended for the use of Pearu Peterson's PySymbolic package, and is not currently documented (nor tested) in great detail for general use. You are welcome to contact gmpy's maintainer directly (and/or study gmpy's C sources:-) if you think you may have use for this facility, or are interested in doing something similar in other C modules for Python use -- it IS an interesting and reasonably novel approach. To summarize: with gmpy.set_callback(name, callable), client-code may set a Python callable as a callback for gmpy in a set of situations determined by the string 'name'. For example, gmpy.set_callback('ZD', myfun) sets 'myfun' as the callback that gmpy is to use in 'zero-division' situations. When gmpy is about to raise a ZeroDivision error, it checks if the 'ZD' callback is set; if so, then, instead of raising the exception itself, it delegates everything to the callback in question, passing it the name of the gmpy function involved, the arguments it was called with, and the error-string gmpy would use if it did raise the error. It's up to the callback to either raise a ZeroDivision itself, OR return some special object to map this situation -- for example, PySymbolic may return an 'infinity' object and suppress the error. Basically, this works around Python's (excellent!) choice to adopt the terminating-model rather than the restartable one for exception handling, in a few cases of specific interest to numeric computation that's being used in a symbolic setting. Most callbacks are module-global, with one specific exception. When any gmpy function or method is trying to convert arguments to gmpy objects (mpz, mpq, mpf), and a conversion fails, all argument objects are examined, looking for a method called '__gmpy__' in any of them. If one is found, then, rather than raising an error to indicate the conversion failure, that method is called as a 'localized callback' as above. This lets other, non-gmpy objects participate in gmpy computations (if they're willing to handle all cases involving them!): Python does much of this via __coerce__ etc, and this localized-callback facility does the rest for named module-functions and methods, where normal coercion would not apply. gmpy-1.17/win_x64_sdk_build.txt0000666000000000000000000000675012174774730015223 0ustar rootroot Building MPIR and GMPY using the Windows SDK tools It is possible to build MPIR and GMPY from source on a Microsoft Windows platform using the command-line compiler that is included with the Microsoft Platform SDK. I've documented the process for a 64-bit build. The operating system was Windows XP x64. The process isn't difficult but assumes some familiarity with the command line. 1) You should have an program for processing .zip and .tar.gz archives. 2) Python should be installed on your system and the installation directory should be added to your system's PATH environment variable. 3) Install .NET Framework 2.0 or later. (This is required for the installer used by the SDK.) 4) Install the Microsoft Windows SDK. I used "Microsoft Windows SDK for Windows 7 and .NET Framework 3.5 Service Pack 1". It can be found at "http://msdn.microsoft.com/en-us/windowsserver/bb980924.aspx". This version of the SDK provides compilers that are compatible with VS2008. VS2008 is required for Python 2.6, 2.7, 3.1, and 3.2. Compiling Python extensions with another version of the SDK is not supported. Use the version appropriate for your system: X86 for a 32-bit system or AMD64 for a 64-bit system. 5) Download the current version of the YASM assembler. It can be found at "http://www.tortall.net/projects/yasm/". Again, use the version approp- riate for your system. The executable must be renamed to "yasm.exe" and copied to the SDK installation directory, typically: C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin 6) Create a directory to use for the build process. I use C:\src. mkdir c:\src 7) Download the GMPY and MPIR source code. This example uses gmpy-1.15.zip and mpir-2.5.0.tar.gz. They should be unzipped (or untarred) into c:\src. There should be c:\src\gmpy-1.15 and c:\src\mpir-2.5.0 directories in c:\src. 8) The file "yasm.rules" must be copied from c:\src\mpir-2.5.0\yasm\Mkfiles\vc9 to C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\VCProjectDefaults 9) Open a command window and enter the following commands: rem Configure the environment for 64-bit builds. rem Use "vcvars32.bat" for a 32-bit build. "C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin\vcvars64.bat" rem Set environment variable so yasm.exe can be found by the batch files. set YASMPATH=C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin rem Build mpir first. cd C:\src\mpir-2.5.0\win rem Check contents of configure.bat to see allowed options. Verify that rem all tests pass. rem 64-bit binaries were built with --cpu=k8. configure make make check rem Copy the required to a convenient location for gmpy. rem The files are located in "lib\Win32\release" for 32-bit rem build. cd c:\src\mpir-2.5.0 mkdir c:\src\lib mkdir c:\src\include xcopy /Y mpir.h c:\src\include\*.* xcopy /Y win\mpir.lib c:\src\lib\*.* rem Done with mpir, now build gmpy. cd c:\src\gmpy-1.15 rem Convince setup.py to use the SDK tools. set MSSdk=1 set DISTUTILS_USE_SDK=1 rem Build and install gmpy.pyd python setup.py build_ext -DMPIR -Ic:\src\include -Lc:\src\lib install rem Run the test suite python test\gmpy_test.py rem (Optional) Build an installer, located in c:\src\gmpy-1.15\dist. python setup.py bdist_wininst gmpy-1.17/windows_build.txt0000666000000000000000000000460212174774730014550 0ustar rootrootInstructions for compiling GMPY 1.12 for 32-bit Windows. GMPY 32-bit binaries can be compiled for the Windows operating systems using the free MinGW toolkit. The MinGW toolkit provides a Minimalist GNU for Windows environment. If you are trying to build a 64-bit version of GMPY, please refer to "win_x64_sdk_build.txt". GMPY can use either the GMP or MPIR multiple-precision library. The procedure for MPIR is indentical. 1) Download and install MinGW-5.1.6.exe. Choose the "current" release. 2) Download and install MSYS-1.0.11.exe. 3) The following instructions assume that both Python and gcc (part of MinGW) exist on the operating system PATH. On Windows XP, this can be done using Settings -> Control Panel -> System -> Environment Variables. If not already present, add c:\python26 and c:\mingw\bin to the PATH. The entries should be separated by a semi-colon. Note: Python 2.6 is used in this example. 4) A icon entitled "MSYS" should be created on the desktop. It provides a GNU-compatible command line interface. Start MSYS and create a directory that will contain the MPIR and GMPY source code. C:\src will be used for this build. Note that /c/src is the MSYS equivalent of C:\src. $ mkdir /c/src 5) Download the GMP source code from www.gmplib.org and save it in C:\src. gmp-5.0.1.tar.bz2 is used in this example. The GMP source is also available at http://gmpy.googlecode.com/files/gmp-5.0.1.tar.bz2. ( Or download the MPIR source code from www.mpir.org and save it in C:\src. The MPIR source code is also available at http://gmpy.googlecode.com/files/mpir-2.1.1.tar.gz. ) 6) Download the GMPY source code and save it in C:\src. 7) Using MSYS, uncompress GMP, and then compile GMP. The resulting files are installed in C:\src. $ cd /c/src $ bunzip2 gmp.5.0.1.tar.bz2 $ tar -xf gmp-5.0.1.tar $ cd gmp-5.0.1 $ ./configure --prefix=/c/src --enable-fat $ make $ make check $ make install 8) Using the Windows command line, compile GMPY. The instructions assume the GMPY source code is uncompressed into C:\src\gmpy-1.12. > cd C:\src\gmpy-1.12 > python setup.py build_ext -cmingw32 -Ic:\src\include -Lc:\src\lib install > python test\gmpy_test.py Miscellaneous notes on compiling GMPY If you are using MPIR, you will need to include -DMPIR after build_ext. gmpy-1.17/setup.py0000666000000000000000000000444712175010722012640 0ustar rootrootimport sys, os from distutils.core import setup, Extension # monkey-patch distutils if it can't cope with the "classifiers" and # "download_url" keywords if sys.version < '2.2.3': from distutils.dist import DistributionMetadata DistributionMetadata.classifiers = None DistributionMetadata.download_url = None # Check if MPIR or GMP should be used. mplib='gmp' for token in sys.argv: if token.startswith('-D') and 'MPIR' in token: mplib='mpir' break # determine include and library dirs incdirs = libdirs = () if sys.version.find('MSC') == -1: # Unix-like build (including MacOSX) incdirs = ['./src'] dirord = ['/usr', '/opt/local', '/usr/local'] for adir in dirord: lookin = '%s/include' % adir if os.path.isfile(lookin + '/' + mplib + '.h'): incdirs.append(lookin) dirord = [adir] break for adir in dirord: lookin = '%s/lib' % adir if os.path.isfile(lookin + '/lib' + mplib + '.a'): libdirs = [lookin] break # decomment next line (w/gcc, only!) to support gcov # os.environ['CFLAGS'] = '-fprofile-arcs -ftest-coverage -O0' # prepare the extension for building gmpy_ext = Extension('gmpy', sources=['src/gmpy.c'], include_dirs=incdirs, library_dirs=libdirs, libraries=[mplib]) setup (name = "gmpy", version = "1.17", maintainer = "Case Van Horsen", maintainer_email = "casevh@gmail.com", url = "http://code.google.com/p/gmpy/", description = "MPIR/GMP interface to Python 2.4+ and 3.x", classifiers = [ 'Development Status :: 5 - Production/Stable', 'Intended Audience :: Developers', 'Intended Audience :: Science/Research', 'License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)', 'Natural Language :: English', 'Operating System :: MacOS :: MacOS X', 'Operating System :: Microsoft :: Windows', 'Operating System :: POSIX', 'Programming Language :: C', 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 3', 'Topic :: Scientific/Engineering :: Mathematics', 'Topic :: Software Development :: Libraries :: Python Modules', ], ext_modules = [ gmpy_ext ] ) gmpy-1.17/setes.py0000666000000000000000000000135612174774730012636 0ustar rootroot# pysymbolicext is no longer supported. It is included soley to test the # exported C API. import sys from distutils.core import setup, Extension if sys.version.find('MSC')==-1: gmpy_ext = Extension('pysymbolicext', sources=['src/pysymbolicext.c'], libraries=['gmp']) else: gmpy_ext = Extension('pysymbolicext', sources=['src/pysymbolicext.c'], libraries=['gmp'],include_dirs=['./src']) setup (name = "pysymbolicext", version = "0.2", description = "PySymbolic Python/GMP extensions (Pollard's rho)", author = "Pearu Peterson", maintainer = "Alex Martelli", maintainer_email = "aleaxit@gmail.com", url = "http://code.google.com/p/gmpy/source/", ext_modules = [ gmpy_ext ] ) gmpy-1.17/README0000666000000000000000000000256512174774730012024 0ustar rootrootGeneral MultiPrecision arithmetic for Python -- i.e., Python 2.4+ and 3.0+ interface module for library GMP 4 -- release 1.10 (July 2009). Note: There is a bug in GMP 4.2.3 that causes a segmentation fault when running gmpy_test.py. There are patches available at the GMP website or use GMP 4.2.4. The gmpy project has moved (since quite a while ago!-) to Google Code: http://code.google.com/p/gmpy/ Please check that site for better-updated sources, docs, etc. Detailed documentation is in subdirectory doc. To install gmpy 1.10 from sources (you need to have Python 2.4 or better, and GMP 4 or MPIR, previously installed): at a shell prompt, python setup.py install Beginning with gmpy 1.10, MPIR is supported as an alternative library to GMP. To install gmpy 1.10 with MPIR support, use the following command: python setup.py build_ext -DMPIR install Note that, on Windows, you may use the distributed binary release, rather than having to rebuild from source. To build GMP and GMPY from source, see the file "windows_build.txt". Binary installations are also available for MacOSX (and for many Linux distributions, but those are not distributed by the gmpy project). To test your installation: cd test, then python gmpy_test.py For any support request, mail Alex Martelli, aleaxit@gmail.com (or, better, use the issues and wiki entries of the Google Code URL previously given). gmpy-1.17/PKG-INFO0000666000000000000000000000170112175010756012220 0ustar rootrootMetadata-Version: 1.0 Name: gmpy Version: 1.17 Summary: MPIR/GMP interface to Python 2.4+ and 3.x Home-page: http://code.google.com/p/gmpy/ Author: Case Van Horsen Author-email: casevh@gmail.com License: UNKNOWN Description: UNKNOWN Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: Intended Audience :: Science/Research Classifier: License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL) Classifier: Natural Language :: English Classifier: Operating System :: MacOS :: MacOS X Classifier: Operating System :: Microsoft :: Windows Classifier: Operating System :: POSIX Classifier: Programming Language :: C Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 3 Classifier: Topic :: Scientific/Engineering :: Mathematics Classifier: Topic :: Software Development :: Libraries :: Python Modules gmpy-1.17/mutable_mpz.txt0000666000000000000000000000266212174774730014222 0ustar rootrootThere have been multiple requests to support efficient inplace operations on mutable integers. gmpy 1.10 did not provide any extra support for inplace operations. gmpy 1.11 adds support for the standard, immutable versions of the inplace operations. There is a compile-time option (-DMUTATE) that uses mutating versions of the inplace operations. A simple benchmark is: (Python 2.6) fact = gmpy.mpz(1) for i in xrange(10000000): fact *= i (Python 3.1) fact = gmpy.mpz(1) for i in range(10000000): fact *= i Measured results: gmpy ver: | 1.10 | 1.11(immutable) | 1.11 (mutable) ------------------------------------------------------------ Python 2.6 | 2.482s | 2.380s (4%) | 1.712s (31%) Python 3.1 | 2.470s | 2.374s (4%) | 1.846s (25%) The question is "How much benefit is there in real-world code?" If you have examples of real-world code that see a significant improvement with mutable integers, please let us know at: http://code.google.com/p/gmpy/ Build instructions ================== To build gmpy with mutable integers, use the following command: $python setup.py build_ext -DMUTATE -f install If you are using MPIR instead of GMP, use the following command: $python setup.py build_ext -DMPIR,MUTATE -f install Caveats ======= Hashing is disabled for mpz when built with MUTATE enabled. The behavior of many expressions involving mpz will change. To make a copy of an mpz, use "x=a._copy()". gmpy-1.17/mac_build.txt0000666000000000000000000000223212174774730013613 0ustar rootrootNews update as of gmpy 1.04: macports AKA darwinports now comes with GMP 4.2.4 and thus offers again the simplest and most effective preliminary to building and installing gmpy (I've tried Pyton 2.5.* and 2.6.* on OSX 10.5 with Intel processors, and 2.5.1 on OSX 10.5 with PowerPC processors -- sorry but I don't currently have at hand other Python/OS/processor combinations to try!). How to build gmpy with XCode 3 and Mac OS X 10.5 (one easy way): - install macports AKA darwinports, see http://darwinports.com/ (you do need to install XCode 3 first); no need to set PATH &c or install X11 etc etc, if all you need is to build gmpy - instructions at http://gmp.darwinports.com/ are wrong, just do (after install & selfupdate of darwinports): sudo /opt/local/bin/port install gmp (or if you have an older macports gmp, port update it) - now, 'python setup.py install' in gmpy's directory should work just fine - verify with python test/gmpy_test.py -- expect at the end of the output: 1214 passed and 0 failed. Test passed. For older systems, or to try and do without XCode, see: http://gmpy.googlecode.com/files/gmpy-1.02.macosx.README.txt and good luck! gmpy-1.17/lgpl-2.1.txt0000666000000000000000000006350412174774730013141 0ustar rootroot GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! gmpy-1.17/changes.txt0000666000000000000000000000342112174774730013305 0ustar rootrootChanges in gmpy 1.10 Number conversion rules have changed. ------------------------------------- The arguments in operations involving mixed types are converted using the following rules: Integer --> Rational --> Floating-point 'int' 'Fraction' 'float' 'long' 'mpq' 'Decimal' 'mpz' 'mpf' Old behavior: mpz(1) + float(1.2) --> float(2.2) mpz(1) + Decimal('1.2') --> mpz(2) New behavior: mpz(1) + float(1.2) --> mpf(2.2) mpz(1) + Decimal('1.2') --> mpf(2.2) As a side-effect of Python 3.x compatibility, coerce() is no longer supported. The result of // will be an mpz if the arguments are Integer or Rational, but will be an mpf if either argument is Floating-point. The result of 'mpq'/'mpq' will be an 'mpq'. It will not be converted to an 'mpf'. This matches the behavior of the 'Fraction' type in Python 3.x. The result of 'mpz'/'float' will an 'mpf' instead of a 'float'. Type-specific methods require appropriate arguments. ---------------------------------------------------- If you call an 'mpq' specific method, i.e. gmpy.qdiv, the arguments are required to be either integer or rational. Floating-point arguments are not automatically converted to rational when an 'mpq' specific method is called. Similarly, if you call an 'mpz' specific method, the arguments must be integers. Other bug fixes and changes -------------------------- Corrected formating bug with mpf where last digit was missing. The wording of some error messages has changed. The type of error has not changed. The result of gcdext may no longer be the "minimal" values. They result does solve gcd(a,b) = ax + by. This is a side-effect of GMP 4.3 using a different (faster) algorithm. Unicode strings are now supported.