diff --git a/Include/longintrepr.h b/Include/longintrepr.h index bbba4d8..460a3b6 100644 --- a/Include/longintrepr.h +++ b/Include/longintrepr.h @@ -1,10 +1,27 @@ #ifndef Py_LIMITED_API #ifndef Py_LONGINTREPR_H #define Py_LONGINTREPR_H + +#if defined(PyLong_GMP) +#include +#endif + #ifdef __cplusplus extern "C" { #endif +#if defined(PyLong_GMP) + +struct _longobject{ + PyObject_VAR_HEAD + mp_limb_t digits[1]; +}; + +PyAPI_FUNC(void) _PyMPN_CompactDigits(mp_limb_t*, size_t, mp_limb_t); +PyAPI_FUNC(void) _PyMPN_Norm(PyLongObject*); +PyAPI_FUNC(size_t) PyMPN_SizeInBase(const PyLongObject *a, int base); +PyAPI_FUNC(PyObject*) PyMPN_AsString(const PyLongObject*, int base, int prefix); +#else /* This is published for the benefit of "friends" marshal.c and _decimal.c. */ @@ -91,6 +108,8 @@ struct _longobject { digit ob_digit[1]; }; +#endif + PyAPI_FUNC(PyLongObject *) _PyLong_New(Py_ssize_t); /* Return a copy of src. */ diff --git a/Lib/fractions.py b/Lib/fractions.py index 43f146f..b53bb11 100644 --- a/Lib/fractions.py +++ b/Lib/fractions.py @@ -13,16 +13,22 @@ import sys __all__ = ['Fraction', 'gcd'] - -def gcd(a, b): - """Calculate the Greatest Common Divisor of a and b. - - Unless b==0, the result will have the same sign as b (so that when - b is divided by it, the result comes out positive). - """ - while b: - a, b = b, a%b - return a +if hasattr(int, '__gcd__'): + def gcd(a, b): + c=int(a).__gcd__(int(b)) + if b<0 or (b==0 and a<0): + c=-c + return c +else: + def gcd(a, b): + """Calculate the Greatest Common Divisor of a and b. + + Unless b==0, the result will have the same sign as b (so that when + b is divided by it, the result comes out positive). + """ + while b: + a, b = b, a%b + return a # Constants related to the hash implementation; hash(x) is based # on the reduction of x modulo the prime _PyHASH_MODULUS. diff --git a/Makefile.pre.in b/Makefile.pre.in index 43bc818..ab125d5 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -427,7 +427,7 @@ OBJECT_OBJS= \ Objects/funcobject.o \ Objects/iterobject.o \ Objects/listobject.o \ - Objects/longobject.o \ + Objects/@PyLong_IMPL@object.o \ Objects/dictobject.o \ Objects/memoryobject.o \ Objects/methodobject.o \ diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index 8be9be6..78304b1 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -2108,6 +2108,30 @@ PyDecType_FromSsizeExact(PyTypeObject *type, mpd_ssize_t v, PyObject *context) /* Convert from a PyLongObject. The context is not modified; flags set during conversion are accumulated in the status parameter. */ +#if defined(PyLong_GMP) +static PyObject * +dec_from_long(PyTypeObject *type, const PyObject *v, + const mpd_context_t *ctx, uint32_t *status) +{ + PyObject *str=PyMPN_AsString((const PyLongObject*)v, 10, 0), *dec; + char *cstr; + if(!str) return NULL; + dec=PyDecType_New(type); + if(!dec){ + Py_DECREF(str); + return NULL; + } + cstr=numeric_as_ascii(str, 0); + Py_DECREF(str); + if(!cstr){ + Py_DECREF(dec); + return NULL; + } + mpd_qset_string(MPD(dec), cstr, ctx, status); + PyMem_FREE(cstr); + return dec; +} +#else static PyObject * dec_from_long(PyTypeObject *type, const PyObject *v, const mpd_context_t *ctx, uint32_t *status) @@ -2156,6 +2180,7 @@ dec_from_long(PyTypeObject *type, const PyObject *v, return dec; } +#endif /* Return a new PyDecObject from a PyLongObject. Use the context for conversion. */ @@ -3307,9 +3332,11 @@ static PyObject * dec_as_long(PyObject *dec, PyObject *context, int round) { PyLongObject *pylong; + #if !defined(PyLong_GMP) + Py_ssize_t i; digit *ob_digit; + #endif size_t n; - Py_ssize_t i; mpd_t *x; mpd_context_t workctx; uint32_t status = 0; @@ -3340,6 +3367,43 @@ dec_as_long(PyObject *dec, PyObject *context, int round) } status = 0; +#if defined(PyLong_GMP) +#if PYLONG_BITS_IN_DIGIT == 32 + n=mpd_sizeinbase(x, 1000000000); + pylong = _PyLong_New(n); + { + uint32_t *tmp; + tmp=pylong->digits; + n=mpd_qexport_u32(&tmp, n, 1000000000, x, &status); + } + _PyMPN_CompactDigits(pylong->digits, n, 1000000000); +#elif PYLONG_BITS_IN_DIGIT == 64 + n=mpd_sizeinbase(x, 1000000000); + if(n%2==1){ + n++; + } + pylong = _PyLong_New(n/2); + { + uint32_t *d32; + size_t i; + d32=(uint32_t*)pylong->digits; + n=mpd_qexport_u32(&d32, n, 1000000000, x, &status); + if(n%2==1){ + d32[n]=0; + n++; + } + n/=2; + for(i=0;idigits[i]=d32[2*i]+(mp_limb_t)1000000000*d32[2*i+1]; + } + } + _PyMPN_CompactDigits(pylong->digits, n, 1000000000000000000); +#else +#error TODO: Non-32/64-bit limbs +#endif + Py_SIZE(pylong)=n; + _PyMPN_Norm(pylong); +#else ob_digit = NULL; #if PYLONG_BITS_IN_DIGIT == 30 n = mpd_qexport_u32(&ob_digit, 0, PyLong_BASE, x, &status); @@ -3372,8 +3436,10 @@ dec_as_long(PyObject *dec, PyObject *context, int round) } Py_SIZE(pylong) = i; +#endif + if (mpd_isnegative(x) && !mpd_iszero(x)) { - Py_SIZE(pylong) = -i; + Py_SIZE(pylong) = -Py_SIZE(pylong); } mpd_del(x); diff --git a/Objects/mpnobject.c b/Objects/mpnobject.c new file mode 100644 index 0000000..e12af51 --- /dev/null +++ b/Objects/mpnobject.c @@ -0,0 +1,15 @@ +#include "Python.h" +#include "longintrepr.h" + +#include "mpnobject/add-sub.c" +#include "mpnobject/base.c" +#include "mpnobject/binary.c" +#include "mpnobject/bytes.c" +#include "mpnobject/double.c" +#include "mpnobject/int.c" +#include "mpnobject/misc.c" +#include "mpnobject/mul-div.c" +#include "mpnobject/pow.c" +#include "mpnobject/string.c" +#include "mpnobject/type.c" +#include "mpnobject/pylong-api.c" diff --git a/Objects/mpnobject/add-sub.c b/Objects/mpnobject/add-sub.c new file mode 100644 index 0000000..7cf7734 --- /dev/null +++ b/Objects/mpnobject/add-sub.c @@ -0,0 +1,131 @@ +#include "internal.h" + +PyMPN_INTERNAL(void) +PyMPN_Negate(PyLongObject **a){ + size_t as; + PyLongObject *res; + if(Py_SIZE(*a)==0) return; + if(Py_REFCNT(*a) == 1){ + Py_SIZE(*a)=-Py_SIZE(*a); + return; + } + as=abss(*a); + if(as==1){ + res=PyMPN_FromDigitSgn((*a)->digits[0], !signof(*a)); + Py_DECREF(*a); + *a=res; + return; + } + res=PyMPN_New(as); + if(!res){ + Py_DECREF(*a); + *a=NULL; + return; + } + mpn_copyi(res->digits, (*a)->digits, as); + Py_SIZE(res)=-Py_SIZE(*a); + Py_DECREF(*a); + *a=res; + return; +} + +Py_LOCAL_INLINE(PyLongObject*) +_PyMPN_AddU(PyLongObject *a, PyLongObject *b, int sign){ + size_t sa=abss(a); + size_t sb=abss(b); + size_t sc; + PyLongObject *c; + if(sa==1 && sb==1){ + mp_limb_t sum=a->digits[0]+b->digits[0]; + if(sum>=a->digits[0]){ + return PyMPN_FromDigitSgn(sum, sign); + } + } + sc=Py_MAX(sa, sb); + c=PyMPN_New(sc+1); + if(!c) return NULL; + if(sa>=sb){ + c->digits[sc]=mpn_add(c->digits, a->digits, sa, b->digits, sb); + }else{ + c->digits[sc]=mpn_add(c->digits, b->digits, sb, a->digits, sa); + } + _PyMPN_Norm(c); + if(sign) Py_SIZE(c)=-Py_SIZE(c); + return c; +} + +PyMPN_INTERNAL(PyLongObject*) +_PyMPN_SubU(PyLongObject *a, PyLongObject *b){ + size_t sa=abss(a); + size_t sb=abss(b); + PyLongObject *c; + int sign=(sadigits[sa-1] == b->digits[sa-1]){ + sa--; + } + sb=sa; + if(sa==0) return PyMPN_Small(0); + if(a->digits[sa-1]digits[sb-1]){ + sign=1; + swap(PyLongObject*, a, b); + } + } + if(sa==1){ + return PyMPN_FromDigitSgn(a->digits[0]-b->digits[0], sign); + } + c=PyMPN_New(sa); + if(!c) return NULL; + if(mpn_sub(c->digits, a->digits, sa, b->digits, sb)){ + assert(0); + } + _PyMPN_Norm(c); + if(sign){ + Py_SIZE(c)=-Py_SIZE(c); + } + return c; +} + +PyMPN_INTERNAL(PyLongObject*) +PyMPN_Add(PyLongObject *a, PyLongObject *b){ + PyLongObject *c; + if(Py_SIZE(b) == 0){ + return PyMPN_ToMPN(a); + } + if(Py_SIZE(a) == 0){ + return PyMPN_ToMPN(b); + } + if(prod2_signof(a, b)==0){ + c=_PyMPN_AddU(a, b, signof(a)); + if(!c) return NULL; + return c; + }else if(signof(b)){ + return _PyMPN_SubU(a, b); + } + return _PyMPN_SubU(b, a); +} + +PyMPN_INTERNAL(PyLongObject*) +PyMPN_Sub(PyLongObject *a, PyLongObject *b){ + if(Py_SIZE(b) == 0){ + return PyMPN_ToMPN(a); + } + if(Py_SIZE(a) == 0){ + Py_INCREF(b); + PyMPN_Negate(&b); + return b; + } + if(prod2_signof(a, b)==1){ + PyLongObject *c=_PyMPN_AddU(a, b, signof(a)); + if(!c) return NULL; + return c; + }else if(!signof(b)>0){ + return _PyMPN_SubU(a, b); + }else{ + return _PyMPN_SubU(b, a); + } +} diff --git a/Objects/mpnobject/base.c b/Objects/mpnobject/base.c new file mode 100644 index 0000000..40da28d --- /dev/null +++ b/Objects/mpnobject/base.c @@ -0,0 +1,132 @@ +#include "internal.h" + +void _PyMPN_Norm(PyLongObject *a){ + while(Py_SIZE(a)!=0 && a->digits[Py_SIZE(a)-1]==0) Py_SIZE(a)--; + return; +} + +static PyLongObject small_neg_ints[20]; +static PyLongObject small_pos_ints[257]; + +size_t PyMPN_SizeInBase(const PyLongObject *a, int base){ + if(Py_SIZE(a)==0) return 0; + if(base==2){ + size_t s=abss(a)-1; + return s*GMP_NUMB_BITS+limbBits(a->digits[s]); + } + return mpn_sizeinbase(a->digits, abss(a), base); +} +PyMPN_INTERNAL(PyLongObject*) +PyMPN_New(size_t n){ + PyLongObject *res; + if(n>=PY_SSIZE_T_MAX/GMP_NUMB_BITS){ + PyErr_SetNone(PyExc_MemoryError); + return NULL; + } + res=PyObject_NEW_VAR(PyLongObject, &PyLong_Type, n); + Py_SIZE(res)=n; + return res; +} + +PyLongObject *PyMPN_FromDigitSgn(mp_limb_t a, int sgn){ + PyLongObject *res; + if(a==0){ + res=small_pos_ints+0; + Py_INCREF(res); + return res; + } + if(!sgn && a<257){ + res=small_pos_ints+a; + Py_INCREF(res); + return res; + }else if(sgn && a<=20){ + res=small_neg_ints+a-1; + Py_INCREF(res); + return res; + } + res=PyMPN_New(1); + if(!res) return NULL; + res->digits[0]=a; + if(sgn) Py_SIZE(res)=-1; + return res; +} + +PyMPN_INTERNAL(PyLongObject*) +PyMPN_SmallWeak(int i){ + return small_pos_ints+i; +} + +PyMPN_INTERNAL(PyLongObject*) +PyMPN_Small(int i){ + PyLongObject *res=PyMPN_SmallWeak(i); + Py_INCREF(res); + return res; +} +PyMPN_INTERNAL(PyLongObject*) PyMPN_ToMPN(PyLongObject *a){ + if(Py_TYPE(a)!=&PyLong_Type){ + PyLongObject *b=PyMPN_New(abss(a)); + mpn_copyi(b->digits, a->digits, Py_SIZE(b)); + if(signof(a)) Py_SIZE(b)=-Py_SIZE(b); + return b; + } + Py_INCREF(a); + return a; +} + +static PyTypeObject MPN_InfoType; +static PyStructSequence_Field pympn_info_fields[] = { + {"bits_per_digit", NULL}, + {"sizeof_digit", NULL}, + {NULL, NULL} +}; + +static PyStructSequence_Desc mpn_info_desc = { + "sys.int_info", /* name */ + NULL, /* doc */ + pympn_info_fields, /* fields */ + 2 /* number of fields */ +}; + +PyObject *PyLong_GetInfo(void){ + PyObject* mpn_info; + int field=0; + mpn_info = PyStructSequence_New(&MPN_InfoType); + if (mpn_info == NULL) + return NULL; + PyStructSequence_SET_ITEM(mpn_info, field++, PyLong_FromLong(GMP_NUMB_BITS)); + PyStructSequence_SET_ITEM(mpn_info, field++, PyLong_FromLong(sizeof(mp_limb_t))); + if(PyErr_Occurred()){ + Py_CLEAR(mpn_info); + return NULL; + } + return mpn_info; +} + +int _PyLong_Init(void){ + mp_limb_t i; + if(Py_TYPE(small_pos_ints+0)) return 1; + if(PyType_Ready(&PyLong_Type)<0){ + return -1; + } + if(PyStructSequence_InitType2(&MPN_InfoType, &mpn_info_desc)<0){ + return -1; + } + for(i=0;i<20;i++){ + Py_TYPE(small_neg_ints+i)=&PyLong_Type; + Py_SIZE(small_neg_ints+i)=-1; + small_neg_ints[i].digits[0]=i+1; + _Py_NewReference((PyObject*)(small_neg_ints+i)); + } + Py_TYPE(small_pos_ints+0)=&PyLong_Type; + _Py_NewReference((PyObject*)(small_pos_ints+0)); + for(i=1;i<257;i++){ + Py_TYPE(small_pos_ints+i)=&PyLong_Type; + Py_SIZE(small_pos_ints+i)=1; + small_pos_ints[i].digits[0]=i; + _Py_NewReference((PyObject*)(small_pos_ints+i)); + } + return 1; +} +void PyLong_Fini(void){ + return; +} diff --git a/Objects/mpnobject/binary.c b/Objects/mpnobject/binary.c new file mode 100644 index 0000000..460fe0c --- /dev/null +++ b/Objects/mpnobject/binary.c @@ -0,0 +1,306 @@ +#include "internal.h" +PyMPN_INTERNAL(void) +PyMPN_Invert(PyLongObject **a){ + PyLongObject *b; + PyMPN_Negate(a); + b=PyMPN_Sub(*a, PyMPN_SmallWeak(1)); + //Py_DECREF(*a); + *a=b; + return; +} + +PyMPN_INTERNAL(PyLongObject*) +PyMPN_And(PyLongObject *a, PyLongObject *b){ + PyLongObject *res; + size_t s; + if(Py_SIZE(a) == 0 || Py_SIZE(b) == 0){ + return PyMPN_Small(0); + } + if(!signof(a)){ + if(!signof(b)){ + s=Py_MIN(Py_SIZE(a), Py_SIZE(b)); + if(s==1){ + return PyMPN_FromDigitSgn(a->digits[0]&b->digits[0], 0); + } + res=PyMPN_New(s); + mpn_and_n(res->digits, a->digits, b->digits, s); + _PyMPN_Norm(res); + }else{ + if(Py_SIZE(a)==1){ + res=PyMPN_FromDigitSgn(a->digits[0]&-b->digits[0], 0); + }else{ + b=_PyMPN_SubU(b, PyMPN_SmallWeak(1)); + s=Py_MIN(Py_SIZE(a), Py_SIZE(b)); + res=PyMPN_New(Py_SIZE(a)); + if(s) mpn_andn_n(res->digits, a->digits, b->digits, s); + if(Py_SIZE(a)>Py_SIZE(b)){ + mpn_copyi(res->digits+Py_SIZE(b), a->digits+Py_SIZE(b), Py_SIZE(a)-Py_SIZE(b)); + } + Py_DECREF(b); + _PyMPN_Norm(res); + } + } + }else{ + if(!signof(b)){ + if(Py_SIZE(b)==1){ + res=PyMPN_FromDigitSgn(b->digits[0]&-a->digits[0], 0); + }else{ + a=_PyMPN_SubU(a, PyMPN_SmallWeak(1)); + s=Py_MIN(Py_SIZE(a), Py_SIZE(b)); + res=PyMPN_New(Py_SIZE(b)); + if(s) mpn_andn_n(res->digits, b->digits, a->digits, s); + if(Py_SIZE(b)>Py_SIZE(a)){ + mpn_copyi(res->digits+Py_SIZE(a), b->digits+Py_SIZE(a), Py_SIZE(b)-Py_SIZE(a)); + } + Py_DECREF(a); + _PyMPN_Norm(res); + } + }else{ + Py_INCREF(a); + PyMPN_Invert(&a); + Py_INCREF(b); + PyMPN_Invert(&b); + res=PyMPN_Or(a, b); + Py_DECREF(a); + Py_DECREF(b); + PyMPN_Invert(&res); + } + } + return res; +} + +PyMPN_INTERNAL(PyLongObject*) +PyMPN_Or(PyLongObject *a, PyLongObject *b){ + PyLongObject *res; + size_t sa, sb; + if(Py_SIZE(a) == 0){ + return PyMPN_ToMPN(b); + } + if(Py_SIZE(b) == 0){ + return PyMPN_ToMPN(a); + } + if(!signof(a) && !signof(b)){ + sa=Py_SIZE(a); + sb=Py_SIZE(b); + if(sa==1 && sb==1){ + return PyMPN_FromDigitSgn(a->digits[0]|b->digits[0], 0); + } + if(sadigits, a->digits, b->digits, sb); + if(sa!=sb) mpn_copyi(res->digits+sb, a->digits+sb, sa-sb); + }else{ + Py_INCREF(a); + PyMPN_Invert(&a); + Py_INCREF(b); + PyMPN_Invert(&b); + res=PyMPN_And(a, b); + Py_DECREF(a); + Py_DECREF(b); + PyMPN_Invert(&res); + } + return res; +} + +PyMPN_INTERNAL(PyLongObject*) +PyMPN_Xor(PyLongObject *a, PyLongObject *b){ + PyLongObject *res; + size_t sa, sb; + int inv=0; + if(Py_SIZE(a) == 0){ + return PyMPN_ToMPN(b); + } + if(Py_SIZE(b) == 0){ + return PyMPN_ToMPN(a); + } + if(abss(a)==1 && abss(b)==1){ + mp_limb_t ad=a->digits[0], bd=b->digits[0]; + if(signof(b)){ + bd=bd-1; + } + if(signof(a)){ + ad=ad-1; + } + ad^=bd; + if(prod2_signof(a, b)){ + if(ad+1) return PyMPN_FromDigitSgn(ad+1, 1); + }else{ + return PyMPN_FromDigitSgn(ad, 0); + } + } + Py_INCREF(a); + if(signof(a)){ + PyMPN_Invert(&a); + inv=!inv; + } + sa=Py_SIZE(a); + Py_INCREF(b); + if(signof(b)){ + PyMPN_Invert(&b); + inv=!inv; + } + sb=Py_SIZE(b); + if(sadigits[0]^b->digits[0], 0); + Py_DECREF(a); + Py_DECREF(b); + }else{ + res=PyMPN_New(sa); + if(sb) mpn_xor_n(res->digits, a->digits, b->digits, sb); + Py_DECREF(b); + mpn_copyi(res->digits+sb, a->digits+sb, sa-sb); + Py_DECREF(a); + _PyMPN_Norm(res); + } + if(inv){ + PyMPN_Invert(&res); + } + return res; +} + +PyMPN_INTERNAL(PyLongObject*) +_PyMPN_LShiftU(PyLongObject *a, size_t b, int sign){ + PyLongObject *res; + size_t whole=b/GMP_NUMB_BITS, sa=abss(a), size=sa+whole; + mp_limb_t carry; + b%=GMP_NUMB_BITS; + if(b) size++; + if(sa==1 && whole==0){ + mp_limb_t l=a->digits[0]<>b == a->digits[0]) return PyMPN_FromDigitSgn(l, sign); + } + res=PyMPN_New(size); + if(whole) mpn_zero(res->digits, whole); + carry=mpn_lshift(res->digits+whole, a->digits, sa, b); + if(b) res->digits[size-1]=carry; + _PyMPN_Norm(res); + if(sign) Py_SIZE(res)=-Py_SIZE(res); + return res; +} +Py_LOCAL_INLINE(PyLongObject*) +_PyMPN_RShiftU(PyLongObject *a, size_t b, int sign){ + PyLongObject *res; + size_t whole=b/GMP_NUMB_BITS, sa=abss(a), size; + if(whole>=sa) return PyMPN_Small(0); + size=sa-whole; + b%=GMP_NUMB_BITS; + if(size==1){ + mp_limb_t res=a->digits[whole]>>b; + return PyMPN_FromDigitSgn(res, sign); + } + res=PyMPN_New(size); + if(b==0){ + mpn_copyi(res->digits, a->digits+whole, size); + }else{ + mpn_rshift(res->digits, a->digits+whole, sa-whole, b); + } + _PyMPN_Norm(res); + if(sign) Py_SIZE(res)=-Py_SIZE(res); + return res; +} +Py_LOCAL_INLINE(PyLongObject*) +_PyMPN_RShiftUU(PyLongObject *a, size_t b, int sign){ + PyLongObject *res; + size_t whole=b/GMP_NUMB_BITS, sa=abss(a), size, i; + int carry=0, extra=1; + if(whole>=sa){ + if(Py_SIZE(a)!=0) return PyMPN_FromDigitSgn(1, sign); + return PyMPN_Small(0); + } + size=sa-whole; + b%=GMP_NUMB_BITS; + for(i=0;idigits[i]){ + carry=1; + break; + } + if(size==1){ + mp_limb_t res=a->digits[whole]; + if(res&((((mp_limb_t)1)<>=b; + if(carry) res++; + if(!carry || res!=0) return PyMPN_FromDigitSgn(res, sign); + } + for(i=whole;idigits[i] != GMP_NUMB_MAX){ + extra=0; + break; + } + } + res=PyMPN_New(size+extra); + if(extra){ + res->digits[size]=0; + } + if(b==0){ + mpn_copyi(res->digits, a->digits+whole, size); + }else{ + if(mpn_rshift(res->digits, a->digits+whole, size, b)) carry=1; + } + if(carry){ + if(mpn_add_1(res->digits, res->digits, size, 1)){ + res->digits[size]=1; + } + } + _PyMPN_Norm(res); + if(sign) Py_SIZE(res)=-Py_SIZE(res); + return res; +} + +PyMPN_INTERNAL(PyLongObject*) +PyMPN_LShift(PyLongObject *a, PyLongObject *b){ + if(Py_SIZE(a)==0){ + return PyMPN_Small(0); + } + if(Py_SIZE(b)==0){ + return PyMPN_ToMPN(a); + } + if(abss(b)>1){ + if(!signof(b)){ + PyErr_SetNone(PyExc_MemoryError); + return NULL; + }else{ + return PyMPN_Small(0); + } + } + if(signof(b)){ + if(!signof(a)){ + return _PyMPN_RShiftU(a, b->digits[0], signof(a)); + }else{ + return _PyMPN_RShiftUU(a, b->digits[0], signof(a)); + } + }else{ + return _PyMPN_LShiftU(a, b->digits[0], signof(a)); + } +} +PyMPN_INTERNAL(PyLongObject*) +PyMPN_RShift(PyLongObject *a, PyLongObject *b){ + if(Py_SIZE(a)==0){ + return PyMPN_Small(0); + } + if(Py_SIZE(b)==0){ + return PyMPN_ToMPN(a); + } + if(abss(b)>1){ + if(signof(b)){ + PyErr_SetNone(PyExc_MemoryError); + return NULL; + }else{ + return PyMPN_Small(0); + } + } + if(!signof(b)){ + if(!signof(a)){ + return _PyMPN_RShiftU(a, b->digits[0], signof(a)); + }else{ + return _PyMPN_RShiftUU(a, b->digits[0], signof(a)); + } + }else{ + return _PyMPN_LShiftU(a, b->digits[0], signof(a)); + } +} diff --git a/Objects/mpnobject/bytes.c b/Objects/mpnobject/bytes.c new file mode 100644 index 0000000..d64c1f7 --- /dev/null +++ b/Objects/mpnobject/bytes.c @@ -0,0 +1,130 @@ +#include "internal.h" +PyLongObject* PyMPN_FromByteArray( + const unsigned char* bytes, size_t n, + int little_endian, int is_signed){ + // ASSUMES GMP_NUMB_BITS%8==0 + int sign=0, inc; + size_t size; + PyLongObject *res; + if(!little_endian){ + if(is_signed){ + if(bytes[0]>=0x80){ + sign=1; + } + } + bytes+=n-1; + inc=-1; + }else{ + if(is_signed){ + if(bytes[n-1]>=0x80){ + sign=1; + } + } + inc=1; + } + size=(8*n+GMP_NUMB_BITS-1)/GMP_NUMB_BITS; + if(size==0){ + return PyMPN_Small(0); + } + res=PyMPN_New(size); + + if(sign){ + int carry=1; + size_t i, j; + for(i=0;idigits[i]=l; + } + }else{ + size_t i, j; + for(i=0;idigits[i]=l; + } + } + _PyMPN_Norm(res); + if(sign) Py_SIZE(res)=-Py_SIZE(res); + return res; +} +int PyMPN_AsByteArray(PyLongObject* v, + unsigned char* bytes, size_t n, + int little_endian, int is_signed){ + size_t i, j, size; + mp_limb_t high; + + size=abss(v); + if(size==0){ + memset(bytes, 0, n); + return 0; + } + if(!is_signed && signof(v)){ + PyErr_SetString(PyExc_OverflowError, "can't convert negative int to unsigned"); + return -1; + } + if(mpn_sizeinbase(v->digits, size, 2)>8*n){ + PyErr_SetString(PyExc_OverflowError, "int too big to convert"); + return -1; + } + for(i=0;idigits[i]; + for(j=0;j>=8; + bytes++; + } + } + high=v->digits[i]; + for(i=PyMPN_BYTES_PER_LIMB*(size-1);i>=8; + bytes++; + } + if(high){ + PyErr_SetString(PyExc_OverflowError, "int too big to convert"); + return -1; + } + bytes-=n; + if(is_signed){ + if(signof(v)){ + int carry=1; + for(i=0;i=0x80){ + PyErr_SetString(PyExc_OverflowError, "int too big to convert"); + return -1; + } + } + if(!little_endian){ + for(i=0;iDBL_MAX_EXP){ + PyErr_SetString(PyExc_OverflowError, "int too large to convert to float"); + return -1.0; + } + a=ldexpl(a, exp); + if(Py_IS_INFINITY(a)) { + PyErr_SetString(PyExc_OverflowError, "int too large to convert to float"); + return -1.0; + } + return a; +} + +Py_LOCAL_INLINE(unsigned) PY_LONG_LONG PyMPN_AsAbsULLAndExp(PyLongObject *a, Py_ssize_t *e, size_t bitsize){ + unsigned PY_LONG_LONG high=1ULL<digits[as-1]; + if(r>=high){ + while(r>>bits >= high){ + bits++; + } + left=1ULL<<(bits-1); + carry=r&(2*left-1); + r>>=bits; + i=as-1; + *e=(as-1)*GMP_NUMB_BITS+bitsize+bits; + }else{ + while(!((r<<1)&high)){ + r<<=1; + bits++; + } + i=as-1; + *e=(as-1)*GMP_NUMB_BITS+bitsize-bits; + + for(i=as-1;i && bits>=GMP_NUMB_BITS;){ + bits-=GMP_NUMB_BITS; + r+=((unsigned long long)(a->digits[--i]))<digits[i-1]>>bits; + carry=a->digits[i-1]&(2*left-1); + i--; + }else{ + left=1ULL<<(GMP_NUMB_BITS-1); + carry=a->digits[i-1]; + i--; + } + } + + if(carry > left){ + r++; + }else if(carry == left){ + if(r%2==1){ + r++; + }else{ + size_t j; + for(j=0;jdigits[j]){ + break; + } + if(i!=j) r++; + } + } + return r; +} + +PyLongObject *PyMPN_FromDoubleAndExp(double a, Py_ssize_t exp){ + PyLongObject *res; + size_t exp2, i, n; + int ed, sign=0; + if(Py_IS_INFINITY(a)) { + PyErr_SetString(PyExc_OverflowError, "cannot convert float infinity to integer"); + return NULL; + } + if(Py_IS_NAN(a)){ + PyErr_SetString(PyExc_ValueError, "cannot convert float NaN to integer"); + return NULL; + } + if(a==0){ + return PyMPN_Small(0); + } + if(a<0){ + sign=1; + a=-a; + } + a=frexp(a, &ed); + exp+=ed; + if(exp<=0) return PyMPN_Small(0); + exp2=exp; + n=(exp2+GMP_NUMB_BITS-1)/GMP_NUMB_BITS; + res=PyMPN_New(n); + a=ldexp(a, exp2-GMP_NUMB_BITS*n); + for(i=n;i--;){ + mp_limb_t val; + a=ldexp(a, GMP_NUMB_BITS); + val=a; + if(val>=GMP_NUMB_MAX) val=GMP_NUMB_MAX; + res->digits[i]=val; + a-=val; + } + _PyMPN_Norm(res); + if(sign) Py_SIZE(res)=-Py_SIZE(res); + Py_INCREF(res); + Py_INCREF(res); + return res; +} + + +double PyMPN_AsDoubleAndExp(PyLongObject *a, Py_ssize_t *e){ + double r=0; + unsigned long long rl; + if(Py_SIZE(a)==0){ + *e=0; + return 0.0; + } + rl=PyMPN_AsAbsULLAndExp(a, e, DBL_MANT_DIG); + r=ldexp(rl, -DBL_MANT_DIG); + if(signof(a)) r=-r; + return r; +} +double PyMPN_AsDouble(PyLongObject *a){ + Py_ssize_t e; + double v=PyMPN_AsDoubleAndExp(a, &e); + if(v==-1.0 && PyErr_Occurred()) return -1.0; + return PyMPN_check_ldexp(v, e); +} + +PyLongObject *PyMPN_FromDouble(double a){ + return PyMPN_FromDoubleAndExp(a, 0); +} diff --git a/Objects/mpnobject/int.c b/Objects/mpnobject/int.c new file mode 100644 index 0000000..db68d27 --- /dev/null +++ b/Objects/mpnobject/int.c @@ -0,0 +1,146 @@ +#include "internal.h" + +#define PyMPN_CONVERTER_C(T, Name) \ + T PyMPN_As##Name(PyLongObject *a){ \ + int overflow; \ + T res=PyMPN_As##Name##AndOverflow(a, &overflow); \ + if(overflow==1){ \ + PyErr_SetString(PyExc_OverflowError, "Python int too large to convert to C " #T); \ + }else if(overflow==-1){ \ + PyErr_SetString(PyExc_OverflowError, "Python int too small to convert to C " #T); \ + } \ + return res; \ + } +#define PyMPN_CONVERTER_S(T, Name, UT) \ + PyLongObject *PyMPN_From##Name(T b){ \ + UT a; \ + PyLongObject *res; \ + size_t n, i; \ + int sign; \ + if(b<0){ \ + a=-b; \ + sign=1; \ + }else{ \ + a=b; \ + sign=0; \ + } \ + if(a<=GMP_NUMB_MAX){ \ + return PyMPN_FromDigitSgn(a, sign); \ + } \ + n=(sizeof(T)*8+GMP_NUMB_BITS-1)/GMP_NUMB_BITS; \ + res=PyMPN_New(n); \ + for(i=0;idigits[i]=a>>(i*GMP_NUMB_BITS)&GMP_NUMB_MAX; \ + } \ + if(sign) Py_SIZE(res)=-Py_SIZE(res); \ + return res; \ + } \ + T PyMPN_As##Name##AndOverflow(PyLongObject *a, int *overflow){ \ + UT res; \ + size_t sz, i; \ + *overflow=0; \ + res=0; \ + sz=abss(a); \ + for(i=0;idigits[i], d2; \ + if(shift>=sizeof(UT)*8 || shift>=GMP_NUMB_BITS){ \ + if(signof(a)){ \ + *overflow=-1; \ + }else{ \ + *overflow=1; \ + } \ + return -1; \ + } \ + d2=d<>shift!=d || d2 > ((UT)-1)){ \ + if(signof(a)){ \ + *overflow=-1; \ + }else{ \ + *overflow=1; \ + } \ + return -1; \ + } \ + res|=d2; \ + } \ + if(signof(a)){ \ + if(res>(((UT)1)<<(sizeof(UT)*8-1))){ \ + *overflow=-1; \ + return -1; \ + } \ + return -res; \ + }else{ \ + if(res>=(((UT)1)<<(sizeof(UT)*8-1))){ \ + *overflow=1; \ + return -1; \ + } \ + return res; \ + }\ + } \ + PyMPN_CONVERTER_C(T, Name) +#define PyMPN_CONVERTER_U(T, Name) \ + PyLongObject *PyMPN_From##Name(T a){ \ + PyLongObject *res; \ + size_t n, i; \ + if(a<=GMP_NUMB_MAX){ \ + return PyMPN_FromDigitSgn(a, 0); \ + } \ + n=(sizeof(T)*8+GMP_NUMB_BITS-1)/GMP_NUMB_BITS; \ + res=PyMPN_New(n); \ + for(i=0;idigits[i]=a>>(i*GMP_NUMB_BITS)&GMP_NUMB_MAX; \ + } \ + return res; \ + } \ + T PyMPN_As##Name##Mask(PyLongObject *a){ \ + T res; \ + size_t sz, i; \ + res=0; \ + sz=Py_SIZE(a); \ + for(i=0;i=sizeof(T)*8 || shift>=GMP_NUMB_BITS){ \ + break; \ + } \ + res|=a->digits[i]<digits[i], d2; \ + if(shift>=sizeof(T)*8 || shift>=GMP_NUMB_BITS){ \ + *overflow=1; \ + return -1; \ + } \ + d2=d<>shift!=d || d2 > ((T)-1)){ \ + *overflow=1; \ + return -1; \ + } \ + res|=d2; \ + } \ + return res; \ + } \ + PyMPN_CONVERTER_C(T, Name) +PyMPN_CONVERTER_S(int, Int, unsigned int) +PyMPN_CONVERTER_S(long, Long, unsigned long) +PyMPN_CONVERTER_S(PY_LONG_LONG, LongLong, unsigned PY_LONG_LONG) +PyMPN_CONVERTER_S(Py_ssize_t, Ssize_t, size_t) +PyMPN_CONVERTER_U(unsigned int, UnsignedInt) +PyMPN_CONVERTER_U(unsigned long, UnsignedLong) +PyMPN_CONVERTER_U(unsigned PY_LONG_LONG, UnsignedLongLong) +PyMPN_CONVERTER_U(size_t, Size_t) diff --git a/Objects/mpnobject/internal.h b/Objects/mpnobject/internal.h new file mode 100644 index 0000000..89e382f --- /dev/null +++ b/Objects/mpnobject/internal.h @@ -0,0 +1,132 @@ +#pragma once +#include "Python.h" +#include "longintrepr.h" + +#include +#include +#include +#include + +#define prod2_signof(a, b) ((Py_SIZE(a)^Py_SIZE(b))<0) +#define signof(a) (Py_SIZE(a)<0) +#define abss(x) ((signof(x))?-Py_SIZE(x):Py_SIZE(x)) +#define swap(T, a, b) do{ \ + T tmp=a; \ + a=b; \ + b=tmp; \ +}while(0); + +#if defined(__GNUC__) +#if GMP_NUMB_BITS <= 32 +#define limbBits(a) (32-__builtin_clz(a)) +#define limbTZ(a) (__builtin_ctz(a)) +#elif GMP_NUMB_BITS <= 64 +#define limbBits(a) (64-__builtin_clzll(a)) +#define limbTZ(a) (__builtin_ctzll(a)) +#else +#error TODO: Limbs bigger than 64 bits +#endif +#else +Py_LOCAL_INLINE(size_t) limbBits(mp_limb_t a){ + size_t res=0; + while(a){ + res++; + a>>=1; + } + return res; +} +Py_LOCAL_INLINE(size_t) limbTZ(mp_limb_t a){ + size_t res=0; + while((a&1)==0){ + res++; + a>>=1; + } + return res; +} +#endif + +#if defined(WITH_THREAD) +#define Py_MAYBE_RELEASE_GIL_BEGIN(cond) { PyThreadState *_threadState=(cond)?PyEval_SaveThread():NULL; +#define Py_MAYBE_RELEASE_GIL_PRE_END if(_threadState){PyEval_RestoreThread(_threadState);_threadState=NULL;} +#define Py_MAYBE_RELEASE_GIL_END if(_threadState) PyEval_RestoreThread(_threadState); } +#else +#define Py_MAYBE_RELEASE_GIL_BEGIN(cond) { +#define Py_MAYBE_RELEASE_GIL_PRE_END +#define Py_MAYBE_RELEASE_GIL_END } +#endif + +#define PyMPN_BYTES_PER_LIMB (GMP_NUMB_BITS/8) + +#define PyMPN_INTERNAL(T) Py_LOCAL_INLINE(T) + +PyMPN_INTERNAL(PyLongObject*) PyMPN_SmallWeak(int i); +PyMPN_INTERNAL(PyLongObject*) PyMPN_Small(int i); +PyMPN_INTERNAL(PyLongObject*) PyMPN_New(size_t n); +PyMPN_INTERNAL(void) PyMPN_Invert(PyLongObject**); +PyMPN_INTERNAL(PyLongObject*) PyMPN_And(PyLongObject*, PyLongObject*); +PyMPN_INTERNAL(PyLongObject*) PyMPN_Or(PyLongObject*, PyLongObject*); +PyMPN_INTERNAL(PyLongObject*) PyMPN_Xor(PyLongObject*, PyLongObject*); +PyMPN_INTERNAL(PyLongObject*) _PyMPN_LShiftU(PyLongObject*, size_t, int); +PyMPN_INTERNAL(PyLongObject*) _PyMPN_RShiftU(PyLongObject*, size_t, int); +PyMPN_INTERNAL(PyLongObject*) PyMPN_LShift(PyLongObject*, PyLongObject*); +PyMPN_INTERNAL(PyLongObject*) PyMPN_RShift(PyLongObject*, PyLongObject*); +PyMPN_INTERNAL(void) PyMPN_Negate(PyLongObject**); +PyMPN_INTERNAL(PyLongObject*) PyMPN_Add(PyLongObject*, PyLongObject*); +PyMPN_INTERNAL(PyLongObject*) PyMPN_Sub(PyLongObject*, PyLongObject*); +PyMPN_INTERNAL(PyLongObject*) _PyMPN_SubU(PyLongObject*, PyLongObject*); +PyMPN_INTERNAL(PyLongObject*) PyMPN_Mul(PyLongObject*, PyLongObject*); +PyMPN_INTERNAL(PyObject*) PyMPN_Pow(PyLongObject*, PyLongObject*); +PyMPN_INTERNAL(double) PyMPN_TrueDiv(PyLongObject*, PyLongObject*); +PyMPN_INTERNAL(PyLongObject*) PyMPN_Pow1(PyLongObject*, size_t); +PyMPN_INTERNAL(PyLongObject*) PyMPN_PowM(PyLongObject*, PyLongObject*, PyLongObject*); +PyMPN_INTERNAL(int) PyMPN_Compare(PyLongObject*, PyLongObject*); +PyMPN_INTERNAL(void) PyMPN_DivMod(PyLongObject*, PyLongObject*, PyLongObject**, PyLongObject**); +PyMPN_INTERNAL(PyLongObject*) PyMPN_ToMPN(PyLongObject*); +PyMPN_INTERNAL(double) PyMPN_check_ldexp(double, Py_ssize_t); +PyMPN_INTERNAL(PyLongObject*) PyMPN_GCD(PyLongObject*, PyLongObject*); + +PyMPN_INTERNAL(PyLongObject*) PyMPN_FromDigitSgn(mp_limb_t a, int sgn); +PyMPN_INTERNAL(PyLongObject*) PyMPN_FromInt(int); +PyMPN_INTERNAL(PyLongObject*) PyMPN_FromUnsignedInt(unsigned int); +PyMPN_INTERNAL(PyLongObject*) PyMPN_FromLong(long); +PyMPN_INTERNAL(PyLongObject*) PyMPN_FromUnsignedLong(unsigned long); +PyMPN_INTERNAL(PyLongObject*) PyMPN_FromLongLong(PY_LONG_LONG); +PyMPN_INTERNAL(PyLongObject*) PyMPN_FromUnsignedLongLong(unsigned PY_LONG_LONG); +PyMPN_INTERNAL(PyLongObject*) PyMPN_FromSize_t(size_t); +PyMPN_INTERNAL(PyLongObject*) PyMPN_FromSsize_t(Py_ssize_t); +PyMPN_INTERNAL(PyLongObject*) PyMPN_FromDouble(double); +PyMPN_INTERNAL(PyLongObject*) PyMPN_FromDoubleAndExp(double, Py_ssize_t); +PyMPN_INTERNAL(int) PyMPN_AsInt(PyLongObject*); +PyMPN_INTERNAL(int) PyMPN_AsIntAndOverflow(PyLongObject*, int*); +PyMPN_INTERNAL(unsigned int) PyMPN_AsUnsignedInt(PyLongObject*); +PyMPN_INTERNAL(unsigned int) PyMPN_AsUnsignedIntMask(PyLongObject*); +PyMPN_INTERNAL(unsigned int) PyMPN_AsUnsignedIntAndOverflow(PyLongObject*, int*); +PyMPN_INTERNAL(long) PyMPN_AsLong(PyLongObject*); +PyMPN_INTERNAL(long) PyMPN_AsLongAndOverflow(PyLongObject*, int*); +PyMPN_INTERNAL(unsigned long) PyMPN_AsUnsignedLong(PyLongObject*); +PyMPN_INTERNAL(unsigned long) PyMPN_AsUnsignedLongMask(PyLongObject*); +PyMPN_INTERNAL(unsigned long) PyMPN_AsUnsignedLongAndOverflow(PyLongObject*, int*); +PyMPN_INTERNAL(PY_LONG_LONG) PyMPN_AsLongLong(PyLongObject*); +PyMPN_INTERNAL(PY_LONG_LONG) PyMPN_AsLongLongAndOverflow(PyLongObject*, int*); +PyMPN_INTERNAL(unsigned PY_LONG_LONG) PyMPN_AsUnsignedLongLong(PyLongObject*); +PyMPN_INTERNAL(unsigned PY_LONG_LONG) PyMPN_AsUnsignedLongLongMask(PyLongObject*); +PyMPN_INTERNAL(unsigned PY_LONG_LONG) PyMPN_AsUnsignedLongLongAndOverflow(PyLongObject*, int*); +PyMPN_INTERNAL(Py_ssize_t) PyMPN_AsSsize_t(PyLongObject*); +PyMPN_INTERNAL(Py_ssize_t) PyMPN_AsSsize_tAndOverflow(PyLongObject*, int*); +PyMPN_INTERNAL(size_t) PyMPN_AsSize_t(PyLongObject*); +PyMPN_INTERNAL(size_t) PyMPN_AsSize_tMask(PyLongObject*); +PyMPN_INTERNAL(size_t) PyMPN_AsSize_tAndOverflow(PyLongObject*, int*); +PyMPN_INTERNAL(double) PyMPN_AsDouble(PyLongObject*); +PyMPN_INTERNAL(double) PyMPN_AsDoubleAndExp(PyLongObject*, Py_ssize_t*); + +PyMPN_INTERNAL(PyLongObject*) _PyMPN_FromBytes(int base, const char *data, size_t len, size_t *used, PyObject *nice); +PyMPN_INTERNAL(PyLongObject*) PyMPN_FromStringOrBuffer(PyObject*, int base); + +PyMPN_INTERNAL(void) PyMPN_DivModNear(PyLongObject *a, PyLongObject *b, PyLongObject **q, PyLongObject **r); + +PyMPN_INTERNAL(PyLongObject*) PyMPN_FromByteArray( + const unsigned char* bytes, size_t n, + int little_endian, int is_signed); +PyMPN_INTERNAL(int) PyMPN_AsByteArray(PyLongObject* v, + unsigned char* bytes, size_t n, + int little_endian, int is_signed); diff --git a/Objects/mpnobject/misc.c b/Objects/mpnobject/misc.c new file mode 100644 index 0000000..9436acd --- /dev/null +++ b/Objects/mpnobject/misc.c @@ -0,0 +1,214 @@ +#include "internal.h" +Py_LOCAL_INLINE(int) +cmpabslsh(PyLongObject *a, PyLongObject *b, size_t n){ + size_t i=abss(b), as=abss(a); + size_t whole=n/GMP_NUMB_BITS; + n%=GMP_NUMB_BITS; + for(;i--;){ + mp_limb_t da, db=b->digits[i]; + if(i>=whole){ + if(i-whole < as) da=a->digits[i-whole]<whole){ + da|=a->digits[i-whole-1]>>(GMP_NUMB_BITS-n); + } + }else da=0; + if(dadb){ + return 1; + } + } + return 0; +} + +Py_LOCAL_INLINE(double) +PyMPN_TrueDivAndExp(PyLongObject *a, PyLongObject *b, Py_ssize_t *e){ + Py_ssize_t shift; + double v; + PyLongObject *c; + int sign=prod2_signof(a, b); + if(Py_SIZE(b)==0){ + PyErr_SetString(PyExc_ZeroDivisionError, "integer division or modulo by zero"); + return -1.0; + } + if(Py_SIZE(a)==0){ + *e=0; + if(signof(b)) return -0.0; + else return 0.0; + } + shift=PyMPN_SizeInBase(b, 2)-PyMPN_SizeInBase(a, 2); + if(shift>=0){ + if(cmpabslsh(a, b, shift)<0){ + shift++; + } + }else{ + if(cmpabslsh(b, a, -shift)>0){ + shift++; + } + } + shift+=DBL_MANT_DIG-1; + if(shift>0){ + a=_PyMPN_LShiftU(a, shift, 0); + }else{ + Py_INCREF(a); + if(Py_SIZE(a)<0) PyMPN_Negate(&a); + } + if(shift<0){ + b=_PyMPN_LShiftU(b, -shift, 0); + }else{ + Py_INCREF(b); + if(Py_SIZE(b)<0) PyMPN_Negate(&b); + } + + PyMPN_DivModNear(a, b, &c, NULL); + Py_DECREF(a); + Py_DECREF(b); + v=PyMPN_AsDoubleAndExp(c, e); + if(v==-1.0 && PyErr_Occurred()) return -1.0; + if(sign) v=-v; + *e-=shift; + return v; +} + +PyMPN_INTERNAL(PyLongObject*) +PyMPN_GCD(PyLongObject *a, PyLongObject *b){ + PyLongObject *res; + mp_limb_t *tmp, *da, *db, *stA, *stB; + size_t sa, sb, sc, shiftA=0, shiftB=0, shiftC=0; + if(Py_SIZE(a)==0){ + b=PyMPN_ToMPN(b); + if(signof(b)) PyMPN_Negate(&b); + return b; + } + if(Py_SIZE(b)==0){ + a=PyMPN_ToMPN(a); + if(signof(a)) PyMPN_Negate(&a); + return a; + } + sa=abss(a); + sb=abss(b); + if(sb==1){ + return PyMPN_FromDigitSgn(mpn_gcd_1(a->digits, sa, b->digits[0]), 0); + } + if(sa==1){ + return PyMPN_FromDigitSgn(mpn_gcd_1(b->digits, sb, a->digits[0]), 0); + } + + da=a->digits; + while(sa && *da==0){ + sa--; + da++; + shiftA++; + } + + db=b->digits; + while(sb && *db==0){ + sb--; + db++; + shiftB++; + } + + Py_MAYBE_RELEASE_GIL_BEGIN(Py_MIN(sa, sb)>=16) + + if(sa==1 || sb==1){ + mp_limb_t r; + shiftC=Py_MIN(shiftA, shiftB); + if(sb==1){ + r=mpn_gcd_1(da, sa, *db); + }else{ + r=mpn_gcd_1(db, sb, *da); + } + Py_MAYBE_RELEASE_GIL_PRE_END + if(shiftC==0){ + res=PyMPN_FromDigitSgn(r, 0); + }else{ + res=PyMPN_New(shiftC+1); + mpn_zero(res->digits, shiftC); + res->digits[shiftC]=r; + } + }else{ + size_t extra; + shiftA=shiftA*GMP_NUMB_BITS+limbTZ(*da); + shiftB=shiftB*GMP_NUMB_BITS+limbTZ(*db); + shiftC=Py_MIN(shiftA, shiftB); + extra=(shiftC+GMP_NUMB_BITS-1)/GMP_NUMB_BITS; + + tmp=(mp_limb_t*)PyMem_RawMalloc(sizeof(mp_limb_t)*(Py_MAX(sa, extra)+sb)); + + stA=tmp; + stB=stA+sa; + if(shiftA%GMP_NUMB_BITS){ + mpn_rshift(stA, da, sa, shiftA%GMP_NUMB_BITS); + if(da[sa-1]==0) sa--; + }else mpn_copyi(stA, da, sa); + if(shiftB%GMP_NUMB_BITS){ + mpn_rshift(stB, db, sb, shiftB%GMP_NUMB_BITS); + if(db[sb-1]==0) sb--; + }else mpn_copyi(stB, db, sb); + + if(sadigits, extra); + mpn_copyi(res->digits+extra, tmp, sc); + }else{ + res->digits[sb+extra-1]=mpn_lshift(res->digits+extra-1, tmp, sb, shiftC%GMP_NUMB_BITS); + _PyMPN_Norm(res); + } + } + PyMem_RawFree(tmp); + } + + Py_MAYBE_RELEASE_GIL_END + + return res; +} + +PyMPN_INTERNAL(double) +PyMPN_TrueDiv(PyLongObject *a, PyLongObject *b){ + Py_ssize_t e; + double v=PyMPN_TrueDivAndExp(a, b, &e); + if(v==-1.0 && PyErr_Occurred()) return -1.0; + return PyMPN_check_ldexp(v, e); +} + +PyMPN_INTERNAL(int) +PyMPN_Compare(PyLongObject *a, PyLongObject *b){ + int r; + if(Py_SIZE(a)Py_SIZE(b)){ + return 1; + } + if(Py_SIZE(a)==1){ + if(a->digits[0]digits[0]) return -1; + if(a->digits[0]>b->digits[0]) return 1; + return 0; + } + if(Py_SIZE(a)==-1){ + if(a->digits[0]digits[0]) return 1; + if(a->digits[0]>b->digits[0]) return -1; + return 0; + } + r=mpn_cmp(a->digits, b->digits, abss(a)); + if(signof(a)){ + r=-r; + } + return r; +} diff --git a/Objects/mpnobject/mul-div.c b/Objects/mpnobject/mul-div.c new file mode 100644 index 0000000..39d5a86 --- /dev/null +++ b/Objects/mpnobject/mul-div.c @@ -0,0 +1,199 @@ +#include "internal.h" + +PyMPN_INTERNAL(PyLongObject*) +PyMPN_Mul(PyLongObject *a, PyLongObject *b){ + size_t sa=abss(a); + size_t sb=abss(b); + const mp_limb_t halfLimb=((mp_limb_t)1)<<(GMP_NUMB_BITS/2); + PyLongObject *c; + if(sa==0 || sb==0){ + return PyMPN_FromDigitSgn(0, 0); + } + if(sa==1 && sb==1){ + if(a->digits[0]digits[0]digits[0]*b->digits[0], prod2_signof(a, b)); + } + } + c=PyMPN_New(sa+sb); + if(!c) return NULL; + + Py_MAYBE_RELEASE_GIL_BEGIN(sa+sb>=64) + if(sa >= sb){ + mpn_mul(c->digits, a->digits, sa, b->digits, sb); + }else{ + mpn_mul(c->digits, b->digits, sb, a->digits, sa); + } + _PyMPN_Norm(c); + if(prod2_signof(a, b)){ + Py_SIZE(c)=-Py_SIZE(c); + } + Py_MAYBE_RELEASE_GIL_END + return c; +} + +PyMPN_INTERNAL(void) +PyMPN_DivMod(PyLongObject *a, PyLongObject *b, PyLongObject **q, PyLongObject **r){ + size_t sa=abss(a); + size_t sb=abss(b); + size_t sq; + int canOverflow; + PyLongObject *qv, *rv; + if(sb==0){ + PyErr_SetString(PyExc_ZeroDivisionError, "division by zero"); + return; + } + if(!q && !r) return; + if(q) *q=NULL; + if(r) *r=NULL; + if(sa==0){ + if(q) *q=PyMPN_FromDigitSgn(0, 0); + if(r) *r=PyMPN_FromDigitSgn(0, 0); + } + if(sadigits[0]/b->digits[0], rd=a->digits[0]%b->digits[0]; + if(rd!=0 && prod2_signof(a, b)){ + rd=b->digits[0]-rd; + qd++; + } + if(q) *q=PyMPN_FromDigitSgn(qd, prod2_signof(a, b)); + if(r){ + *r=PyMPN_FromDigitSgn(rd, signof(b)); + if(!*r && q) Py_CLEAR(*q); + } + }else if(!q){ + mp_limb_t rd=mpn_mod_1(a->digits, sa, b->digits[0]); + if(rd!=0 && prod2_signof(a, b)){ + rd=b->digits[0]-rd; + } + *r=PyMPN_FromDigitSgn(rd, signof(b)); + }else{ + mp_limb_t rd; + qv=PyMPN_New(sa); + if(!qv){ + return; + } + rd=mpn_divrem_1(qv->digits, 0, a->digits, sa, b->digits[0]); + if(rd!=0 && prod2_signof(a, b)){ + rd=b->digits[0]-rd; + mpn_add_1(qv->digits, qv->digits, sa, 1); + } + _PyMPN_Norm(qv); + if(prod2_signof(a, b)){ + Py_SIZE(qv)=-Py_SIZE(qv); + } + *q=qv; + if(r){ + *r=PyMPN_FromDigitSgn(rd, signof(b)); + if(!*r) Py_CLEAR(*q); + } + } + return; + } + sq=sa-sb+1; + if(prod2_signof(a, b) && a->digits[sa-1]==GMP_NUMB_MAX && b->digits[sb-1]==1){ + canOverflow=1; + }else{ + canOverflow=0; + } + qv=PyMPN_New(sq+canOverflow); + if(canOverflow) qv->digits[sq]=0; + if(!qv) return; + rv=PyMPN_New(sb); + if(!rv){ + Py_DECREF(qv); + return; + } + + Py_MAYBE_RELEASE_GIL_BEGIN(sq+sb>=64) + mpn_tdiv_qr(qv->digits, rv->digits, 0, a->digits, sa, b->digits, sb); + if(prod2_signof(a, b)){ + size_t i; + for(i=0;i!=sb;i++){ + if(rv->digits[i]!=0) break; + } + if(i!=sb){ + mp_limb_t carry; + mpn_sub_n(rv->digits, b->digits, rv->digits, sb); + carry=mpn_add_1(qv->digits, qv->digits, sq, 1); + if(carry){ + assert(canOverflow); + qv->digits[sq]=carry; // only if canOverflow + } + } + } + if(q){ + _PyMPN_Norm(qv); + if(prod2_signof(a, b)){ + Py_SIZE(qv)=-Py_SIZE(qv); + } + } + if(r){ + _PyMPN_Norm(rv); + if(signof(b)){ + Py_SIZE(rv)=-Py_SIZE(rv); + } + } + Py_MAYBE_RELEASE_GIL_END + + if(q) *q=qv; + else Py_DECREF(qv); + if(r) *r=rv; + else Py_DECREF(rv); + return; +} + +void PyMPN_DivModNear(PyLongObject *a, PyLongObject *b, PyLongObject **q, PyLongObject **r){ + PyLongObject *qv=NULL, *rv=NULL, *tmp, *halfQ; + int unexpect=signof(b)?-1:1, cmp; + PyMPN_DivMod(a, b, &qv, &rv); + halfQ=_PyMPN_RShiftU(b, 1, 0); + if(signof(b)) PyMPN_Negate(&halfQ); + cmp=PyMPN_Compare(rv, halfQ); + if(cmp==0 && b->digits[0]%2==0){ + if(Py_SIZE(qv)!=0 && qv->digits[0]%2!=0){ + cmp=unexpect; + } + } + if(cmp==unexpect){ + if(q){ + tmp=PyMPN_Add(qv, PyMPN_SmallWeak(1)); + *q=tmp; + } + Py_DECREF(qv); + if(r){ + *r=PyMPN_Sub(rv, b); + } + Py_DECREF(rv); + }else{ + if(q){ + *q=qv; + }else{ + Py_DECREF(qv); + } + if(r){ + *r=rv; + }else{ + Py_DECREF(rv); + } + } + return; +} diff --git a/Objects/mpnobject/pow.c b/Objects/mpnobject/pow.c new file mode 100644 index 0000000..a28cb98 --- /dev/null +++ b/Objects/mpnobject/pow.c @@ -0,0 +1,106 @@ +#include "internal.h" +Py_LOCAL_INLINE(PyLongObject*) +PyMPN_Pow1(PyLongObject *a, size_t b){ +#define MULT(X, Y, result) \ + do { \ + PyLongObject *temp=PyMPN_Mul(X, Y); \ + if (temp == NULL) \ + goto error; \ + Py_DECREF(result); \ + result=temp; \ + } while(0) + PyLongObject *r; + if(b==1){ + return PyMPN_ToMPN(a); + }else if(b==2){ + return PyMPN_Mul(a, a); + } + r=PyMPN_Small(1); + Py_INCREF(a); + while(b){ + if(b&1){ + MULT(a, r, r); + } + MULT(a, a, a); + b>>=1; + } + Py_DECREF(a); + return r; + error: + Py_XDECREF(r); + Py_XDECREF(a); + return NULL; +} + +Py_LOCAL_INLINE(PyObject*) +PyMPN_Pow(PyLongObject *a, PyLongObject *b){ + if(Py_SIZE(b) == 0){ + return (PyObject*)PyMPN_Small(1); + } + if(signof(b)){ + return PyFloat_Type.tp_as_number->nb_power((PyObject*)a, (PyObject*)b, Py_None); + } + if(Py_SIZE(a)==1){ + if(a->digits[0]==1){ + return (PyObject*)PyMPN_ToMPN(a); + } + } + if(Py_SIZE(a)==-1){ + if(a->digits[0]==1){ + return (PyObject*)PyMPN_FromDigitSgn(1, b->digits[0]%2); + } + } + if(Py_SIZE(b)==1){ + return (PyObject*)PyMPN_Pow1(a, b->digits[0]); + } + return PyErr_NoMemory(); +} +Py_LOCAL_INLINE(PyLongObject*) +PyMPN_PowM(PyLongObject *a, PyLongObject *b, PyLongObject *c){ + mpz_t res_mpz, a_mpz, b_mpz, c_mpz; + PyLongObject *res; + if(Py_SIZE(c)==0){ + PyErr_SetString(PyExc_ZeroDivisionError, "division by zero"); + return NULL; + } + if(Py_SIZE(b)==0){ + if(Py_SIZE(c)==1 && c->digits[0]==1){ + return PyMPN_Small(0); + }else{ + return PyMPN_Small(1); + } + } + if(signof(b)){ + PyErr_SetString(PyExc_ValueError, "pow() 2nd argument " + "cannot be negative when 3rd argument specified"); + return NULL; + } + if(signof(a) || signof(c)){ + PyErr_SetNone(PyExc_NotImplementedError); + return NULL; + } + mpz_roinit_n(a_mpz, a->digits, Py_SIZE(a)); + mpz_roinit_n(b_mpz, b->digits, Py_SIZE(b)); + mpz_roinit_n(c_mpz, c->digits, Py_SIZE(c)); + mpz_init(res_mpz); + + Py_MAYBE_RELEASE_GIL_BEGIN(Py_SIZE(b)>=16 && Py_SIZE(c)>=16) + mpz_powm(res_mpz, a_mpz, b_mpz, c_mpz); + Py_MAYBE_RELEASE_GIL_END + + res=PyMPN_New(mpz_size(res_mpz)); + if(!res){ + mpz_clear(res_mpz); + return NULL; + } + mpn_copyi(res->digits, mpz_limbs_read(res_mpz), Py_SIZE(res)); + mpz_clear(res_mpz); + _PyMPN_Norm(res); + if(!signof(res) && signof(c)){ + Py_SIZE(res)=-Py_SIZE(c); + mpn_sub_n(res->digits, res->digits, c->digits, Py_SIZE(res)); + _PyMPN_Norm(res); + Py_SIZE(res)=-Py_SIZE(res); + } + return res; +} diff --git a/Objects/mpnobject/pylong-api.c b/Objects/mpnobject/pylong-api.c new file mode 100644 index 0000000..01aa0a6 --- /dev/null +++ b/Objects/mpnobject/pylong-api.c @@ -0,0 +1,253 @@ +#include "internal.h" +#define CONV(T, Name) \ +T PyLong_As##Name(PyObject *a){ \ + T res; \ + if(PyObject_TypeCheck(a, &PyLong_Type)){ \ + Py_INCREF(a); \ + }else{ \ + a=(PyObject*)_PyLong_FromNbInt(a); \ + if(!a) return -1; \ + } \ + res=PyMPN_As##Name((PyLongObject*)a); \ + Py_DECREF(a); \ + return res; \ +} +PyObject *PyLong_FromLong(long a){ + return (PyObject*)PyMPN_FromLong(a); +} +PyObject *PyLong_FromUnsignedLong(unsigned long a){ + return (PyObject*)PyMPN_FromUnsignedLong(a); +} +PyObject *PyLong_FromSize_t(size_t a){ + return (PyObject*)PyMPN_FromSize_t(a); +} +PyObject *PyLong_FromSsize_t(Py_ssize_t a){ + return (PyObject*)PyMPN_FromSsize_t(a); +} +PyObject *PyLong_FromDouble(double a){ + return (PyObject*)PyMPN_FromDouble(a); +} +long PyLong_AsLongAndOverflow(PyObject *a, int *ov){ + long res; + if(PyObject_TypeCheck(a, &PyLong_Type)){ + Py_INCREF(a); + }else{ + a=(PyObject*)_PyLong_FromNbInt(a); + if(!a) return -1; \ + } + res=PyMPN_AsLongAndOverflow((PyLongObject*)a, ov); + Py_DECREF(a); + return res; +} +CONV(long, Long) +CONV(Py_ssize_t, Ssize_t) +CONV(size_t, Size_t) +CONV(unsigned long, UnsignedLong) +CONV(unsigned long, UnsignedLongMask) +int _PyLong_AsInt(PyObject *a){ + int res; + if(PyObject_TypeCheck(a, &PyLong_Type)){ + Py_INCREF(a); + }else{ + a=(PyObject*)_PyLong_FromNbInt(a); + if(!a) return -1; + } + res=PyMPN_AsInt((PyLongObject*)a); + Py_DECREF(a); + return res; +} + +double _PyLong_Frexp(PyLongObject *a, Py_ssize_t *e){ + return PyMPN_AsDoubleAndExp(a, e); +} + +CONV(double, Double) +PyObject *PyLong_FromVoidPtr(void *a){ + return PyLong_FromSize_t((size_t)a); +} +void * PyLong_AsVoidPtr(PyObject *a){ + return (void*)PyLong_AsSize_t(a); +} + +#ifdef HAVE_LONG_LONG +PyObject *PyLong_FromLongLong(PY_LONG_LONG a){ + return (PyObject*)PyMPN_FromLongLong(a); +} +PyObject* PyLong_FromUnsignedLongLong(unsigned PY_LONG_LONG a){ + return (PyObject*) PyMPN_FromUnsignedLongLong(a); +} + +CONV(long long, LongLong) +CONV(unsigned long long, UnsignedLongLong) +CONV(unsigned long long, UnsignedLongLongMask) +PY_LONG_LONG PyLong_AsLongLongAndOverflow(PyObject *a, int *ov){ + long long res; + if(PyObject_TypeCheck(a, &PyLong_Type)){ + Py_INCREF(a); + }else{ + a=(PyObject*)_PyLong_FromNbInt(a); + if(!a) return -1; + } + res=PyMPN_AsLongLongAndOverflow((PyLongObject*)a, ov); + Py_DECREF(a); + return res; +} +#endif /* HAVE_LONG_LONG */ + +PyObject *PyLong_FromString(const char *str, char **end, int base){ + if(end){ + size_t used; + PyObject *res=(PyObject*)_PyMPN_FromBytes(base, str, strlen(str), &used, NULL); + *end=(char*)str+used; + return res; + }else{ + return (PyObject*)_PyMPN_FromBytes(base, str, strlen(str), NULL, NULL); + } +} +PyObject *PyLong_FromUnicode(Py_UNICODE *data, Py_ssize_t size, int base){ + PyObject *u=PyUnicode_FromUnicode(data, size); + PyObject *res=PyLong_FromUnicodeObject(u, base); + Py_DECREF(u); + return res; +} +PyObject *PyLong_FromUnicodeObject(PyObject *u, int base){ + return (PyObject*)PyMPN_FromStringOrBuffer(u, base); +} +PyObject *_PyLong_FromBytes(const char *data, Py_ssize_t size, int base){ + return (PyObject*)_PyMPN_FromBytes(base, data, size, NULL, NULL); +} + +int _PyLong_Sign(PyObject *v){ + if(Py_SIZE(v)>0) return 1; + if(Py_SIZE(v)<0) return -1; + return 0; +} +size_t _PyLong_NumBits(PyObject *a){ + size_t res; + if(!PyLong_Check(a)){ + PyErr_SetString(PyExc_TypeError, "an integer is required"); + return -1; + } + res=PyMPN_SizeInBase((PyLongObject*)a, 2); + return res; +} +PyObject *_PyLong_DivmodNear(PyObject *a, PyObject *b){ + PyLongObject *ra, *rb; + PyObject *res; + if(!PyLong_Check(a) || !PyLong_Check(b)){ + PyErr_SetString(PyExc_TypeError, + "non-integer arguments in division"); + return NULL; + } + PyMPN_DivModNear((PyLongObject*)a, (PyLongObject*)b, &ra, &rb); + if(!ra || !rb){ + return NULL; + } + res=PyTuple_New(2); + if(!res){ + Py_DECREF(ra); + Py_DECREF(rb); + return NULL; + } + PyTuple_SET_ITEM(res, 0, (PyObject*)ra); + PyTuple_SET_ITEM(res, 1, (PyObject*)rb); + return res; +} +PyObject *_PyLong_FromByteArray( + const unsigned char* bytes, size_t n, + int little_endian, int is_signed){ + return (PyObject*)PyMPN_FromByteArray(bytes, n, little_endian, is_signed); +} +int _PyLong_AsByteArray(PyLongObject* v, + unsigned char* bytes, size_t n, + int little_endian, int is_signed){ + return PyMPN_AsByteArray(v, bytes, n, little_endian, is_signed); +} + +PyLongObject * _PyLong_New(Py_ssize_t n){ + return PyMPN_New(n); +} + +PyObject *_PyLong_Copy(PyLongObject *src){ + Py_INCREF(src); + return (PyObject*)src; +} + +PyLongObject * +_PyLong_FromNbInt(PyObject *integral) +{ + PyNumberMethods *nb; + PyObject *result; + + /* Fast path for the case that we already have an int. */ + if (PyLong_CheckExact(integral)) { + Py_INCREF(integral); + return (PyLongObject *)integral; + } + + nb = Py_TYPE(integral)->tp_as_number; + if (nb == NULL || nb->nb_int == NULL) { + PyErr_Format(PyExc_TypeError, + "an integer is required (got type %.200s)", + Py_TYPE(integral)->tp_name); + return NULL; + } + + /* Convert using the nb_int slot, which should return something + of exact type int. */ + result = nb->nb_int(integral); + if (!result || PyLong_CheckExact(result)) + return (PyLongObject *)result; + if (!PyLong_Check(result)) { + PyErr_Format(PyExc_TypeError, + "__int__ returned non-int (type %.200s)", + result->ob_type->tp_name); + Py_DECREF(result); + return NULL; + } + /* Issue #17576: warn if 'result' not of exact type int. */ + if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, + "__int__ returned non-int (type %.200s). " + "The ability to return an instance of a strict subclass of int " + "is deprecated, and may be removed in a future version of Python.", + result->ob_type->tp_name)) { + Py_DECREF(result); + return NULL; + } + return (PyLongObject *)result; +} + +PyObject *_PyLong_Format(PyObject *obj, int base){ + return PyMPN_AsString((PyLongObject*)obj, base, 1); +} + +int _PyLong_FormatWriter(_PyUnicodeWriter *writer, + PyObject *obj, + int base, int alternate){ + PyObject *str=PyMPN_AsString((PyLongObject*)obj, base, alternate); + int r; + if(!str) return -1; + r=_PyUnicodeWriter_WriteStr(writer, str); + if(r<0) return -1; + Py_DECREF(str); + return 0; +} + +unsigned char _PyLong_DigitValue[256] = { + 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 37, 37, 37, 37, 37, 37, + 37, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 37, 37, 37, 37, 37, + 37, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, +}; diff --git a/Objects/mpnobject/string.c b/Objects/mpnobject/string.c new file mode 100644 index 0000000..2142cc8 --- /dev/null +++ b/Objects/mpnobject/string.c @@ -0,0 +1,360 @@ +#include "internal.h" + +Py_LOCAL_INLINE(size_t) +PyMPN_GetAsBytes(const PyLongObject *a, unsigned char *bytes, size_t bytesN, int base, int little_endian){ + size_t n=abss(a), m, i; + Py_MAYBE_RELEASE_GIL_BEGIN((base&(base-1))?n>=256:n>=64) + + if(base&(base-1)){ + mp_limb_t *mem=PyMem_RawMalloc(sizeof(mp_limb_t)*n); + mpn_copyi(mem, a->digits, n); + m=mpn_get_str(bytes, base, mem, n); + PyMem_RawFree(mem); + }else{ + m=mpn_get_str(bytes, base, (mp_limb_t*)a->digits, n); // Will not modify + } + if(little_endian){ + for(i=0;i 2**64: + return i-1 +print('0, 0, '+', '.join(str(f(i)) for i in range(2,257))) + */ + +#if GMP_NUMB_BITS == 64 +static const size_t limb_digits[257]={ + 0, 0, 64, 40, 32, 27, 24, 22, 21, 20, 19, 18, 17, 17, 16, 16, 16, 15, 15, 15, 14, 14, 14, 14, 13, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 +}; +#elif GMP_NUMB_BITS == 32 +static const size_t limb_digits[257]={ + 0, 0, 32, 20, 16, 13, 12, 11, 10, 10, 9, 9, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 +}; +#else +#error TODO: Non-32/64-bit limbs +#endif + +Py_LOCAL_INLINE(size_t) _PyMPN_LimbsForString(size_t len, int base){ + return (len+limb_digits[base]-1)/limb_digits[base]; +} + +void _PyMPN_CompactDigits(mp_limb_t *stA, size_t size, mp_limb_t base){ + mp_limb_t *scratch=PyMem_NEW(mp_limb_t, 2*size); + mp_limb_t *stBase=scratch+size; + size_t block, baseSize, i, bOff=0; + + Py_MAYBE_RELEASE_GIL_BEGIN(size>=64) + + for(i=0;i+1=rSize){ + mpn_mul(scratch, stBase, baseSize, cur+block, rSize); + }else{ + mpn_mul(scratch, cur+block, rSize, stBase, baseSize); + } + mpn_zero(cur+block, rSize); + mpn_add(cur+bOff, cur+bOff, block+rSize-bOff, scratch, scratchSize); + } + } + + PyMem_FREE(scratch); + + Py_MAYBE_RELEASE_GIL_END + return; +} + +PyLongObject* _PyMPN_FromBytes(int base, const char *begin, size_t len, size_t *used, PyObject *nice){ + static const unsigned char digitTab[256]={ + 99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99, + 99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99, + 99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,99,99,99,99,99,99, + 99,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24, + 25,26,27,28,29,30,31,32,33,34,35,99,99,99,99,99, + 99,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24, + 25,26,27,28,29,30,31,32,33,34,35,99,99,99,99,99, + 99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99, + 99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99, + 99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99, + 99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99, + 99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99, + 99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99, + 99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99, + 99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99, + }; + const char *end=begin+len, *cur=begin, *tmp; + PyLongObject *mpn; + int sign, starts_0=0; + size_t alloc; + + while(cur!=end && (*cur==' '||*cur=='\t'||*cur=='\n')) cur++; + tmp=end; + while(tmp!=cur && (tmp[-1]==' '||tmp[-1]=='\t'||tmp[-1]=='\n')) tmp--; + if(used) *used=end-tmp; + end=tmp; + if(cur==end){ + if(nice){ + PyErr_Format(PyExc_ValueError, "invalid literal for int() with base %d: %.200R", base, nice); + }else{ + PyErr_Format(PyExc_ValueError, "invalid literal for int() with base %d", base); + } + return NULL; + } + + if(*cur=='-'){ + sign=1; + ++cur; + }else if(*cur=='+'){ + sign=0; + ++cur; + }else{ + sign=0; + } + if(base==0){ + base=10; + if(cur+2 <= end && *cur == '0'){ + char next=*(cur+1); + if(next=='b' || next=='B'){ + cur+=2; + base=2; + }else if(next=='o' || next=='O'){ + cur+=2; + base=8; + }else if(next=='x' || next=='X'){ + cur+=2; + base=16; + }else{ + starts_0=1; + } + } + }else if(base==2 && cur+2=base){ + if(nice){ + PyErr_Format(PyExc_ValueError, "invalid literal for int() with base %d: %.200R", base, nice); + }else{ + PyErr_Format(PyExc_ValueError, "invalid literal for int() with base %d", base); + } + return NULL; + } + while(cur!=end && *cur=='0') cur++; + tmp=cur; + if(starts_0 && cur!=end){ + if(nice){ + PyErr_Format(PyExc_ValueError, "invalid literal for int() with base %d: %.200R", base, nice); + }else{ + PyErr_Format(PyExc_ValueError, "invalid literal for int() with base %d", base); + } + return NULL; + } + while(cur!=end){ + char c=*cur; + if(digitTab[(unsigned char)c]>=base) break; + cur++; + } + if(used){ + *used+=cur-begin; + }else if(end!=cur){ + if(nice){ + PyErr_Format(PyExc_ValueError, "invalid literal for int() with base %d: %.200R", base, nice); + }else{ + PyErr_Format(PyExc_ValueError, "invalid literal for int() with base %d", base); + } + return NULL; + } + + end=cur; + begin=tmp; + if(end==begin){ + return PyMPN_FromDigitSgn(0, 0); + } + + alloc=_PyMPN_LimbsForString(end-begin, base); + if(alloc==1){ + mp_limb_t r=0; + while(begin!=end){ + r*=base; + r+=digitTab[(unsigned char)*begin]; + ++begin; + } + mpn=PyMPN_FromDigitSgn(r, sign); + }else{ + size_t perLimb=limb_digits[base], i, j, last; + mp_limb_t r, newBase=1; + mpn=PyMPN_New(alloc); + for(j=0;jdigits[i-1]=r; + } + last=end-begin-(alloc-1)*perLimb; + r=0; + for(j=0;jdigits[alloc-1]=r; + + if(newBase!=0) _PyMPN_CompactDigits(mpn->digits, Py_SIZE(mpn), newBase); + _PyMPN_Norm(mpn); + + if(sign) Py_SIZE(mpn)=-Py_SIZE(mpn); + } + return mpn; +} + +PyLongObject *PyMPN_FromStringOrBuffer(PyObject *u, int base){ + PyLongObject *res=NULL; + PyObject *prep=_PyMPN_PrepareString(u, base); + if(!prep) return NULL; + res=_PyMPN_FromBytes(base, PyBytes_AS_STRING(prep), PyBytes_GET_SIZE(prep), NULL, u); + Py_DECREF(prep); + return res; +} + diff --git a/Objects/mpnobject/type.c b/Objects/mpnobject/type.c new file mode 100644 index 0000000..53416ce --- /dev/null +++ b/Objects/mpnobject/type.c @@ -0,0 +1,572 @@ +#include "internal.h" + +#define CHECK_OP(v) \ + do { \ + if (!PyLong_Check(v)) \ + Py_RETURN_NOTIMPLEMENTED; \ + } while(0) + +static PyObject *pympn_add(PyObject *a, PyObject *b){ + CHECK_OP(a); + CHECK_OP(b); + return (PyObject*)PyMPN_Add((PyLongObject*)a, (PyLongObject*)b); +} +static PyObject *pympn_sub(PyObject *a, PyObject *b){ + CHECK_OP(a); + CHECK_OP(b); + return (PyObject*)PyMPN_Sub((PyLongObject*)a, (PyLongObject*)b); +} +static PyObject *pympn_mul(PyObject *a, PyObject *b){ + CHECK_OP(a); + CHECK_OP(b); + return (PyObject*)PyMPN_Mul((PyLongObject*)a, (PyLongObject*)b); +} +static PyObject *pympn_mod(PyObject *a, PyObject *b){ + PyLongObject *r=NULL; + CHECK_OP(a); + CHECK_OP(b); + PyMPN_DivMod((PyLongObject*)a, (PyLongObject*)b, NULL, &r); + return (PyObject*)r; +} +static PyObject *pympn_div(PyObject *a, PyObject *b){ + PyLongObject *q=NULL; + CHECK_OP(a); + CHECK_OP(b); + PyMPN_DivMod((PyLongObject*)a, (PyLongObject*)b, &q, NULL); + return (PyObject*)q; +} +static PyObject *pympn_divmod(PyObject *a, PyObject *b){ + PyObject *z=PyTuple_New(2); + PyLongObject *q=NULL, *r=NULL; + if(!z){ + return NULL; + } + CHECK_OP(a); + CHECK_OP(b); + PyMPN_DivMod((PyLongObject*)a, (PyLongObject*)b, &q, &r); + PyTuple_SetItem(z, 0, (PyObject*)q); + PyTuple_SetItem(z, 1, (PyObject*)r); + return z; +} +static PyObject *pympn_pow(PyObject *a, PyObject *b, PyObject *m){ + CHECK_OP(a); + CHECK_OP(b); + if(m==Py_None){ + return (PyObject*)PyMPN_Pow((PyLongObject*)a, (PyLongObject*)b); + }else{ + CHECK_OP(m); + return (PyObject*)PyMPN_PowM((PyLongObject*)a, (PyLongObject*)b, (PyLongObject*)m); + } +} +static PyObject *pympn_neg(PyObject *a){ + PyLongObject *al=(PyLongObject*)a; + Py_INCREF(al); + PyMPN_Negate(&al); + return (PyObject*)al; +} +static PyObject *pympn_abs(PyObject *a){ + if(signof(a)){ + return pympn_neg(a); + } + return (PyObject*)PyMPN_ToMPN((PyLongObject*)a); +} +static int pympn_bool(PyObject *a){ + return Py_SIZE(a)!=0; +} +static PyObject *pympn_richcompare(PyObject *a, PyObject *b, int op){ + int r; + CHECK_OP(a); + CHECK_OP(b); + if(a==b){ + r=0; + }else{ + r=PyMPN_Compare((PyLongObject*)a, (PyLongObject*)b); + } + switch(op){ + case Py_LT: + return PyBool_FromLong(r==-1); + case Py_LE: + return PyBool_FromLong(r!=1); + case Py_GT: + return PyBool_FromLong(r==1); + case Py_GE: + return PyBool_FromLong(r!=-1); + case Py_EQ: + return PyBool_FromLong(r==0); + case Py_NE: + return PyBool_FromLong(r!=0); + } + Py_RETURN_NOTIMPLEMENTED; +} + +static PyObject *pympn_invert(PyObject *a){ + PyLongObject *al=(PyLongObject*)a; + Py_INCREF(al); + PyMPN_Invert(&al); + return (PyObject*)al; +} +static PyObject *pympn_lshift(PyObject *a, PyObject *b){ + CHECK_OP(a); + CHECK_OP(b); + return (PyObject*)PyMPN_LShift((PyLongObject*)a, (PyLongObject*)b); +} +static PyObject *pympn_rshift(PyObject *a, PyObject *b){ + CHECK_OP(a); + CHECK_OP(b); + return (PyObject*)PyMPN_RShift((PyLongObject*)a, (PyLongObject*)b); +} + +static PyObject *pympn_and(PyObject *a, PyObject *b){ + CHECK_OP(a); + CHECK_OP(b); + return (PyObject*)PyMPN_And((PyLongObject*)a, (PyLongObject*)b); +} +static PyObject *pympn_or(PyObject *a, PyObject *b){ + CHECK_OP(a); + CHECK_OP(b); + return (PyObject*)PyMPN_Or((PyLongObject*)a, (PyLongObject*)b); +} +static PyObject *pympn_xor(PyObject *a, PyObject *b){ + CHECK_OP(a); + CHECK_OP(b); + return (PyObject*)PyMPN_Xor((PyLongObject*)a, (PyLongObject*)b); +} + +static PyObject *pympn_float(PyObject *a){ + double r=PyMPN_AsDouble((PyLongObject*)a); + if(r==-1.0 && PyErr_Occurred()) return NULL; + return PyFloat_FromDouble(r); +} + +static PyObject *pympn_true_divide(PyObject *a, PyObject *b){ + double r; + CHECK_OP(a); + CHECK_OP(b); + r=PyMPN_TrueDiv((PyLongObject*)a, (PyLongObject*)b); + if(r==-1.0 && PyErr_Occurred()) return NULL; + return PyFloat_FromDouble(r); +} + +static PyObject *pympn_bit_length(PyObject *v){ + return (PyObject*)PyMPN_FromDigitSgn(PyMPN_SizeInBase((PyLongObject*)v, 2), 0); +} + +static PyObject * pympn_get0(PyLongObject *v, void *context){ + (void)v; + (void)context; + return (PyObject*)PyMPN_Small(0); +} + +static PyObject * pympn_get1(PyLongObject *v, void *context){ + (void)v; + (void)context; + return (PyObject*)PyMPN_Small(1); +} + +static PyObject * pympn_to_decimal_string(PyObject *a){ + return (PyObject*)PyMPN_AsString((PyLongObject*)a, 10, 0); +} + +static Py_hash_t pympn_hash(PyObject *a){ + Py_hash_t r=mpn_mod_1(((PyLongObject*)a)->digits, abss(a), _PyHASH_MODULUS); + if(signof(a)){ + r=-r; + } + if(r==-1){ + r=-2; + } + return r; +} + +static PyObject *pympn_new(PyTypeObject *tp, PyObject *args, PyObject *kwds){ + static const char *kwlist[] = {"x", "base", 0}; + PyLongObject *res; + PyObject *x=NULL, *obase=NULL; + Py_ssize_t base=-1; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OO:int", (char**)kwlist, + &x, &obase)) + return NULL; + + if(!obase){ + base=-1; + }else{ + base = PyNumber_AsSsize_t(obase, NULL); + if(base==-1 && PyErr_Occurred()) + return NULL; + if(base!=0 && (base < 2 || base > 36)){ + PyErr_SetString(PyExc_ValueError, "int() base must be >= 2 and <= 36"); + return NULL; + } + } + + if(!x){ + if(base!=-1){ + PyErr_SetString(PyExc_TypeError, "int() missing string argument"); + return NULL; + } + res=PyMPN_Small(0); + }else if(base==-1){ + res=(PyLongObject*)PyNumber_Long(x); + }else if(PyObject_CheckReadBuffer(x) || PyUnicode_Check(x) || PyBytes_Check(x) || PyByteArray_Check(x)){ + if(base==-1) base=0; + res=PyMPN_FromStringOrBuffer(x, base); + }else if(PyNumber_Check(x)){ + PyErr_SetString(PyExc_TypeError, "int() can't convert non-string with explicit base"); + return NULL; + }else{ + PyErr_Format(PyExc_TypeError, "int() argument must be a string or a number, not '%s'", Py_TYPE(x)->tp_name); + return NULL; + } + + if(!res) return NULL; + + if(tp!=&PyLong_Type){ + size_t n=abss(res); + PyLongObject *tmp=(PyLongObject*)tp->tp_alloc(tp, n); + Py_SIZE(tmp)=Py_SIZE(res); + mpn_copyi(tmp->digits, res->digits, n); + Py_DECREF(res); + res=tmp; + } + return (PyObject*)res; +} + +static PyObject *pympn_int(PyObject *a){ + if(Py_TYPE(a)!=&PyLong_Type){ + PyLongObject *ao=(PyLongObject*)a; + PyLongObject *b; + if(abss(ao)==1) b=PyMPN_FromDigitSgn(ao->digits[0], signof(a)); + else{ + size_t s=abss(a); + b=PyMPN_New(s); + mpn_copyi(b->digits, ao->digits, s); + if(signof(a)) Py_SIZE(b)=-s; + } + return (PyObject*)b; + }else{ + Py_INCREF(a); + return a; + } +} + +static PyObject *pympn_sizeof(PyObject *v){ + size_t res; + res=offsetof(PyLongObject, digits) + abss(v)*sizeof(mp_limb_t); + return PyLong_FromSize_t(res); +} + +static PyObject *pympn_getnewargs(PyObject *v){ + return Py_BuildValue("(N)", (PyObject*)PyMPN_ToMPN((PyLongObject*)v)); +} + +static PyObject *pympn__format__(PyObject *self, PyObject *args){ + PyObject *format_spec; + _PyUnicodeWriter writer; + int ret; + + if (!PyArg_ParseTuple(args, "U:__format__", &format_spec)) + return NULL; + + _PyUnicodeWriter_Init(&writer); + ret = _PyLong_FormatAdvancedWriter( + &writer, + self, + format_spec, 0, PyUnicode_GET_LENGTH(format_spec)); + if (ret == -1) { + _PyUnicodeWriter_Dealloc(&writer); + return NULL; + } + return _PyUnicodeWriter_Finish(&writer); +} +static PyObject *pympn_from_bytes(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *byteorder_str; + PyObject *is_signed_obj = NULL; + int little_endian; + int is_signed; + PyObject *obj; + PyObject *bytes; + PyObject *long_obj; + static char *kwlist[] = {"bytes", "byteorder", "signed", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "OU|O:from_bytes", kwlist, + &obj, &byteorder_str, + &is_signed_obj)) + return NULL; + + if (args != NULL && Py_SIZE(args) > 2) { + PyErr_SetString(PyExc_TypeError, + "'signed' is a keyword-only argument"); + return NULL; + } + + if (!PyUnicode_CompareWithASCIIString(byteorder_str, "little")) + little_endian = 1; + else if (!PyUnicode_CompareWithASCIIString(byteorder_str, "big")) + little_endian = 0; + else { + PyErr_SetString(PyExc_ValueError, + "byteorder must be either 'little' or 'big'"); + return NULL; + } + + if (is_signed_obj != NULL) { + int cmp = PyObject_IsTrue(is_signed_obj); + if (cmp < 0) + return NULL; + is_signed = cmp ? 1 : 0; + } + else { + /* If the signed argument was omitted, use False as the + default. */ + is_signed = 0; + } + + bytes = PyObject_Bytes(obj); + if (bytes == NULL) + return NULL; + + long_obj = (PyObject*)PyMPN_FromByteArray( + (unsigned char *)PyBytes_AS_STRING(bytes), Py_SIZE(bytes), + little_endian, is_signed); + Py_DECREF(bytes); + + /* If from_bytes() was used on subclass, allocate new subclass + * instance, initialize it with decoded int value and return it. + */ + if (type != &PyLong_Type && PyType_IsSubtype(type, &PyLong_Type)) { + PyLongObject *newobj; + int i; + Py_ssize_t n = abss(long_obj); + + newobj = (PyLongObject *)type->tp_alloc(type, n); + if (newobj == NULL) { + Py_DECREF(long_obj); + return NULL; + } + assert(PyLong_Check(newobj)); + Py_SIZE(newobj) = Py_SIZE(long_obj); + for (i = 0; i < n; i++) { + newobj->digits[i] = + ((PyLongObject*)long_obj)->digits[i]; + } + Py_DECREF(long_obj); + return (PyObject *)newobj; + } + + return long_obj; +} + +static PyObject *pympn_round(PyObject *self, PyObject *args){ + PyLongObject *v=(PyLongObject*)self, *r, *p, *res, *od; + PyObject *o_digits=NULL; + size_t digits=0; + + if(!PyArg_ParseTuple(args, "|O", &o_digits)){ + return NULL; + } + if(o_digits==NULL){ + return (PyObject*)PyMPN_ToMPN(v); + } + od=(PyLongObject*)PyNumber_Index(o_digits); + if(!od) return NULL; + if(Py_SIZE(od)>=0){ + return (PyObject*)PyMPN_ToMPN(v); + } + if(Py_SIZE(od)<-1 || od->digits[0] >= SIZE_MAX){ + return (PyObject*)PyMPN_Small(0); + } + digits=od->digits[0]; + + p=PyMPN_Pow1(PyMPN_SmallWeak(10), digits); + PyMPN_DivModNear(v, p, NULL, &r); + Py_DECREF(p); + res=PyMPN_Sub(v, r); + Py_DECREF(r); + return (PyObject*)res; +} + +static PyObject *pympn_to_bytes(PyLongObject *v, PyObject *args, PyObject *kwds) { + PyObject *byteorder_str; + PyObject *is_signed_obj = NULL; + Py_ssize_t length; + int little_endian; + int is_signed; + PyObject *bytes; + static char *kwlist[] = {"length", "byteorder", "signed", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "nU|O:to_bytes", kwlist, + &length, &byteorder_str, + &is_signed_obj)) + return NULL; + + if (args != NULL && Py_SIZE(args) > 2) { + PyErr_SetString(PyExc_TypeError, + "'signed' is a keyword-only argument"); + return NULL; + } + + if (!PyUnicode_CompareWithASCIIString(byteorder_str, "little")) + little_endian = 1; + else if (!PyUnicode_CompareWithASCIIString(byteorder_str, "big")) + little_endian = 0; + else { + PyErr_SetString(PyExc_ValueError, + "byteorder must be either 'little' or 'big'"); + return NULL; + } + + if (is_signed_obj != NULL) { + int cmp = PyObject_IsTrue(is_signed_obj); + if (cmp < 0) + return NULL; + is_signed = cmp ? 1 : 0; + } + else { + /* If the signed argument was omitted, use False as the + default. */ + is_signed = 0; + } + + if (length < 0) { + PyErr_SetString(PyExc_ValueError, + "length argument must be non-negative"); + return NULL; + } + + bytes = PyBytes_FromStringAndSize(NULL, length); + if (bytes == NULL) + return NULL; + + if (PyMPN_AsByteArray(v, (unsigned char *)PyBytes_AS_STRING(bytes), + length, little_endian, is_signed) < 0) { + Py_DECREF(bytes); + return NULL; + } + + return bytes; +} + +static PyObject *pympn_gcd(PyObject *a, PyObject *b){ + CHECK_OP(a); + CHECK_OP(b); + return (PyObject*)PyMPN_GCD((PyLongObject*)a, (PyLongObject*)b); +} + +static PyNumberMethods pympn_as_number = { + pympn_add, /* nb_add */ + pympn_sub, /* nb_subtract */ + pympn_mul, /* nb_multiply */ + pympn_mod, /* nb_remainder */ + pympn_divmod, /* nb_divmod */ + pympn_pow, /* nb_power */ + pympn_neg, /* nb_negative */ + pympn_int, /* tp_positive */ + pympn_abs, /* tp_absolute */ + pympn_bool, /* tp_bool */ + pympn_invert, /* nb_invert */ + pympn_lshift, /* nb_lshift */ + pympn_rshift, /* nb_rshift */ + pympn_and, /* nb_and */ + pympn_xor, /* nb_xor */ + pympn_or, /* nb_or */ + pympn_int, /* nb_int */ + 0, /* nb_reserved */ + pympn_float, /* nb_float */ + 0, /* nb_inplace_add */ + 0, /* nb_inplace_subtract */ + 0, /* nb_inplace_multiply */ + 0, /* nb_inplace_remainder */ + 0, /* nb_inplace_power */ + 0, /* nb_inplace_lshift */ + 0, /* nb_inplace_rshift */ + 0, /* nb_inplace_and */ + 0, /* nb_inplace_xor */ + 0, /* nb_inplace_or */ + pympn_div, /* nb_floor_divide */ + pympn_true_divide, /* nb_true_divide */ + 0, /* nb_inplace_floor_divide */ + 0, /* nb_inplace_true_divide */ + pympn_int, /* nb_index */ + #if PY_VERSION_HEX >= 0x03050000 + 0, /* no idea */ + 0, /* no idea */ + #endif +}; + + +static PyMethodDef pympn_methods[] = { + {"conjugate", (PyCFunction)pympn_int, METH_NOARGS, NULL}, + {"bit_length", (PyCFunction)pympn_bit_length, METH_NOARGS, NULL}, + {"to_bytes", (PyCFunction)pympn_to_bytes, METH_VARARGS|METH_KEYWORDS, NULL}, + {"from_bytes", (PyCFunction)pympn_from_bytes, METH_VARARGS|METH_KEYWORDS|METH_CLASS, NULL}, + {"__gcd__", (PyCFunction)pympn_gcd, METH_O, NULL}, + {"__trunc__", (PyCFunction)pympn_int, METH_NOARGS, NULL}, + {"__floor__", (PyCFunction)pympn_int, METH_NOARGS, NULL}, + {"__ceil__", (PyCFunction)pympn_int, METH_NOARGS, NULL}, + {"__round__", (PyCFunction)pympn_round, METH_VARARGS, NULL}, + {"__getnewargs__",(PyCFunction)pympn_getnewargs, METH_NOARGS, NULL}, + {"__format__", (PyCFunction)pympn__format__, METH_VARARGS, NULL}, + {"__sizeof__", (PyCFunction)pympn_sizeof, METH_NOARGS, NULL}, + {NULL, NULL, 0, NULL} +}; + +static PyGetSetDef pympn_getset[] = { + {"real", (getter)pympn_int, (setter)NULL, NULL, NULL}, + {"imag", (getter)pympn_get0, (setter)NULL, NULL, NULL}, + {"numerator", (getter)pympn_int, (setter)NULL, NULL, NULL}, + {"denominator", (getter)pympn_get1, (setter)NULL, NULL, NULL}, + {NULL, (getter)NULL, (setter)NULL, NULL, NULL} /* Sentinel */ +}; + +PyTypeObject PyLong_Type={ + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "int", /* tp_name */ + offsetof(PyLongObject, digits), /* tp_basicsize */ + sizeof(mp_limb_t), /* tp_itemsize */ + NULL, /* tp_dealloc */ + NULL, /* tp_print */ + NULL, /* tp_getattr */ + NULL, /* tp_setattr */ + NULL, /* tp_reserved */ + pympn_to_decimal_string, /* tp_repr */ + &pympn_as_number, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + pympn_hash, /* tp_hash */ + 0, /* tp_call */ + pympn_to_decimal_string, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_LONG_SUBCLASS, /* tp_flags */ + NULL, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + pympn_richcompare, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + pympn_methods, /* tp_methods */ + 0, /* tp_members */ + pympn_getset, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + pympn_new, /* tp_new */ + PyObject_Del, /* tp_free */ + NULL, /* tp_is_gc */ + NULL, /* tp_bases */ + NULL, /* tp_mro */ + NULL, /* tp_cache */ + NULL, /* tp_subclasses */ + NULL, /* tp_weaklist */ + NULL, /* tp_del */ + 0, /* tp_version_tag */ + NULL, /* tp_finalize */ +}; diff --git a/Python/marshal.c b/Python/marshal.c index ca64be3..ad29e63 100644 --- a/Python/marshal.c +++ b/Python/marshal.c @@ -168,15 +168,61 @@ w_short_pstring(const char *s, Py_ssize_t n, WFILE *p) #define PyLong_MARSHAL_SHIFT 15 #define PyLong_MARSHAL_BASE ((short)1 << PyLong_MARSHAL_SHIFT) #define PyLong_MARSHAL_MASK (PyLong_MARSHAL_BASE - 1) -#if PyLong_SHIFT % PyLong_MARSHAL_SHIFT != 0 -#error "PyLong_SHIFT must be a multiple of PyLong_MARSHAL_SHIFT" -#endif -#define PyLong_MARSHAL_RATIO (PyLong_SHIFT / PyLong_MARSHAL_SHIFT) #define W_TYPE(t, p) do { \ w_byte((t) | flag, (p)); \ } while(0) +#if defined(PyLong_GMP) +static void +w_PyLong(const PyLongObject *ob, char flag, WFILE *p) +{ + size_t i, j, l, k, s; + mp_limb_t d; + + W_TYPE(TYPE_LONG, p); + if (Py_SIZE(ob) == 0) { + w_long((long)0, p); + return; + } + + l = (PyMPN_SizeInBase(ob, 2)+PyLong_MARSHAL_SHIFT-1)/PyLong_MARSHAL_SHIFT; + if (l > SIZE32_MAX) { + p->depth--; + p->error = WFERR_UNMARSHALLABLE; + return; + } + w_long((long)(Py_SIZE(ob) > 0 ? l : -l), p); + + d=0; + j=0; + k=0; + if(Py_SIZE(ob)<0){ + s=-(Py_SIZE(ob)); + }else{ + s=Py_SIZE(ob); + } + for (i=0; i < l; i++) { + if(kdigits[j++]; + w_short((d|(dig<>(PyLong_MARSHAL_SHIFT-k); + k=GMP_NUMB_BITS-(PyLong_MARSHAL_SHIFT-k); + }else{ + w_short(d & PyLong_MARSHAL_MASK, p); + d>>=PyLong_MARSHAL_SHIFT; + k-=PyLong_MARSHAL_SHIFT; + } + } + return; +} +#else +#if PyLong_SHIFT % PyLong_MARSHAL_SHIFT != 0 +#error "PyLong_SHIFT must be a multiple of PyLong_MARSHAL_SHIFT" +#endif +#define PyLong_MARSHAL_RATIO (PyLong_SHIFT / PyLong_MARSHAL_SHIFT) static void w_PyLong(const PyLongObject *ob, char flag, WFILE *p) { @@ -219,6 +265,7 @@ w_PyLong(const PyLongObject *ob, char flag, WFILE *p) d >>= PyLong_MARSHAL_SHIFT; } while (d != 0); } +#endif static int w_ref(PyObject *v, char *flag, WFILE *p) @@ -706,6 +753,61 @@ r_long(RFILE *p) return x; } +#if defined(PyLong_GMP) +static PyObject * +r_PyLong(RFILE *p){ + PyLongObject *ob; + long n; + int sign=0; + size_t i, k, j; + mp_limb_t d; + + n = r_long(p); + if (PyErr_Occurred()) + return NULL; + if (n == 0) + return (PyObject *)_PyLong_New(0); + if (n < -SIZE32_MAX || n > SIZE32_MAX) { + PyErr_SetString(PyExc_ValueError, + "bad marshal data (long size out of range)"); + return NULL; + } + if(n<0){ + sign=1; + n=-n; + } + ob=_PyLong_New((n*15+GMP_NUMB_BITS-1)/GMP_NUMB_BITS); + + k=0; + d=0; + j=0; + for(i=0;i=PyLong_MARSHAL_BASE || (i==n-1 && dig==0)){ + Py_DECREF(ob); + PyErr_SetString(PyExc_ValueError, + "bad marshal data (digit out of range in long)"); + return NULL; + } + d|=((mp_limb_t)dig)<=GMP_NUMB_BITS){ + ob->digits[j++]=d; + k-=GMP_NUMB_BITS; + d=((mp_limb_t)dig)>>(PyLong_MARSHAL_SHIFT-k); + } + } + if(k){ + ob->digits[j++]=d; + } + Py_SIZE(ob)=j; + _PyMPN_Norm(ob); + if(sign) Py_SIZE(ob)=-Py_SIZE(ob); + return (PyObject*)ob; +} +#else static PyObject * r_PyLong(RFILE *p) { @@ -780,6 +882,7 @@ r_PyLong(RFILE *p) "bad marshal data (digit out of range in long)"); return NULL; } +#endif /* allocate the reflist index for a new object. Return -1 on failure */ static Py_ssize_t diff --git a/Tools/gdb/libpython.py b/Tools/gdb/libpython.py index 2ad22e2..243b8a6 100755 --- a/Tools/gdb/libpython.py +++ b/Tools/gdb/libpython.py @@ -752,12 +752,15 @@ class PyLongObjectPtr(PyObjectPtr): if ob_size == 0: return 0 - ob_digit = self.field('ob_digit') - - if gdb.lookup_type('digit').sizeof == 2: - SHIFT = 15 - else: - SHIFT = 30 + try: + ob_digit = self.field('ob_digit') + if gdb.lookup_type('digit').sizeof == 2: + SHIFT = 15 + else: + SHIFT = 30 + except: + ob_digit = self.field('digits') + SHIFT=int(gdb.parse_and_eval('__gmp_bits_per_limb')) digits = [long(ob_digit[i]) * 2**(SHIFT*i) for i in safe_range(abs(ob_size))] diff --git a/configure b/configure index 71d7b46..20ee111 100755 --- a/configure +++ b/configure @@ -630,6 +630,7 @@ LIBPL PY_ENABLE_SHARED EXT_SUFFIX SOABI +PyLong_IMPL LIBC LIBM HAVE_GETHOSTBYNAME @@ -9016,6 +9017,8 @@ fi # pthread (first!) on Linux fi +LIBS="-lgmp $LIBS" + # check if we need libintl for locale functions { $as_echo "$as_me:${as_lineno-$LINENO}: checking for textdomain in -lintl" >&5 $as_echo_n "checking for textdomain in -lintl... " >&6; } @@ -13617,6 +13620,7 @@ fi # determine what size digit to use for Python's longs { $as_echo "$as_me:${as_lineno-$LINENO}: checking digit size for Python's longs" >&5 $as_echo_n "checking digit size for Python's longs... " >&6; } +PyLong_IMPL=long # Check whether --enable-big-digits was given. if test "${enable_big_digits+set}" = set; then : enableval=$enable_big_digits; case $enable_big_digits in @@ -13624,10 +13628,53 @@ yes) enable_big_digits=30 ;; no) enable_big_digits=15 ;; +gmp) + # The cast to long int works around a bug in the HP C Compiler +# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. +# This bug is HP SR number 8606223364. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of mp_limb_t" >&5 +$as_echo_n "checking size of mp_limb_t... " >&6; } +if ${ac_cv_sizeof_mp_limb_t+:} false; then : + $as_echo_n "(cached) " >&6 +else + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (mp_limb_t))" "ac_cv_sizeof_mp_limb_t" "#include +"; then : + +else + if test "$ac_cv_type_mp_limb_t" = yes; then + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "cannot compute sizeof (mp_limb_t) +See \`config.log' for more details" "$LINENO" 5; } + else + ac_cv_sizeof_mp_limb_t=0 + fi +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_mp_limb_t" >&5 +$as_echo "$ac_cv_sizeof_mp_limb_t" >&6; } + + + +cat >>confdefs.h <<_ACEOF +#define SIZEOF_MP_LIMB_T $ac_cv_sizeof_mp_limb_t +_ACEOF + + + enable_gmp=yes + enable_big_digits=(8*SIZEOF_MP_LIMB_T) + PyLong_IMPL=mpn + +cat >>confdefs.h <<_ACEOF +#define PyLong_GMP 1 +_ACEOF + ;; 15|30) ;; *) - as_fn_error $? "bad value $enable_big_digits for --enable-big-digits; value should be 15 or 30" "$LINENO" 5 ;; + as_fn_error $? "bad value $enable_big_digits for --enable-big-digits; value should be 15, 30 or gmp" "$LINENO" 5 ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_big_digits" >&5 $as_echo "$enable_big_digits" >&6; } @@ -13643,6 +13690,8 @@ $as_echo "no value specified" >&6; } fi + + # check for wchar.h ac_fn_c_check_header_mongrel "$LINENO" "wchar.h" "ac_cv_header_wchar_h" "$ac_includes_default" if test "x$ac_cv_header_wchar_h" = xyes; then : diff --git a/configure.ac b/configure.ac index 3b3a734..fc3b3ab 100644 --- a/configure.ac +++ b/configure.ac @@ -4018,6 +4018,7 @@ fi # determine what size digit to use for Python's longs AC_MSG_CHECKING([digit size for Python's longs]) +PyLong_IMPL=long AC_ARG_ENABLE(big-digits, AS_HELP_STRING([--enable-big-digits@<:@=BITS@:>@],[use big digits for Python longs [[BITS=30]]]), [case $enable_big_digits in @@ -4025,16 +4026,25 @@ yes) enable_big_digits=30 ;; no) enable_big_digits=15 ;; +gmp) + AC_CHECK_SIZEOF(mp_limb_t, 4, [#include ]) + enable_gmp=yes + enable_big_digits=(8*SIZEOF_MP_LIMB_T) + PyLong_IMPL=mpn + LIBS="-lgmp $LIBS" + AC_DEFINE_UNQUOTED(PyLong_GMP, 1, [Use GMP]) ;; [15|30]) ;; *) - AC_MSG_ERROR([bad value $enable_big_digits for --enable-big-digits; value should be 15 or 30]) ;; + AC_MSG_ERROR([bad value $enable_big_digits for --enable-big-digits; value should be 15, 30 or gmp]) ;; esac AC_MSG_RESULT($enable_big_digits) AC_DEFINE_UNQUOTED(PYLONG_BITS_IN_DIGIT, $enable_big_digits, [Define as the preferred size in bits of long digits]) ], [AC_MSG_RESULT(no value specified)]) +AC_SUBST(PyLong_IMPL) + # check for wchar.h AC_CHECK_HEADER(wchar.h, [ AC_DEFINE(HAVE_WCHAR_H, 1, diff --git a/pyconfig.h.in b/pyconfig.h.in index e469f6a..a0da6b4 100644 --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -1202,6 +1202,9 @@ /* Define to printf format modifier for Py_ssize_t */ #undef PY_FORMAT_SIZE_T +/* Use GMP */ +#undef PyLong_GMP + /* Define if you want to build an interpreter with many run-time checks. */ #undef Py_DEBUG @@ -1242,6 +1245,9 @@ /* The size of `long long', as computed by sizeof. */ #undef SIZEOF_LONG_LONG +/* The size of `mp_limb_t', as computed by sizeof. */ +#undef SIZEOF_MP_LIMB_T + /* The size of `off_t', as computed by sizeof. */ #undef SIZEOF_OFF_T