annotate cos/python/Objects/longobject.c @ 39:600f48b74799

Move ide
author windel
date Fri, 03 Feb 2012 18:40:43 +0100
parents 7f74363f4c82
children
rev   line source
27
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1 /* Long (arbitrary precision) integer object implementation */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3 /* XXX The functional organization of this file is terrible */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
5 #include "Python.h"
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
6 #include "longintrepr.h"
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
7
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
8
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
9 /* convert a PyLong of size 1, 0 or -1 to an sdigit */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
10 #define MEDIUM_VALUE(x) (Py_SIZE(x) < 0 ? -(sdigit)(x)->ob_digit[0] : \
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
11 (Py_SIZE(x) == 0 ? (sdigit)0 : \
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
12 (sdigit)(x)->ob_digit[0]))
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
13 #define ABS(x) ((x) < 0 ? -(x) : (x))
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
14
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
15 /* If a freshly-allocated long is already shared, it must
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
16 be a small integer, so negating it must go to PyLong_FromLong */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
17 #define NEGATE(x) \
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
18 do if (Py_REFCNT(x) == 1) Py_SIZE(x) = -Py_SIZE(x); \
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
19 else { PyObject* tmp=PyLong_FromLong(-MEDIUM_VALUE(x)); \
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
20 Py_DECREF(x); (x) = (PyLongObject*)tmp; } \
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
21 while(0)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
22 /* For long multiplication, use the O(N**2) school algorithm unless
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
23 * both operands contain more than KARATSUBA_CUTOFF digits (this
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
24 * being an internal Python long digit, in base BASE).
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
25 */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
26 #define KARATSUBA_CUTOFF 70
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
27 #define KARATSUBA_SQUARE_CUTOFF (2 * KARATSUBA_CUTOFF)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
28
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
29 /* For exponentiation, use the binary left-to-right algorithm
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
30 * unless the exponent contains more than FIVEARY_CUTOFF digits.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
31 * In that case, do 5 bits at a time. The potential drawback is that
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
32 * a table of 2**5 intermediate results is computed.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
33 */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
34 #define FIVEARY_CUTOFF 8
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
35
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
36 #undef MIN
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
37 #undef MAX
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
38 #define MAX(x, y) ((x) < (y) ? (y) : (x))
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
39 #define MIN(x, y) ((x) > (y) ? (y) : (x))
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
40
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
41 #define SIGCHECK(PyTryBlock) \
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
42 do { \
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
43 if (PyErr_CheckSignals()) PyTryBlock \
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
44 } while(0)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
45
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
46 /* Normalize (remove leading zeros from) a long int object.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
47 Doesn't attempt to free the storage--in most cases, due to the nature
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
48 of the algorithms used, this could save at most be one word anyway. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
49
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
50 static PyLongObject *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
51 long_normalize(register PyLongObject *v)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
52 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
53 Py_ssize_t j = ABS(Py_SIZE(v));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
54 Py_ssize_t i = j;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
55
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
56 while (i > 0 && v->ob_digit[i-1] == 0)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
57 --i;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
58 if (i != j)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
59 Py_SIZE(v) = (Py_SIZE(v) < 0) ? -(i) : i;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
60 return v;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
61 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
62
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
63 /* Allocate a new long int object with size digits.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
64 Return NULL and set exception if we run out of memory. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
65
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
66 #define MAX_LONG_DIGITS \
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
67 ((PY_SSIZE_T_MAX - offsetof(PyLongObject, ob_digit))/sizeof(digit))
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
68
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
69 PyLongObject *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
70 _PyLong_New(Py_ssize_t size)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
71 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
72 PyLongObject *result;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
73 /* Number of bytes needed is: offsetof(PyLongObject, ob_digit) +
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
74 sizeof(digit)*size. Previous incarnations of this code used
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
75 sizeof(PyVarObject) instead of the offsetof, but this risks being
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
76 incorrect in the presence of padding between the PyVarObject header
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
77 and the digits. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
78 if (size > (Py_ssize_t)MAX_LONG_DIGITS) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
79 PyErr_SetString(PyExc_OverflowError,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
80 "too many digits in integer");
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
81 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
82 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
83 result = PyObject_MALLOC(offsetof(PyLongObject, ob_digit) +
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
84 size*sizeof(digit));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
85 if (!result) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
86 PyErr_NoMemory();
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
87 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
88 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
89 return (PyLongObject*)PyObject_INIT_VAR(result, &PyLong_Type, size);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
90 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
91
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
92 PyObject *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
93 _PyLong_Copy(PyLongObject *src)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
94 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
95 PyLongObject *result;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
96 Py_ssize_t i;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
97
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
98 assert(src != NULL);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
99 i = Py_SIZE(src);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
100 if (i < 0)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
101 i = -(i);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
102 if (i < 2) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
103 sdigit ival = src->ob_digit[0];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
104 if (Py_SIZE(src) < 0)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
105 ival = -ival;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
106 CHECK_SMALL_INT(ival);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
107 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
108 result = _PyLong_New(i);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
109 if (result != NULL) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
110 Py_SIZE(result) = Py_SIZE(src);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
111 while (--i >= 0)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
112 result->ob_digit[i] = src->ob_digit[i];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
113 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
114 return (PyObject *)result;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
115 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
116
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
117 /* Create a new long int object from a C long int */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
118
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
119 PyObject *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
120 PyLong_FromLong(long ival)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
121 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
122 PyLongObject *v;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
123 unsigned long abs_ival;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
124 unsigned long t; /* unsigned so >> doesn't propagate sign bit */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
125 int ndigits = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
126 int sign = 1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
127
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
128 if (ival < 0) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
129 /* negate: can't write this as abs_ival = -ival since that
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
130 invokes undefined behaviour when ival is LONG_MIN */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
131 abs_ival = 0U-(unsigned long)ival;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
132 sign = -1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
133 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
134 else {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
135 abs_ival = (unsigned long)ival;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
136 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
137
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
138 /* Fast path for single-digit ints */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
139 if (!(abs_ival >> PyLong_SHIFT)) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
140 v = _PyLong_New(1);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
141 if (v) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
142 Py_SIZE(v) = sign;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
143 v->ob_digit[0] = Py_SAFE_DOWNCAST(
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
144 abs_ival, unsigned long, digit);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
145 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
146 return (PyObject*)v;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
147 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
148
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
149 #if PyLong_SHIFT==15
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
150 /* 2 digits */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
151 if (!(abs_ival >> 2*PyLong_SHIFT)) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
152 v = _PyLong_New(2);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
153 if (v) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
154 Py_SIZE(v) = 2*sign;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
155 v->ob_digit[0] = Py_SAFE_DOWNCAST(
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
156 abs_ival & PyLong_MASK, unsigned long, digit);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
157 v->ob_digit[1] = Py_SAFE_DOWNCAST(
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
158 abs_ival >> PyLong_SHIFT, unsigned long, digit);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
159 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
160 return (PyObject*)v;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
161 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
162 #endif
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
163
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
164 /* Larger numbers: loop to determine number of digits */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
165 t = abs_ival;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
166 while (t) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
167 ++ndigits;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
168 t >>= PyLong_SHIFT;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
169 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
170 v = _PyLong_New(ndigits);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
171 if (v != NULL) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
172 digit *p = v->ob_digit;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
173 Py_SIZE(v) = ndigits*sign;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
174 t = abs_ival;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
175 while (t) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
176 *p++ = Py_SAFE_DOWNCAST(
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
177 t & PyLong_MASK, unsigned long, digit);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
178 t >>= PyLong_SHIFT;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
179 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
180 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
181 return (PyObject *)v;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
182 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
183
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
184 /* Create a new long int object from a C unsigned long int */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
185
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
186 PyObject *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
187 PyLong_FromUnsignedLong(unsigned long ival)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
188 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
189 PyLongObject *v;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
190 unsigned long t;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
191 int ndigits = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
192
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
193 if (ival < PyLong_BASE)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
194 return PyLong_FromLong(ival);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
195 /* Count the number of Python digits. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
196 t = (unsigned long)ival;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
197 while (t) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
198 ++ndigits;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
199 t >>= PyLong_SHIFT;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
200 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
201 v = _PyLong_New(ndigits);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
202 if (v != NULL) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
203 digit *p = v->ob_digit;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
204 Py_SIZE(v) = ndigits;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
205 while (ival) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
206 *p++ = (digit)(ival & PyLong_MASK);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
207 ival >>= PyLong_SHIFT;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
208 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
209 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
210 return (PyObject *)v;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
211 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
212
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
213 /* Create a new long int object from a C double */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
214
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
215 PyObject *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
216 PyLong_FromDouble(double dval)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
217 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
218 PyLongObject *v;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
219 double frac;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
220 int i, ndig, expo, neg;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
221 neg = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
222 if (Py_IS_INFINITY(dval)) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
223 PyErr_SetString(PyExc_OverflowError,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
224 "cannot convert float infinity to integer");
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
225 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
226 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
227 if (Py_IS_NAN(dval)) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
228 PyErr_SetString(PyExc_ValueError,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
229 "cannot convert float NaN to integer");
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
230 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
231 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
232 if (dval < 0.0) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
233 neg = 1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
234 dval = -dval;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
235 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
236 frac = frexp(dval, &expo); /* dval = frac*2**expo; 0.0 <= frac < 1.0 */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
237 if (expo <= 0)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
238 return PyLong_FromLong(0L);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
239 ndig = (expo-1) / PyLong_SHIFT + 1; /* Number of 'digits' in result */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
240 v = _PyLong_New(ndig);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
241 if (v == NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
242 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
243 frac = ldexp(frac, (expo-1) % PyLong_SHIFT + 1);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
244 for (i = ndig; --i >= 0; ) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
245 digit bits = (digit)frac;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
246 v->ob_digit[i] = bits;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
247 frac = frac - (double)bits;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
248 frac = ldexp(frac, PyLong_SHIFT);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
249 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
250 if (neg)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
251 Py_SIZE(v) = -(Py_SIZE(v));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
252 return (PyObject *)v;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
253 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
254
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
255 /* Checking for overflow in PyLong_AsLong is a PITA since C doesn't define
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
256 * anything about what happens when a signed integer operation overflows,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
257 * and some compilers think they're doing you a favor by being "clever"
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
258 * then. The bit pattern for the largest postive signed long is
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
259 * (unsigned long)LONG_MAX, and for the smallest negative signed long
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
260 * it is abs(LONG_MIN), which we could write -(unsigned long)LONG_MIN.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
261 * However, some other compilers warn about applying unary minus to an
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
262 * unsigned operand. Hence the weird "0-".
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
263 */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
264 #define PY_ABS_LONG_MIN (0-(unsigned long)LONG_MIN)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
265 #define PY_ABS_SSIZE_T_MIN (0-(size_t)PY_SSIZE_T_MIN)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
266
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
267 /* Get a C long int from a long int object or any object that has an __int__
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
268 method.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
269
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
270 On overflow, return -1 and set *overflow to 1 or -1 depending on the sign of
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
271 the result. Otherwise *overflow is 0.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
272
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
273 For other errors (e.g., TypeError), return -1 and set an error condition.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
274 In this case *overflow will be 0.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
275 */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
276
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
277 long
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
278 PyLong_AsLongAndOverflow(PyObject *vv, int *overflow)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
279 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
280 /* This version by Tim Peters */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
281 register PyLongObject *v;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
282 unsigned long x, prev;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
283 long res;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
284 Py_ssize_t i;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
285 int sign;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
286 int do_decref = 0; /* if nb_int was called */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
287
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
288 *overflow = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
289 if (vv == NULL) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
290 PyErr_BadInternalCall();
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
291 return -1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
292 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
293
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
294 if (!PyLong_Check(vv)) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
295 PyNumberMethods *nb;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
296 nb = vv->ob_type->tp_as_number;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
297 if (nb == NULL || nb->nb_int == NULL) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
298 PyErr_SetString(PyExc_TypeError,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
299 "an integer is required");
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
300 return -1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
301 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
302 vv = (*nb->nb_int) (vv);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
303 if (vv == NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
304 return -1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
305 do_decref = 1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
306 if (!PyLong_Check(vv)) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
307 Py_DECREF(vv);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
308 PyErr_SetString(PyExc_TypeError,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
309 "nb_int should return int object");
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
310 return -1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
311 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
312 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
313
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
314 res = -1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
315 v = (PyLongObject *)vv;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
316 i = Py_SIZE(v);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
317
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
318 switch (i) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
319 case -1:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
320 res = -(sdigit)v->ob_digit[0];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
321 break;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
322 case 0:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
323 res = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
324 break;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
325 case 1:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
326 res = v->ob_digit[0];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
327 break;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
328 default:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
329 sign = 1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
330 x = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
331 if (i < 0) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
332 sign = -1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
333 i = -(i);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
334 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
335 while (--i >= 0) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
336 prev = x;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
337 x = (x << PyLong_SHIFT) | v->ob_digit[i];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
338 if ((x >> PyLong_SHIFT) != prev) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
339 *overflow = sign;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
340 goto exit;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
341 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
342 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
343 /* Haven't lost any bits, but casting to long requires extra
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
344 * care (see comment above).
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
345 */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
346 if (x <= (unsigned long)LONG_MAX) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
347 res = (long)x * sign;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
348 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
349 else if (sign < 0 && x == PY_ABS_LONG_MIN) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
350 res = LONG_MIN;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
351 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
352 else {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
353 *overflow = sign;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
354 /* res is already set to -1 */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
355 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
356 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
357 exit:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
358 if (do_decref) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
359 Py_DECREF(vv);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
360 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
361 return res;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
362 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
363
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
364 /* Get a C long int from a long int object or any object that has an __int__
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
365 method. Return -1 and set an error if overflow occurs. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
366
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
367 long
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
368 PyLong_AsLong(PyObject *obj)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
369 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
370 int overflow;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
371 long result = PyLong_AsLongAndOverflow(obj, &overflow);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
372 if (overflow) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
373 /* XXX: could be cute and give a different
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
374 message for overflow == -1 */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
375 PyErr_SetString(PyExc_OverflowError,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
376 "Python int too large to convert to C long");
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
377 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
378 return result;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
379 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
380
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
381 /* Get a Py_ssize_t from a long int object.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
382 Returns -1 and sets an error condition if overflow occurs. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
383
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
384 Py_ssize_t
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
385 PyLong_AsSsize_t(PyObject *vv) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
386 register PyLongObject *v;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
387 size_t x, prev;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
388 Py_ssize_t i;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
389 int sign;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
390
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
391 if (vv == NULL) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
392 PyErr_BadInternalCall();
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
393 return -1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
394 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
395 if (!PyLong_Check(vv)) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
396 PyErr_SetString(PyExc_TypeError, "an integer is required");
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
397 return -1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
398 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
399
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
400 v = (PyLongObject *)vv;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
401 i = Py_SIZE(v);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
402 switch (i) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
403 case -1: return -(sdigit)v->ob_digit[0];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
404 case 0: return 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
405 case 1: return v->ob_digit[0];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
406 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
407 sign = 1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
408 x = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
409 if (i < 0) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
410 sign = -1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
411 i = -(i);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
412 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
413 while (--i >= 0) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
414 prev = x;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
415 x = (x << PyLong_SHIFT) | v->ob_digit[i];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
416 if ((x >> PyLong_SHIFT) != prev)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
417 goto overflow;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
418 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
419 /* Haven't lost any bits, but casting to a signed type requires
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
420 * extra care (see comment above).
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
421 */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
422 if (x <= (size_t)PY_SSIZE_T_MAX) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
423 return (Py_ssize_t)x * sign;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
424 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
425 else if (sign < 0 && x == PY_ABS_SSIZE_T_MIN) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
426 return PY_SSIZE_T_MIN;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
427 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
428 /* else overflow */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
429
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
430 overflow:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
431 PyErr_SetString(PyExc_OverflowError,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
432 "Python int too large to convert to C ssize_t");
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
433 return -1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
434 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
435
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
436 /* Get a C unsigned long int from a long int object.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
437 Returns -1 and sets an error condition if overflow occurs. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
438
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
439 unsigned long
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
440 PyLong_AsUnsignedLong(PyObject *vv)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
441 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
442 register PyLongObject *v;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
443 unsigned long x, prev;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
444 Py_ssize_t i;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
445
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
446 if (vv == NULL) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
447 PyErr_BadInternalCall();
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
448 return (unsigned long)-1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
449 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
450 if (!PyLong_Check(vv)) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
451 PyErr_SetString(PyExc_TypeError, "an integer is required");
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
452 return (unsigned long)-1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
453 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
454
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
455 v = (PyLongObject *)vv;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
456 i = Py_SIZE(v);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
457 x = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
458 if (i < 0) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
459 PyErr_SetString(PyExc_OverflowError,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
460 "can't convert negative value to unsigned int");
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
461 return (unsigned long) -1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
462 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
463 switch (i) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
464 case 0: return 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
465 case 1: return v->ob_digit[0];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
466 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
467 while (--i >= 0) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
468 prev = x;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
469 x = (x << PyLong_SHIFT) | v->ob_digit[i];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
470 if ((x >> PyLong_SHIFT) != prev) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
471 PyErr_SetString(PyExc_OverflowError,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
472 "python int too large to convert "
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
473 "to C unsigned long");
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
474 return (unsigned long) -1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
475 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
476 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
477 return x;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
478 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
479
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
480 /* Get a C size_t from a long int object. Returns (size_t)-1 and sets
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
481 an error condition if overflow occurs. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
482
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
483 size_t
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
484 PyLong_AsSize_t(PyObject *vv)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
485 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
486 register PyLongObject *v;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
487 size_t x, prev;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
488 Py_ssize_t i;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
489
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
490 if (vv == NULL) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
491 PyErr_BadInternalCall();
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
492 return (size_t) -1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
493 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
494 if (!PyLong_Check(vv)) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
495 PyErr_SetString(PyExc_TypeError, "an integer is required");
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
496 return (size_t)-1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
497 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
498
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
499 v = (PyLongObject *)vv;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
500 i = Py_SIZE(v);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
501 x = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
502 if (i < 0) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
503 PyErr_SetString(PyExc_OverflowError,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
504 "can't convert negative value to size_t");
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
505 return (size_t) -1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
506 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
507 switch (i) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
508 case 0: return 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
509 case 1: return v->ob_digit[0];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
510 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
511 while (--i >= 0) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
512 prev = x;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
513 x = (x << PyLong_SHIFT) | v->ob_digit[i];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
514 if ((x >> PyLong_SHIFT) != prev) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
515 PyErr_SetString(PyExc_OverflowError,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
516 "Python int too large to convert to C size_t");
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
517 return (size_t) -1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
518 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
519 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
520 return x;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
521 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
522
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
523 /* Get a C unsigned long int from a long int object, ignoring the high bits.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
524 Returns -1 and sets an error condition if an error occurs. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
525
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
526 static unsigned long
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
527 _PyLong_AsUnsignedLongMask(PyObject *vv)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
528 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
529 register PyLongObject *v;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
530 unsigned long x;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
531 Py_ssize_t i;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
532 int sign;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
533
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
534 if (vv == NULL || !PyLong_Check(vv)) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
535 PyErr_BadInternalCall();
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
536 return (unsigned long) -1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
537 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
538 v = (PyLongObject *)vv;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
539 i = Py_SIZE(v);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
540 switch (i) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
541 case 0: return 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
542 case 1: return v->ob_digit[0];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
543 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
544 sign = 1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
545 x = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
546 if (i < 0) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
547 sign = -1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
548 i = -i;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
549 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
550 while (--i >= 0) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
551 x = (x << PyLong_SHIFT) | v->ob_digit[i];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
552 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
553 return x * sign;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
554 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
555
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
556 unsigned long
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
557 PyLong_AsUnsignedLongMask(register PyObject *op)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
558 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
559 PyNumberMethods *nb;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
560 PyLongObject *lo;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
561 unsigned long val;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
562
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
563 if (op && PyLong_Check(op))
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
564 return _PyLong_AsUnsignedLongMask(op);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
565
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
566 if (op == NULL || (nb = op->ob_type->tp_as_number) == NULL ||
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
567 nb->nb_int == NULL) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
568 PyErr_SetString(PyExc_TypeError, "an integer is required");
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
569 return (unsigned long)-1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
570 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
571
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
572 lo = (PyLongObject*) (*nb->nb_int) (op);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
573 if (lo == NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
574 return (unsigned long)-1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
575 if (PyLong_Check(lo)) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
576 val = _PyLong_AsUnsignedLongMask((PyObject *)lo);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
577 Py_DECREF(lo);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
578 if (PyErr_Occurred())
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
579 return (unsigned long)-1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
580 return val;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
581 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
582 else
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
583 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
584 Py_DECREF(lo);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
585 PyErr_SetString(PyExc_TypeError,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
586 "nb_int should return int object");
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
587 return (unsigned long)-1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
588 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
589 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
590
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
591 int
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
592 _PyLong_Sign(PyObject *vv)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
593 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
594 PyLongObject *v = (PyLongObject *)vv;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
595
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
596 assert(v != NULL);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
597 assert(PyLong_Check(v));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
598
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
599 return Py_SIZE(v) == 0 ? 0 : (Py_SIZE(v) < 0 ? -1 : 1);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
600 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
601
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
602 size_t
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
603 _PyLong_NumBits(PyObject *vv)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
604 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
605 PyLongObject *v = (PyLongObject *)vv;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
606 size_t result = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
607 Py_ssize_t ndigits;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
608
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
609 assert(v != NULL);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
610 assert(PyLong_Check(v));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
611 ndigits = ABS(Py_SIZE(v));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
612 assert(ndigits == 0 || v->ob_digit[ndigits - 1] != 0);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
613 if (ndigits > 0) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
614 digit msd = v->ob_digit[ndigits - 1];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
615
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
616 result = (ndigits - 1) * PyLong_SHIFT;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
617 if (result / PyLong_SHIFT != (size_t)(ndigits - 1))
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
618 goto Overflow;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
619 do {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
620 ++result;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
621 if (result == 0)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
622 goto Overflow;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
623 msd >>= 1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
624 } while (msd);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
625 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
626 return result;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
627
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
628 Overflow:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
629 PyErr_SetString(PyExc_OverflowError, "int has too many bits "
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
630 "to express in a platform size_t");
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
631 return (size_t)-1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
632 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
633
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
634 PyObject *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
635 _PyLong_FromByteArray(const unsigned char* bytes, size_t n,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
636 int little_endian, int is_signed)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
637 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
638 const unsigned char* pstartbyte; /* LSB of bytes */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
639 int incr; /* direction to move pstartbyte */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
640 const unsigned char* pendbyte; /* MSB of bytes */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
641 size_t numsignificantbytes; /* number of bytes that matter */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
642 Py_ssize_t ndigits; /* number of Python long digits */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
643 PyLongObject* v; /* result */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
644 Py_ssize_t idigit = 0; /* next free index in v->ob_digit */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
645
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
646 if (n == 0)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
647 return PyLong_FromLong(0L);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
648
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
649 if (little_endian) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
650 pstartbyte = bytes;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
651 pendbyte = bytes + n - 1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
652 incr = 1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
653 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
654 else {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
655 pstartbyte = bytes + n - 1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
656 pendbyte = bytes;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
657 incr = -1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
658 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
659
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
660 if (is_signed)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
661 is_signed = *pendbyte >= 0x80;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
662
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
663 /* Compute numsignificantbytes. This consists of finding the most
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
664 significant byte. Leading 0 bytes are insignificant if the number
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
665 is positive, and leading 0xff bytes if negative. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
666 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
667 size_t i;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
668 const unsigned char* p = pendbyte;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
669 const int pincr = -incr; /* search MSB to LSB */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
670 const unsigned char insignficant = is_signed ? 0xff : 0x00;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
671
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
672 for (i = 0; i < n; ++i, p += pincr) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
673 if (*p != insignficant)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
674 break;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
675 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
676 numsignificantbytes = n - i;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
677 /* 2's-comp is a bit tricky here, e.g. 0xff00 == -0x0100, so
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
678 actually has 2 significant bytes. OTOH, 0xff0001 ==
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
679 -0x00ffff, so we wouldn't *need* to bump it there; but we
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
680 do for 0xffff = -0x0001. To be safe without bothering to
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
681 check every case, bump it regardless. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
682 if (is_signed && numsignificantbytes < n)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
683 ++numsignificantbytes;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
684 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
685
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
686 /* How many Python long digits do we need? We have
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
687 8*numsignificantbytes bits, and each Python long digit has
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
688 PyLong_SHIFT bits, so it's the ceiling of the quotient. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
689 /* catch overflow before it happens */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
690 if (numsignificantbytes > (PY_SSIZE_T_MAX - PyLong_SHIFT) / 8) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
691 PyErr_SetString(PyExc_OverflowError,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
692 "byte array too long to convert to int");
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
693 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
694 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
695 ndigits = (numsignificantbytes * 8 + PyLong_SHIFT - 1) / PyLong_SHIFT;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
696 v = _PyLong_New(ndigits);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
697 if (v == NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
698 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
699
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
700 /* Copy the bits over. The tricky parts are computing 2's-comp on
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
701 the fly for signed numbers, and dealing with the mismatch between
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
702 8-bit bytes and (probably) 15-bit Python digits.*/
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
703 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
704 size_t i;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
705 twodigits carry = 1; /* for 2's-comp calculation */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
706 twodigits accum = 0; /* sliding register */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
707 unsigned int accumbits = 0; /* number of bits in accum */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
708 const unsigned char* p = pstartbyte;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
709
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
710 for (i = 0; i < numsignificantbytes; ++i, p += incr) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
711 twodigits thisbyte = *p;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
712 /* Compute correction for 2's comp, if needed. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
713 if (is_signed) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
714 thisbyte = (0xff ^ thisbyte) + carry;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
715 carry = thisbyte >> 8;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
716 thisbyte &= 0xff;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
717 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
718 /* Because we're going LSB to MSB, thisbyte is
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
719 more significant than what's already in accum,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
720 so needs to be prepended to accum. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
721 accum |= (twodigits)thisbyte << accumbits;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
722 accumbits += 8;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
723 if (accumbits >= PyLong_SHIFT) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
724 /* There's enough to fill a Python digit. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
725 assert(idigit < ndigits);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
726 v->ob_digit[idigit] = (digit)(accum & PyLong_MASK);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
727 ++idigit;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
728 accum >>= PyLong_SHIFT;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
729 accumbits -= PyLong_SHIFT;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
730 assert(accumbits < PyLong_SHIFT);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
731 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
732 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
733 assert(accumbits < PyLong_SHIFT);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
734 if (accumbits) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
735 assert(idigit < ndigits);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
736 v->ob_digit[idigit] = (digit)accum;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
737 ++idigit;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
738 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
739 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
740
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
741 Py_SIZE(v) = is_signed ? -idigit : idigit;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
742 return (PyObject *)long_normalize(v);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
743 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
744
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
745 int
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
746 _PyLong_AsByteArray(PyLongObject* v,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
747 unsigned char* bytes, size_t n,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
748 int little_endian, int is_signed)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
749 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
750 Py_ssize_t i; /* index into v->ob_digit */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
751 Py_ssize_t ndigits; /* |v->ob_size| */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
752 twodigits accum; /* sliding register */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
753 unsigned int accumbits; /* # bits in accum */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
754 int do_twos_comp; /* store 2's-comp? is_signed and v < 0 */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
755 digit carry; /* for computing 2's-comp */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
756 size_t j; /* # bytes filled */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
757 unsigned char* p; /* pointer to next byte in bytes */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
758 int pincr; /* direction to move p */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
759
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
760 assert(v != NULL && PyLong_Check(v));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
761
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
762 if (Py_SIZE(v) < 0) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
763 ndigits = -(Py_SIZE(v));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
764 if (!is_signed) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
765 PyErr_SetString(PyExc_OverflowError,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
766 "can't convert negative int to unsigned");
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
767 return -1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
768 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
769 do_twos_comp = 1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
770 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
771 else {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
772 ndigits = Py_SIZE(v);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
773 do_twos_comp = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
774 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
775
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
776 if (little_endian) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
777 p = bytes;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
778 pincr = 1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
779 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
780 else {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
781 p = bytes + n - 1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
782 pincr = -1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
783 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
784
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
785 /* Copy over all the Python digits.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
786 It's crucial that every Python digit except for the MSD contribute
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
787 exactly PyLong_SHIFT bits to the total, so first assert that the long is
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
788 normalized. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
789 assert(ndigits == 0 || v->ob_digit[ndigits - 1] != 0);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
790 j = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
791 accum = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
792 accumbits = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
793 carry = do_twos_comp ? 1 : 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
794 for (i = 0; i < ndigits; ++i) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
795 digit thisdigit = v->ob_digit[i];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
796 if (do_twos_comp) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
797 thisdigit = (thisdigit ^ PyLong_MASK) + carry;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
798 carry = thisdigit >> PyLong_SHIFT;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
799 thisdigit &= PyLong_MASK;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
800 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
801 /* Because we're going LSB to MSB, thisdigit is more
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
802 significant than what's already in accum, so needs to be
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
803 prepended to accum. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
804 accum |= (twodigits)thisdigit << accumbits;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
805
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
806 /* The most-significant digit may be (probably is) at least
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
807 partly empty. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
808 if (i == ndigits - 1) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
809 /* Count # of sign bits -- they needn't be stored,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
810 * although for signed conversion we need later to
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
811 * make sure at least one sign bit gets stored. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
812 digit s = do_twos_comp ? thisdigit ^ PyLong_MASK : thisdigit;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
813 while (s != 0) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
814 s >>= 1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
815 accumbits++;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
816 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
817 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
818 else
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
819 accumbits += PyLong_SHIFT;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
820
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
821 /* Store as many bytes as possible. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
822 while (accumbits >= 8) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
823 if (j >= n)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
824 goto Overflow;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
825 ++j;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
826 *p = (unsigned char)(accum & 0xff);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
827 p += pincr;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
828 accumbits -= 8;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
829 accum >>= 8;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
830 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
831 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
832
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
833 /* Store the straggler (if any). */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
834 assert(accumbits < 8);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
835 assert(carry == 0); /* else do_twos_comp and *every* digit was 0 */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
836 if (accumbits > 0) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
837 if (j >= n)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
838 goto Overflow;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
839 ++j;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
840 if (do_twos_comp) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
841 /* Fill leading bits of the byte with sign bits
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
842 (appropriately pretending that the long had an
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
843 infinite supply of sign bits). */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
844 accum |= (~(twodigits)0) << accumbits;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
845 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
846 *p = (unsigned char)(accum & 0xff);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
847 p += pincr;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
848 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
849 else if (j == n && n > 0 && is_signed) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
850 /* The main loop filled the byte array exactly, so the code
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
851 just above didn't get to ensure there's a sign bit, and the
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
852 loop below wouldn't add one either. Make sure a sign bit
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
853 exists. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
854 unsigned char msb = *(p - pincr);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
855 int sign_bit_set = msb >= 0x80;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
856 assert(accumbits == 0);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
857 if (sign_bit_set == do_twos_comp)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
858 return 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
859 else
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
860 goto Overflow;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
861 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
862
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
863 /* Fill remaining bytes with copies of the sign bit. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
864 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
865 unsigned char signbyte = do_twos_comp ? 0xffU : 0U;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
866 for ( ; j < n; ++j, p += pincr)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
867 *p = signbyte;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
868 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
869
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
870 return 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
871
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
872 Overflow:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
873 PyErr_SetString(PyExc_OverflowError, "int too big to convert");
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
874 return -1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
875
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
876 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
877
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
878 /* Create a new long int object from a C pointer */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
879
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
880 PyObject *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
881 PyLong_FromVoidPtr(void *p)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
882 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
883 #ifndef HAVE_LONG_LONG
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
884 # error "PyLong_FromVoidPtr: sizeof(void*) > sizeof(long), but no long long"
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
885 #endif
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
886 #if SIZEOF_LONG_LONG < SIZEOF_VOID_P
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
887 # error "PyLong_FromVoidPtr: sizeof(PY_LONG_LONG) < sizeof(void*)"
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
888 #endif
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
889 /* special-case null pointer */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
890 if (!p)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
891 return PyLong_FromLong(0);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
892 return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG)(Py_uintptr_t)p);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
893
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
894 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
895
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
896 /* Get a C pointer from a long int object. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
897
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
898 void *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
899 PyLong_AsVoidPtr(PyObject *vv)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
900 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
901 #if SIZEOF_VOID_P <= SIZEOF_LONG
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
902 long x;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
903
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
904 if (PyLong_Check(vv) && _PyLong_Sign(vv) < 0)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
905 x = PyLong_AsLong(vv);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
906 else
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
907 x = PyLong_AsUnsignedLong(vv);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
908 #else
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
909
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
910 #ifndef HAVE_LONG_LONG
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
911 # error "PyLong_AsVoidPtr: sizeof(void*) > sizeof(long), but no long long"
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
912 #endif
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
913 #if SIZEOF_LONG_LONG < SIZEOF_VOID_P
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
914 # error "PyLong_AsVoidPtr: sizeof(PY_LONG_LONG) < sizeof(void*)"
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
915 #endif
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
916 PY_LONG_LONG x;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
917
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
918 if (PyLong_Check(vv) && _PyLong_Sign(vv) < 0)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
919 x = PyLong_AsLongLong(vv);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
920 else
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
921 x = PyLong_AsUnsignedLongLong(vv);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
922
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
923 #endif /* SIZEOF_VOID_P <= SIZEOF_LONG */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
924
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
925 if (x == -1 && PyErr_Occurred())
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
926 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
927 return (void *)x;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
928 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
929
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
930 #ifdef HAVE_LONG_LONG
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
931
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
932 /* Initial PY_LONG_LONG support by Chris Herborth (chrish@qnx.com), later
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
933 * rewritten to use the newer PyLong_{As,From}ByteArray API.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
934 */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
935
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
936 #define IS_LITTLE_ENDIAN (int)*(unsigned char*)&one
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
937 #define PY_ABS_LLONG_MIN (0-(unsigned PY_LONG_LONG)PY_LLONG_MIN)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
938
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
939 /* Create a new long int object from a C PY_LONG_LONG int. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
940
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
941 PyObject *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
942 PyLong_FromLongLong(PY_LONG_LONG ival)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
943 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
944 PyLongObject *v;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
945 unsigned PY_LONG_LONG abs_ival;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
946 unsigned PY_LONG_LONG t; /* unsigned so >> doesn't propagate sign bit */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
947 int ndigits = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
948 int negative = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
949
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
950 if (ival < 0) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
951 /* avoid signed overflow on negation; see comments
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
952 in PyLong_FromLong above. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
953 abs_ival = (unsigned PY_LONG_LONG)(-1-ival) + 1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
954 negative = 1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
955 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
956 else {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
957 abs_ival = (unsigned PY_LONG_LONG)ival;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
958 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
959
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
960 /* Count the number of Python digits.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
961 We used to pick 5 ("big enough for anything"), but that's a
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
962 waste of time and space given that 5*15 = 75 bits are rarely
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
963 needed. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
964 t = abs_ival;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
965 while (t) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
966 ++ndigits;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
967 t >>= PyLong_SHIFT;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
968 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
969 v = _PyLong_New(ndigits);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
970 if (v != NULL) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
971 digit *p = v->ob_digit;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
972 Py_SIZE(v) = negative ? -ndigits : ndigits;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
973 t = abs_ival;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
974 while (t) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
975 *p++ = (digit)(t & PyLong_MASK);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
976 t >>= PyLong_SHIFT;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
977 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
978 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
979 return (PyObject *)v;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
980 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
981
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
982 /* Create a new long int object from a C unsigned PY_LONG_LONG int. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
983
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
984 PyObject *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
985 PyLong_FromUnsignedLongLong(unsigned PY_LONG_LONG ival)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
986 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
987 PyLongObject *v;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
988 unsigned PY_LONG_LONG t;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
989 int ndigits = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
990
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
991 if (ival < PyLong_BASE)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
992 return PyLong_FromLong((long)ival);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
993 /* Count the number of Python digits. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
994 t = (unsigned PY_LONG_LONG)ival;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
995 while (t) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
996 ++ndigits;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
997 t >>= PyLong_SHIFT;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
998 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
999 v = _PyLong_New(ndigits);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1000 if (v != NULL) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1001 digit *p = v->ob_digit;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1002 Py_SIZE(v) = ndigits;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1003 while (ival) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1004 *p++ = (digit)(ival & PyLong_MASK);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1005 ival >>= PyLong_SHIFT;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1006 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1007 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1008 return (PyObject *)v;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1009 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1010
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1011 /* Create a new long int object from a C Py_ssize_t. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1012
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1013 PyObject *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1014 PyLong_FromSsize_t(Py_ssize_t ival)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1015 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1016 PyLongObject *v;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1017 size_t abs_ival;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1018 size_t t; /* unsigned so >> doesn't propagate sign bit */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1019 int ndigits = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1020 int negative = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1021
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1022 CHECK_SMALL_INT(ival);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1023 if (ival < 0) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1024 /* avoid signed overflow when ival = SIZE_T_MIN */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1025 abs_ival = (size_t)(-1-ival)+1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1026 negative = 1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1027 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1028 else {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1029 abs_ival = (size_t)ival;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1030 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1031
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1032 /* Count the number of Python digits. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1033 t = abs_ival;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1034 while (t) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1035 ++ndigits;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1036 t >>= PyLong_SHIFT;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1037 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1038 v = _PyLong_New(ndigits);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1039 if (v != NULL) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1040 digit *p = v->ob_digit;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1041 Py_SIZE(v) = negative ? -ndigits : ndigits;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1042 t = abs_ival;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1043 while (t) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1044 *p++ = (digit)(t & PyLong_MASK);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1045 t >>= PyLong_SHIFT;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1046 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1047 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1048 return (PyObject *)v;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1049 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1050
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1051 /* Create a new long int object from a C size_t. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1052
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1053 PyObject *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1054 PyLong_FromSize_t(size_t ival)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1055 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1056 PyLongObject *v;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1057 size_t t;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1058 int ndigits = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1059
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1060 if (ival < PyLong_BASE)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1061 return PyLong_FromLong((long)ival);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1062 /* Count the number of Python digits. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1063 t = ival;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1064 while (t) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1065 ++ndigits;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1066 t >>= PyLong_SHIFT;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1067 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1068 v = _PyLong_New(ndigits);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1069 if (v != NULL) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1070 digit *p = v->ob_digit;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1071 Py_SIZE(v) = ndigits;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1072 while (ival) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1073 *p++ = (digit)(ival & PyLong_MASK);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1074 ival >>= PyLong_SHIFT;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1075 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1076 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1077 return (PyObject *)v;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1078 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1079
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1080 /* Get a C long long int from a long int object or any object that has an
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1081 __int__ method. Return -1 and set an error if overflow occurs. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1082
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1083 PY_LONG_LONG
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1084 PyLong_AsLongLong(PyObject *vv)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1085 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1086 PyLongObject *v;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1087 PY_LONG_LONG bytes;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1088 int one = 1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1089 int res;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1090
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1091 if (vv == NULL) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1092 PyErr_BadInternalCall();
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1093 return -1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1094 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1095 if (!PyLong_Check(vv)) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1096 PyNumberMethods *nb;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1097 PyObject *io;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1098 if ((nb = vv->ob_type->tp_as_number) == NULL ||
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1099 nb->nb_int == NULL) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1100 PyErr_SetString(PyExc_TypeError, "an integer is required");
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1101 return -1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1102 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1103 io = (*nb->nb_int) (vv);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1104 if (io == NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1105 return -1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1106 if (PyLong_Check(io)) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1107 bytes = PyLong_AsLongLong(io);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1108 Py_DECREF(io);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1109 return bytes;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1110 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1111 Py_DECREF(io);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1112 PyErr_SetString(PyExc_TypeError, "integer conversion failed");
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1113 return -1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1114 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1115
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1116 v = (PyLongObject*)vv;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1117 switch(Py_SIZE(v)) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1118 case -1: return -(sdigit)v->ob_digit[0];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1119 case 0: return 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1120 case 1: return v->ob_digit[0];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1121 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1122 res = _PyLong_AsByteArray((PyLongObject *)vv, (unsigned char *)&bytes,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1123 SIZEOF_LONG_LONG, IS_LITTLE_ENDIAN, 1);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1124
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1125 /* Plan 9 can't handle PY_LONG_LONG in ? : expressions */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1126 if (res < 0)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1127 return (PY_LONG_LONG)-1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1128 else
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1129 return bytes;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1130 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1131
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1132 /* Get a C unsigned PY_LONG_LONG int from a long int object.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1133 Return -1 and set an error if overflow occurs. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1134
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1135 unsigned PY_LONG_LONG
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1136 PyLong_AsUnsignedLongLong(PyObject *vv)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1137 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1138 PyLongObject *v;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1139 unsigned PY_LONG_LONG bytes;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1140 int one = 1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1141 int res;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1142
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1143 if (vv == NULL) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1144 PyErr_BadInternalCall();
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1145 return (unsigned PY_LONG_LONG)-1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1146 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1147 if (!PyLong_Check(vv)) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1148 PyErr_SetString(PyExc_TypeError, "an integer is required");
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1149 return (unsigned PY_LONG_LONG)-1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1150 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1151
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1152 v = (PyLongObject*)vv;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1153 switch(Py_SIZE(v)) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1154 case 0: return 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1155 case 1: return v->ob_digit[0];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1156 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1157
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1158 res = _PyLong_AsByteArray((PyLongObject *)vv, (unsigned char *)&bytes,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1159 SIZEOF_LONG_LONG, IS_LITTLE_ENDIAN, 0);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1160
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1161 /* Plan 9 can't handle PY_LONG_LONG in ? : expressions */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1162 if (res < 0)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1163 return (unsigned PY_LONG_LONG)res;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1164 else
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1165 return bytes;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1166 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1167
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1168 /* Get a C unsigned long int from a long int object, ignoring the high bits.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1169 Returns -1 and sets an error condition if an error occurs. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1170
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1171 static unsigned PY_LONG_LONG
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1172 _PyLong_AsUnsignedLongLongMask(PyObject *vv)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1173 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1174 register PyLongObject *v;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1175 unsigned PY_LONG_LONG x;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1176 Py_ssize_t i;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1177 int sign;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1178
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1179 if (vv == NULL || !PyLong_Check(vv)) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1180 PyErr_BadInternalCall();
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1181 return (unsigned long) -1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1182 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1183 v = (PyLongObject *)vv;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1184 switch(Py_SIZE(v)) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1185 case 0: return 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1186 case 1: return v->ob_digit[0];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1187 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1188 i = Py_SIZE(v);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1189 sign = 1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1190 x = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1191 if (i < 0) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1192 sign = -1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1193 i = -i;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1194 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1195 while (--i >= 0) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1196 x = (x << PyLong_SHIFT) | v->ob_digit[i];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1197 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1198 return x * sign;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1199 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1200
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1201 unsigned PY_LONG_LONG
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1202 PyLong_AsUnsignedLongLongMask(register PyObject *op)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1203 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1204 PyNumberMethods *nb;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1205 PyLongObject *lo;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1206 unsigned PY_LONG_LONG val;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1207
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1208 if (op && PyLong_Check(op))
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1209 return _PyLong_AsUnsignedLongLongMask(op);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1210
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1211 if (op == NULL || (nb = op->ob_type->tp_as_number) == NULL ||
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1212 nb->nb_int == NULL) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1213 PyErr_SetString(PyExc_TypeError, "an integer is required");
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1214 return (unsigned PY_LONG_LONG)-1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1215 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1216
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1217 lo = (PyLongObject*) (*nb->nb_int) (op);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1218 if (lo == NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1219 return (unsigned PY_LONG_LONG)-1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1220 if (PyLong_Check(lo)) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1221 val = _PyLong_AsUnsignedLongLongMask((PyObject *)lo);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1222 Py_DECREF(lo);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1223 if (PyErr_Occurred())
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1224 return (unsigned PY_LONG_LONG)-1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1225 return val;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1226 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1227 else
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1228 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1229 Py_DECREF(lo);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1230 PyErr_SetString(PyExc_TypeError,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1231 "nb_int should return int object");
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1232 return (unsigned PY_LONG_LONG)-1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1233 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1234 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1235 #undef IS_LITTLE_ENDIAN
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1236
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1237 /* Get a C long long int from a long int object or any object that has an
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1238 __int__ method.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1239
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1240 On overflow, return -1 and set *overflow to 1 or -1 depending on the sign of
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1241 the result. Otherwise *overflow is 0.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1242
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1243 For other errors (e.g., TypeError), return -1 and set an error condition.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1244 In this case *overflow will be 0.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1245 */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1246
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1247 PY_LONG_LONG
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1248 PyLong_AsLongLongAndOverflow(PyObject *vv, int *overflow)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1249 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1250 /* This version by Tim Peters */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1251 register PyLongObject *v;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1252 unsigned PY_LONG_LONG x, prev;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1253 PY_LONG_LONG res;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1254 Py_ssize_t i;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1255 int sign;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1256 int do_decref = 0; /* if nb_int was called */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1257
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1258 *overflow = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1259 if (vv == NULL) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1260 PyErr_BadInternalCall();
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1261 return -1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1262 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1263
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1264 if (!PyLong_Check(vv)) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1265 PyNumberMethods *nb;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1266 nb = vv->ob_type->tp_as_number;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1267 if (nb == NULL || nb->nb_int == NULL) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1268 PyErr_SetString(PyExc_TypeError,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1269 "an integer is required");
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1270 return -1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1271 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1272 vv = (*nb->nb_int) (vv);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1273 if (vv == NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1274 return -1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1275 do_decref = 1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1276 if (!PyLong_Check(vv)) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1277 Py_DECREF(vv);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1278 PyErr_SetString(PyExc_TypeError,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1279 "nb_int should return int object");
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1280 return -1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1281 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1282 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1283
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1284 res = -1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1285 v = (PyLongObject *)vv;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1286 i = Py_SIZE(v);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1287
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1288 switch (i) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1289 case -1:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1290 res = -(sdigit)v->ob_digit[0];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1291 break;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1292 case 0:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1293 res = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1294 break;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1295 case 1:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1296 res = v->ob_digit[0];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1297 break;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1298 default:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1299 sign = 1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1300 x = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1301 if (i < 0) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1302 sign = -1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1303 i = -(i);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1304 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1305 while (--i >= 0) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1306 prev = x;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1307 x = (x << PyLong_SHIFT) + v->ob_digit[i];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1308 if ((x >> PyLong_SHIFT) != prev) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1309 *overflow = sign;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1310 goto exit;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1311 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1312 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1313 /* Haven't lost any bits, but casting to long requires extra
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1314 * care (see comment above).
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1315 */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1316 if (x <= (unsigned PY_LONG_LONG)PY_LLONG_MAX) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1317 res = (PY_LONG_LONG)x * sign;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1318 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1319 else if (sign < 0 && x == PY_ABS_LLONG_MIN) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1320 res = PY_LLONG_MIN;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1321 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1322 else {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1323 *overflow = sign;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1324 /* res is already set to -1 */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1325 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1326 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1327 exit:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1328 if (do_decref) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1329 Py_DECREF(vv);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1330 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1331 return res;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1332 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1333
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1334 #endif /* HAVE_LONG_LONG */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1335
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1336 #define CHECK_BINOP(v,w) \
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1337 do { \
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1338 if (!PyLong_Check(v) || !PyLong_Check(w)) \
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1339 Py_RETURN_NOTIMPLEMENTED; \
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1340 } while(0)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1341
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1342 /* bits_in_digit(d) returns the unique integer k such that 2**(k-1) <= d <
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1343 2**k if d is nonzero, else 0. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1344
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1345 static const unsigned char BitLengthTable[32] = {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1346 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1347 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1348 };
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1349
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1350 static int
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1351 bits_in_digit(digit d)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1352 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1353 int d_bits = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1354 while (d >= 32) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1355 d_bits += 6;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1356 d >>= 6;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1357 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1358 d_bits += (int)BitLengthTable[d];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1359 return d_bits;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1360 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1361
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1362 /* x[0:m] and y[0:n] are digit vectors, LSD first, m >= n required. x[0:n]
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1363 * is modified in place, by adding y to it. Carries are propagated as far as
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1364 * x[m-1], and the remaining carry (0 or 1) is returned.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1365 */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1366 static digit
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1367 v_iadd(digit *x, Py_ssize_t m, digit *y, Py_ssize_t n)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1368 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1369 Py_ssize_t i;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1370 digit carry = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1371
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1372 assert(m >= n);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1373 for (i = 0; i < n; ++i) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1374 carry += x[i] + y[i];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1375 x[i] = carry & PyLong_MASK;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1376 carry >>= PyLong_SHIFT;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1377 assert((carry & 1) == carry);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1378 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1379 for (; carry && i < m; ++i) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1380 carry += x[i];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1381 x[i] = carry & PyLong_MASK;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1382 carry >>= PyLong_SHIFT;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1383 assert((carry & 1) == carry);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1384 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1385 return carry;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1386 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1387
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1388 /* x[0:m] and y[0:n] are digit vectors, LSD first, m >= n required. x[0:n]
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1389 * is modified in place, by subtracting y from it. Borrows are propagated as
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1390 * far as x[m-1], and the remaining borrow (0 or 1) is returned.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1391 */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1392 static digit
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1393 v_isub(digit *x, Py_ssize_t m, digit *y, Py_ssize_t n)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1394 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1395 Py_ssize_t i;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1396 digit borrow = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1397
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1398 assert(m >= n);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1399 for (i = 0; i < n; ++i) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1400 borrow = x[i] - y[i] - borrow;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1401 x[i] = borrow & PyLong_MASK;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1402 borrow >>= PyLong_SHIFT;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1403 borrow &= 1; /* keep only 1 sign bit */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1404 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1405 for (; borrow && i < m; ++i) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1406 borrow = x[i] - borrow;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1407 x[i] = borrow & PyLong_MASK;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1408 borrow >>= PyLong_SHIFT;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1409 borrow &= 1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1410 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1411 return borrow;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1412 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1413
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1414 /* Shift digit vector a[0:m] d bits left, with 0 <= d < PyLong_SHIFT. Put
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1415 * result in z[0:m], and return the d bits shifted out of the top.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1416 */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1417 static digit
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1418 v_lshift(digit *z, digit *a, Py_ssize_t m, int d)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1419 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1420 Py_ssize_t i;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1421 digit carry = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1422
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1423 assert(0 <= d && d < PyLong_SHIFT);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1424 for (i=0; i < m; i++) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1425 twodigits acc = (twodigits)a[i] << d | carry;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1426 z[i] = (digit)acc & PyLong_MASK;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1427 carry = (digit)(acc >> PyLong_SHIFT);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1428 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1429 return carry;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1430 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1431
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1432 /* Shift digit vector a[0:m] d bits right, with 0 <= d < PyLong_SHIFT. Put
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1433 * result in z[0:m], and return the d bits shifted out of the bottom.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1434 */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1435 static digit
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1436 v_rshift(digit *z, digit *a, Py_ssize_t m, int d)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1437 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1438 Py_ssize_t i;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1439 digit carry = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1440 digit mask = ((digit)1 << d) - 1U;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1441
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1442 assert(0 <= d && d < PyLong_SHIFT);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1443 for (i=m; i-- > 0;) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1444 twodigits acc = (twodigits)carry << PyLong_SHIFT | a[i];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1445 carry = (digit)acc & mask;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1446 z[i] = (digit)(acc >> d);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1447 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1448 return carry;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1449 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1450
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1451 /* Divide long pin, w/ size digits, by non-zero digit n, storing quotient
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1452 in pout, and returning the remainder. pin and pout point at the LSD.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1453 It's OK for pin == pout on entry, which saves oodles of mallocs/frees in
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1454 _PyLong_Format, but that should be done with great care since longs are
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1455 immutable. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1456
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1457 static digit
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1458 inplace_divrem1(digit *pout, digit *pin, Py_ssize_t size, digit n)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1459 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1460 twodigits rem = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1461
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1462 assert(n > 0 && n <= PyLong_MASK);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1463 pin += size;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1464 pout += size;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1465 while (--size >= 0) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1466 digit hi;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1467 rem = (rem << PyLong_SHIFT) | *--pin;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1468 *--pout = hi = (digit)(rem / n);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1469 rem -= (twodigits)hi * n;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1470 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1471 return (digit)rem;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1472 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1473
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1474 /* Divide a long integer by a digit, returning both the quotient
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1475 (as function result) and the remainder (through *prem).
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1476 The sign of a is ignored; n should not be zero. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1477
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1478 static PyLongObject *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1479 divrem1(PyLongObject *a, digit n, digit *prem)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1480 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1481 const Py_ssize_t size = ABS(Py_SIZE(a));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1482 PyLongObject *z;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1483
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1484 assert(n > 0 && n <= PyLong_MASK);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1485 z = _PyLong_New(size);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1486 if (z == NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1487 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1488 *prem = inplace_divrem1(z->ob_digit, a->ob_digit, size, n);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1489 return long_normalize(z);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1490 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1491
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1492 /* Convert a long integer to a base 10 string. Returns a new non-shared
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1493 string. (Return value is non-shared so that callers can modify the
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1494 returned value if necessary.) */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1495
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1496 static PyObject *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1497 long_to_decimal_string(PyObject *aa)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1498 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1499 PyLongObject *scratch, *a;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1500 PyObject *str;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1501 Py_ssize_t size, strlen, size_a, i, j;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1502 digit *pout, *pin, rem, tenpow;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1503 unsigned char *p;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1504 int negative;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1505
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1506 a = (PyLongObject *)aa;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1507 if (a == NULL || !PyLong_Check(a)) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1508 PyErr_BadInternalCall();
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1509 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1510 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1511 size_a = ABS(Py_SIZE(a));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1512 negative = Py_SIZE(a) < 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1513
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1514 /* quick and dirty upper bound for the number of digits
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1515 required to express a in base _PyLong_DECIMAL_BASE:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1516
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1517 #digits = 1 + floor(log2(a) / log2(_PyLong_DECIMAL_BASE))
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1518
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1519 But log2(a) < size_a * PyLong_SHIFT, and
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1520 log2(_PyLong_DECIMAL_BASE) = log2(10) * _PyLong_DECIMAL_SHIFT
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1521 > 3 * _PyLong_DECIMAL_SHIFT
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1522 */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1523 if (size_a > PY_SSIZE_T_MAX / PyLong_SHIFT) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1524 PyErr_SetString(PyExc_OverflowError,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1525 "long is too large to format");
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1526 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1527 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1528 /* the expression size_a * PyLong_SHIFT is now safe from overflow */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1529 size = 1 + size_a * PyLong_SHIFT / (3 * _PyLong_DECIMAL_SHIFT);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1530 scratch = _PyLong_New(size);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1531 if (scratch == NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1532 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1533
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1534 /* convert array of base _PyLong_BASE digits in pin to an array of
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1535 base _PyLong_DECIMAL_BASE digits in pout, following Knuth (TAOCP,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1536 Volume 2 (3rd edn), section 4.4, Method 1b). */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1537 pin = a->ob_digit;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1538 pout = scratch->ob_digit;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1539 size = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1540 for (i = size_a; --i >= 0; ) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1541 digit hi = pin[i];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1542 for (j = 0; j < size; j++) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1543 twodigits z = (twodigits)pout[j] << PyLong_SHIFT | hi;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1544 hi = (digit)(z / _PyLong_DECIMAL_BASE);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1545 pout[j] = (digit)(z - (twodigits)hi *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1546 _PyLong_DECIMAL_BASE);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1547 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1548 while (hi) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1549 pout[size++] = hi % _PyLong_DECIMAL_BASE;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1550 hi /= _PyLong_DECIMAL_BASE;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1551 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1552 /* check for keyboard interrupt */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1553 SIGCHECK({
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1554 Py_DECREF(scratch);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1555 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1556 });
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1557 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1558 /* pout should have at least one digit, so that the case when a = 0
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1559 works correctly */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1560 if (size == 0)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1561 pout[size++] = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1562
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1563 /* calculate exact length of output string, and allocate */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1564 strlen = negative + 1 + (size - 1) * _PyLong_DECIMAL_SHIFT;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1565 tenpow = 10;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1566 rem = pout[size-1];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1567 while (rem >= tenpow) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1568 tenpow *= 10;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1569 strlen++;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1570 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1571 str = PyUnicode_New(strlen, '9');
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1572 if (str == NULL) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1573 Py_DECREF(scratch);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1574 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1575 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1576
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1577 /* fill the string right-to-left */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1578 assert(PyUnicode_KIND(str) == PyUnicode_1BYTE_KIND);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1579 p = PyUnicode_1BYTE_DATA(str) + strlen;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1580 *p = '\0';
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1581 /* pout[0] through pout[size-2] contribute exactly
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1582 _PyLong_DECIMAL_SHIFT digits each */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1583 for (i=0; i < size - 1; i++) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1584 rem = pout[i];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1585 for (j = 0; j < _PyLong_DECIMAL_SHIFT; j++) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1586 *--p = '0' + rem % 10;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1587 rem /= 10;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1588 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1589 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1590 /* pout[size-1]: always produce at least one decimal digit */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1591 rem = pout[i];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1592 do {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1593 *--p = '0' + rem % 10;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1594 rem /= 10;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1595 } while (rem != 0);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1596
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1597 /* and sign */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1598 if (negative)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1599 *--p = '-';
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1600
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1601 /* check we've counted correctly */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1602 assert(p == PyUnicode_1BYTE_DATA(str));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1603 Py_DECREF(scratch);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1604 return (PyObject *)str;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1605 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1606
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1607 /* Convert a long int object to a string, using a given conversion base,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1608 which should be one of 2, 8, 10 or 16. Return a string object.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1609 If base is 2, 8 or 16, add the proper prefix '0b', '0o' or '0x'. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1610
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1611 PyObject *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1612 _PyLong_Format(PyObject *aa, int base)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1613 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1614 register PyLongObject *a = (PyLongObject *)aa;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1615 PyObject *v;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1616 Py_ssize_t i, sz;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1617 Py_ssize_t size_a;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1618 char *p;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1619 char sign = '\0';
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1620 char *buffer;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1621 int bits;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1622
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1623 assert(base == 2 || base == 8 || base == 10 || base == 16);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1624 if (base == 10)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1625 return long_to_decimal_string((PyObject *)a);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1626
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1627 if (a == NULL || !PyLong_Check(a)) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1628 PyErr_BadInternalCall();
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1629 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1630 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1631 size_a = ABS(Py_SIZE(a));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1632
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1633 /* Compute a rough upper bound for the length of the string */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1634 switch (base) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1635 case 16:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1636 bits = 4;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1637 break;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1638 case 8:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1639 bits = 3;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1640 break;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1641 case 2:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1642 bits = 1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1643 break;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1644 default:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1645 assert(0); /* shouldn't ever get here */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1646 bits = 0; /* to silence gcc warning */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1647 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1648 /* compute length of output string: allow 2 characters for prefix and
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1649 1 for possible '-' sign. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1650 if (size_a > (PY_SSIZE_T_MAX - 3) / PyLong_SHIFT / sizeof(Py_UCS4)) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1651 PyErr_SetString(PyExc_OverflowError,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1652 "int is too large to format");
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1653 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1654 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1655 /* now size_a * PyLong_SHIFT + 3 <= PY_SSIZE_T_MAX, so the RHS below
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1656 is safe from overflow */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1657 sz = 3 + (size_a * PyLong_SHIFT + (bits - 1)) / bits;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1658 assert(sz >= 0);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1659 buffer = PyMem_Malloc(sz);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1660 if (buffer == NULL) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1661 PyErr_NoMemory();
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1662 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1663 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1664 p = &buffer[sz];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1665 if (Py_SIZE(a) < 0)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1666 sign = '-';
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1667
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1668 if (Py_SIZE(a) == 0) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1669 *--p = '0';
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1670 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1671 else {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1672 /* JRH: special case for power-of-2 bases */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1673 twodigits accum = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1674 int accumbits = 0; /* # of bits in accum */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1675 for (i = 0; i < size_a; ++i) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1676 accum |= (twodigits)a->ob_digit[i] << accumbits;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1677 accumbits += PyLong_SHIFT;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1678 assert(accumbits >= bits);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1679 do {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1680 char cdigit;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1681 cdigit = (char)(accum & (base - 1));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1682 cdigit += (cdigit < 10) ? '0' : 'a'-10;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1683 assert(p > buffer);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1684 *--p = cdigit;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1685 accumbits -= bits;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1686 accum >>= bits;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1687 } while (i < size_a-1 ? accumbits >= bits : accum > 0);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1688 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1689 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1690
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1691 if (base == 16)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1692 *--p = 'x';
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1693 else if (base == 8)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1694 *--p = 'o';
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1695 else /* (base == 2) */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1696 *--p = 'b';
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1697 *--p = '0';
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1698 if (sign)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1699 *--p = sign;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1700 v = PyUnicode_DecodeASCII(p, &buffer[sz] - p, NULL);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1701 PyMem_Free(buffer);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1702 return v;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1703 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1704
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1705 /* Table of digit values for 8-bit string -> integer conversion.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1706 * '0' maps to 0, ..., '9' maps to 9.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1707 * 'a' and 'A' map to 10, ..., 'z' and 'Z' map to 35.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1708 * All other indices map to 37.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1709 * Note that when converting a base B string, a char c is a legitimate
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1710 * base B digit iff _PyLong_DigitValue[Py_CHARPyLong_MASK(c)] < B.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1711 */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1712 unsigned char _PyLong_DigitValue[256] = {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1713 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1714 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1715 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1716 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 37, 37, 37, 37, 37, 37,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1717 37, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1718 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 37, 37, 37, 37, 37,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1719 37, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1720 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 37, 37, 37, 37, 37,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1721 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1722 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1723 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1724 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1725 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1726 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1727 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1728 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1729 };
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1730
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1731 /* *str points to the first digit in a string of base `base` digits. base
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1732 * is a power of 2 (2, 4, 8, 16, or 32). *str is set to point to the first
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1733 * non-digit (which may be *str!). A normalized long is returned.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1734 * The point to this routine is that it takes time linear in the number of
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1735 * string characters.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1736 */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1737 static PyLongObject *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1738 long_from_binary_base(char **str, int base)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1739 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1740 char *p = *str;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1741 char *start = p;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1742 int bits_per_char;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1743 Py_ssize_t n;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1744 PyLongObject *z;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1745 twodigits accum;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1746 int bits_in_accum;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1747 digit *pdigit;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1748
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1749 assert(base >= 2 && base <= 32 && (base & (base - 1)) == 0);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1750 n = base;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1751 for (bits_per_char = -1; n; ++bits_per_char)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1752 n >>= 1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1753 /* n <- total # of bits needed, while setting p to end-of-string */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1754 while (_PyLong_DigitValue[Py_CHARMASK(*p)] < base)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1755 ++p;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1756 *str = p;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1757 /* n <- # of Python digits needed, = ceiling(n/PyLong_SHIFT). */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1758 n = (p - start) * bits_per_char + PyLong_SHIFT - 1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1759 if (n / bits_per_char < p - start) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1760 PyErr_SetString(PyExc_ValueError,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1761 "int string too large to convert");
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1762 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1763 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1764 n = n / PyLong_SHIFT;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1765 z = _PyLong_New(n);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1766 if (z == NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1767 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1768 /* Read string from right, and fill in long from left; i.e.,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1769 * from least to most significant in both.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1770 */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1771 accum = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1772 bits_in_accum = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1773 pdigit = z->ob_digit;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1774 while (--p >= start) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1775 int k = (int)_PyLong_DigitValue[Py_CHARMASK(*p)];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1776 assert(k >= 0 && k < base);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1777 accum |= (twodigits)k << bits_in_accum;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1778 bits_in_accum += bits_per_char;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1779 if (bits_in_accum >= PyLong_SHIFT) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1780 *pdigit++ = (digit)(accum & PyLong_MASK);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1781 assert(pdigit - z->ob_digit <= n);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1782 accum >>= PyLong_SHIFT;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1783 bits_in_accum -= PyLong_SHIFT;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1784 assert(bits_in_accum < PyLong_SHIFT);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1785 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1786 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1787 if (bits_in_accum) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1788 assert(bits_in_accum <= PyLong_SHIFT);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1789 *pdigit++ = (digit)accum;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1790 assert(pdigit - z->ob_digit <= n);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1791 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1792 while (pdigit - z->ob_digit < n)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1793 *pdigit++ = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1794 return long_normalize(z);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1795 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1796
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1797 PyObject *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1798 PyLong_FromString(char *str, char **pend, int base)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1799 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1800 int sign = 1, error_if_nonzero = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1801 char *start, *orig_str = str;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1802 PyLongObject *z = NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1803 PyObject *strobj;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1804 Py_ssize_t slen;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1805
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1806 if ((base != 0 && base < 2) || base > 36) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1807 PyErr_SetString(PyExc_ValueError,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1808 "int() arg 2 must be >= 2 and <= 36");
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1809 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1810 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1811 while (*str != '\0' && isspace(Py_CHARMASK(*str)))
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1812 str++;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1813 if (*str == '+')
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1814 ++str;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1815 else if (*str == '-') {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1816 ++str;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1817 sign = -1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1818 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1819 if (base == 0) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1820 if (str[0] != '0')
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1821 base = 10;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1822 else if (str[1] == 'x' || str[1] == 'X')
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1823 base = 16;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1824 else if (str[1] == 'o' || str[1] == 'O')
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1825 base = 8;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1826 else if (str[1] == 'b' || str[1] == 'B')
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1827 base = 2;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1828 else {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1829 /* "old" (C-style) octal literal, now invalid.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1830 it might still be zero though */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1831 error_if_nonzero = 1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1832 base = 10;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1833 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1834 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1835 if (str[0] == '0' &&
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1836 ((base == 16 && (str[1] == 'x' || str[1] == 'X')) ||
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1837 (base == 8 && (str[1] == 'o' || str[1] == 'O')) ||
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1838 (base == 2 && (str[1] == 'b' || str[1] == 'B'))))
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1839 str += 2;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1840
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1841 start = str;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1842 if ((base & (base - 1)) == 0)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1843 z = long_from_binary_base(&str, base);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1844 else {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1845 /***
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1846 Binary bases can be converted in time linear in the number of digits, because
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1847 Python's representation base is binary. Other bases (including decimal!) use
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1848 the simple quadratic-time algorithm below, complicated by some speed tricks.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1849
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1850 First some math: the largest integer that can be expressed in N base-B digits
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1851 is B**N-1. Consequently, if we have an N-digit input in base B, the worst-
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1852 case number of Python digits needed to hold it is the smallest integer n s.t.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1853
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1854 BASE**n-1 >= B**N-1 [or, adding 1 to both sides]
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1855 BASE**n >= B**N [taking logs to base BASE]
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1856 n >= log(B**N)/log(BASE) = N * log(B)/log(BASE)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1857
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1858 The static array log_base_BASE[base] == log(base)/log(BASE) so we can compute
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1859 this quickly. A Python long with that much space is reserved near the start,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1860 and the result is computed into it.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1861
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1862 The input string is actually treated as being in base base**i (i.e., i digits
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1863 are processed at a time), where two more static arrays hold:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1864
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1865 convwidth_base[base] = the largest integer i such that base**i <= BASE
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1866 convmultmax_base[base] = base ** convwidth_base[base]
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1867
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1868 The first of these is the largest i such that i consecutive input digits
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1869 must fit in a single Python digit. The second is effectively the input
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1870 base we're really using.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1871
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1872 Viewing the input as a sequence <c0, c1, ..., c_n-1> of digits in base
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1873 convmultmax_base[base], the result is "simply"
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1874
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1875 (((c0*B + c1)*B + c2)*B + c3)*B + ... ))) + c_n-1
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1876
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1877 where B = convmultmax_base[base].
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1878
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1879 Error analysis: as above, the number of Python digits `n` needed is worst-
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1880 case
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1881
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1882 n >= N * log(B)/log(BASE)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1883
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1884 where `N` is the number of input digits in base `B`. This is computed via
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1885
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1886 size_z = (Py_ssize_t)((scan - str) * log_base_BASE[base]) + 1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1887
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1888 below. Two numeric concerns are how much space this can waste, and whether
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1889 the computed result can be too small. To be concrete, assume BASE = 2**15,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1890 which is the default (and it's unlikely anyone changes that).
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1891
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1892 Waste isn't a problem: provided the first input digit isn't 0, the difference
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1893 between the worst-case input with N digits and the smallest input with N
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1894 digits is about a factor of B, but B is small compared to BASE so at most
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1895 one allocated Python digit can remain unused on that count. If
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1896 N*log(B)/log(BASE) is mathematically an exact integer, then truncating that
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1897 and adding 1 returns a result 1 larger than necessary. However, that can't
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1898 happen: whenever B is a power of 2, long_from_binary_base() is called
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1899 instead, and it's impossible for B**i to be an integer power of 2**15 when
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1900 B is not a power of 2 (i.e., it's impossible for N*log(B)/log(BASE) to be
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1901 an exact integer when B is not a power of 2, since B**i has a prime factor
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1902 other than 2 in that case, but (2**15)**j's only prime factor is 2).
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1903
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1904 The computed result can be too small if the true value of N*log(B)/log(BASE)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1905 is a little bit larger than an exact integer, but due to roundoff errors (in
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1906 computing log(B), log(BASE), their quotient, and/or multiplying that by N)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1907 yields a numeric result a little less than that integer. Unfortunately, "how
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1908 close can a transcendental function get to an integer over some range?"
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1909 questions are generally theoretically intractable. Computer analysis via
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1910 continued fractions is practical: expand log(B)/log(BASE) via continued
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1911 fractions, giving a sequence i/j of "the best" rational approximations. Then
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1912 j*log(B)/log(BASE) is approximately equal to (the integer) i. This shows that
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1913 we can get very close to being in trouble, but very rarely. For example,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1914 76573 is a denominator in one of the continued-fraction approximations to
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1915 log(10)/log(2**15), and indeed:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1916
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1917 >>> log(10)/log(2**15)*76573
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1918 16958.000000654003
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1919
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1920 is very close to an integer. If we were working with IEEE single-precision,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1921 rounding errors could kill us. Finding worst cases in IEEE double-precision
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1922 requires better-than-double-precision log() functions, and Tim didn't bother.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1923 Instead the code checks to see whether the allocated space is enough as each
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1924 new Python digit is added, and copies the whole thing to a larger long if not.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1925 This should happen extremely rarely, and in fact I don't have a test case
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1926 that triggers it(!). Instead the code was tested by artificially allocating
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1927 just 1 digit at the start, so that the copying code was exercised for every
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1928 digit beyond the first.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1929 ***/
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1930 register twodigits c; /* current input character */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1931 Py_ssize_t size_z;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1932 int i;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1933 int convwidth;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1934 twodigits convmultmax, convmult;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1935 digit *pz, *pzstop;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1936 char* scan;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1937
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1938 static double log_base_BASE[37] = {0.0e0,};
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1939 static int convwidth_base[37] = {0,};
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1940 static twodigits convmultmax_base[37] = {0,};
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1941
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1942 if (log_base_BASE[base] == 0.0) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1943 twodigits convmax = base;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1944 int i = 1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1945
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1946 log_base_BASE[base] = (log((double)base) /
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1947 log((double)PyLong_BASE));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1948 for (;;) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1949 twodigits next = convmax * base;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1950 if (next > PyLong_BASE)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1951 break;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1952 convmax = next;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1953 ++i;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1954 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1955 convmultmax_base[base] = convmax;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1956 assert(i > 0);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1957 convwidth_base[base] = i;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1958 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1959
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1960 /* Find length of the string of numeric characters. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1961 scan = str;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1962 while (_PyLong_DigitValue[Py_CHARMASK(*scan)] < base)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1963 ++scan;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1964
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1965 /* Create a long object that can contain the largest possible
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1966 * integer with this base and length. Note that there's no
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1967 * need to initialize z->ob_digit -- no slot is read up before
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1968 * being stored into.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1969 */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1970 size_z = (Py_ssize_t)((scan - str) * log_base_BASE[base]) + 1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1971 /* Uncomment next line to test exceedingly rare copy code */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1972 /* size_z = 1; */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1973 assert(size_z > 0);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1974 z = _PyLong_New(size_z);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1975 if (z == NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1976 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1977 Py_SIZE(z) = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1978
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1979 /* `convwidth` consecutive input digits are treated as a single
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1980 * digit in base `convmultmax`.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1981 */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1982 convwidth = convwidth_base[base];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1983 convmultmax = convmultmax_base[base];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1984
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1985 /* Work ;-) */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1986 while (str < scan) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1987 /* grab up to convwidth digits from the input string */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1988 c = (digit)_PyLong_DigitValue[Py_CHARMASK(*str++)];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1989 for (i = 1; i < convwidth && str != scan; ++i, ++str) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1990 c = (twodigits)(c * base +
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1991 (int)_PyLong_DigitValue[Py_CHARMASK(*str)]);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1992 assert(c < PyLong_BASE);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1993 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1994
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1995 convmult = convmultmax;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1996 /* Calculate the shift only if we couldn't get
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1997 * convwidth digits.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1998 */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
1999 if (i != convwidth) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2000 convmult = base;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2001 for ( ; i > 1; --i)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2002 convmult *= base;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2003 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2004
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2005 /* Multiply z by convmult, and add c. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2006 pz = z->ob_digit;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2007 pzstop = pz + Py_SIZE(z);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2008 for (; pz < pzstop; ++pz) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2009 c += (twodigits)*pz * convmult;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2010 *pz = (digit)(c & PyLong_MASK);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2011 c >>= PyLong_SHIFT;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2012 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2013 /* carry off the current end? */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2014 if (c) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2015 assert(c < PyLong_BASE);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2016 if (Py_SIZE(z) < size_z) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2017 *pz = (digit)c;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2018 ++Py_SIZE(z);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2019 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2020 else {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2021 PyLongObject *tmp;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2022 /* Extremely rare. Get more space. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2023 assert(Py_SIZE(z) == size_z);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2024 tmp = _PyLong_New(size_z + 1);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2025 if (tmp == NULL) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2026 Py_DECREF(z);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2027 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2028 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2029 memcpy(tmp->ob_digit,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2030 z->ob_digit,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2031 sizeof(digit) * size_z);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2032 Py_DECREF(z);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2033 z = tmp;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2034 z->ob_digit[size_z] = (digit)c;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2035 ++size_z;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2036 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2037 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2038 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2039 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2040 if (z == NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2041 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2042 if (error_if_nonzero) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2043 /* reset the base to 0, else the exception message
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2044 doesn't make too much sense */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2045 base = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2046 if (Py_SIZE(z) != 0)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2047 goto onError;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2048 /* there might still be other problems, therefore base
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2049 remains zero here for the same reason */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2050 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2051 if (str == start)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2052 goto onError;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2053 if (sign < 0)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2054 Py_SIZE(z) = -(Py_SIZE(z));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2055 while (*str && isspace(Py_CHARMASK(*str)))
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2056 str++;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2057 if (*str != '\0')
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2058 goto onError;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2059 if (pend)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2060 *pend = str;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2061 long_normalize(z);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2062 return (PyObject *) maybe_small_long(z);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2063
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2064 onError:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2065 Py_XDECREF(z);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2066 slen = strlen(orig_str) < 200 ? strlen(orig_str) : 200;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2067 strobj = PyUnicode_FromStringAndSize(orig_str, slen);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2068 if (strobj == NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2069 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2070 PyErr_Format(PyExc_ValueError,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2071 "invalid literal for int() with base %d: %R",
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2072 base, strobj);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2073 Py_DECREF(strobj);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2074 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2075 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2076
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2077 PyObject *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2078 PyLong_FromUnicode(Py_UNICODE *u, Py_ssize_t length, int base)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2079 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2080 PyObject *v, *unicode = PyUnicode_FromUnicode(u, length);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2081 if (unicode == NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2082 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2083 v = PyLong_FromUnicodeObject(unicode, base);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2084 Py_DECREF(unicode);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2085 return v;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2086 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2087
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2088 PyObject *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2089 PyLong_FromUnicodeObject(PyObject *u, int base)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2090 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2091 PyObject *result;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2092 PyObject *asciidig;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2093 char *buffer, *end;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2094 Py_ssize_t buflen;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2095
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2096 asciidig = _PyUnicode_TransformDecimalAndSpaceToASCII(u);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2097 if (asciidig == NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2098 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2099 buffer = PyUnicode_AsUTF8AndSize(asciidig, &buflen);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2100 if (buffer == NULL) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2101 Py_DECREF(asciidig);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2102 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2103 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2104 result = PyLong_FromString(buffer, &end, base);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2105 if (result != NULL && end != buffer + buflen) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2106 PyErr_SetString(PyExc_ValueError,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2107 "null byte in argument for int()");
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2108 Py_DECREF(result);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2109 result = NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2110 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2111 Py_DECREF(asciidig);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2112 return result;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2113 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2114
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2115 /* forward */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2116 static PyLongObject *x_divrem
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2117 (PyLongObject *, PyLongObject *, PyLongObject **);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2118 static PyObject *long_long(PyObject *v);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2119
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2120 /* Long division with remainder, top-level routine */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2121
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2122 static int
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2123 long_divrem(PyLongObject *a, PyLongObject *b,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2124 PyLongObject **pdiv, PyLongObject **prem)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2125 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2126 Py_ssize_t size_a = ABS(Py_SIZE(a)), size_b = ABS(Py_SIZE(b));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2127 PyLongObject *z;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2128
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2129 if (size_b == 0) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2130 PyErr_SetString(PyExc_ZeroDivisionError,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2131 "integer division or modulo by zero");
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2132 return -1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2133 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2134 if (size_a < size_b ||
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2135 (size_a == size_b &&
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2136 a->ob_digit[size_a-1] < b->ob_digit[size_b-1])) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2137 /* |a| < |b|. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2138 *pdiv = (PyLongObject*)PyLong_FromLong(0);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2139 if (*pdiv == NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2140 return -1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2141 Py_INCREF(a);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2142 *prem = (PyLongObject *) a;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2143 return 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2144 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2145 if (size_b == 1) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2146 digit rem = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2147 z = divrem1(a, b->ob_digit[0], &rem);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2148 if (z == NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2149 return -1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2150 *prem = (PyLongObject *) PyLong_FromLong((long)rem);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2151 if (*prem == NULL) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2152 Py_DECREF(z);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2153 return -1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2154 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2155 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2156 else {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2157 z = x_divrem(a, b, prem);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2158 if (z == NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2159 return -1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2160 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2161 /* Set the signs.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2162 The quotient z has the sign of a*b;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2163 the remainder r has the sign of a,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2164 so a = b*z + r. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2165 if ((Py_SIZE(a) < 0) != (Py_SIZE(b) < 0))
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2166 NEGATE(z);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2167 if (Py_SIZE(a) < 0 && Py_SIZE(*prem) != 0)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2168 NEGATE(*prem);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2169 *pdiv = maybe_small_long(z);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2170 return 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2171 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2172
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2173 /* Unsigned long division with remainder -- the algorithm. The arguments v1
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2174 and w1 should satisfy 2 <= ABS(Py_SIZE(w1)) <= ABS(Py_SIZE(v1)). */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2175
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2176 static PyLongObject *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2177 x_divrem(PyLongObject *v1, PyLongObject *w1, PyLongObject **prem)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2178 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2179 PyLongObject *v, *w, *a;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2180 Py_ssize_t i, k, size_v, size_w;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2181 int d;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2182 digit wm1, wm2, carry, q, r, vtop, *v0, *vk, *w0, *ak;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2183 twodigits vv;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2184 sdigit zhi;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2185 stwodigits z;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2186
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2187 /* We follow Knuth [The Art of Computer Programming, Vol. 2 (3rd
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2188 edn.), section 4.3.1, Algorithm D], except that we don't explicitly
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2189 handle the special case when the initial estimate q for a quotient
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2190 digit is >= PyLong_BASE: the max value for q is PyLong_BASE+1, and
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2191 that won't overflow a digit. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2192
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2193 /* allocate space; w will also be used to hold the final remainder */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2194 size_v = ABS(Py_SIZE(v1));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2195 size_w = ABS(Py_SIZE(w1));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2196 assert(size_v >= size_w && size_w >= 2); /* Assert checks by div() */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2197 v = _PyLong_New(size_v+1);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2198 if (v == NULL) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2199 *prem = NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2200 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2201 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2202 w = _PyLong_New(size_w);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2203 if (w == NULL) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2204 Py_DECREF(v);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2205 *prem = NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2206 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2207 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2208
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2209 /* normalize: shift w1 left so that its top digit is >= PyLong_BASE/2.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2210 shift v1 left by the same amount. Results go into w and v. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2211 d = PyLong_SHIFT - bits_in_digit(w1->ob_digit[size_w-1]);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2212 carry = v_lshift(w->ob_digit, w1->ob_digit, size_w, d);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2213 assert(carry == 0);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2214 carry = v_lshift(v->ob_digit, v1->ob_digit, size_v, d);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2215 if (carry != 0 || v->ob_digit[size_v-1] >= w->ob_digit[size_w-1]) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2216 v->ob_digit[size_v] = carry;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2217 size_v++;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2218 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2219
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2220 /* Now v->ob_digit[size_v-1] < w->ob_digit[size_w-1], so quotient has
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2221 at most (and usually exactly) k = size_v - size_w digits. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2222 k = size_v - size_w;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2223 assert(k >= 0);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2224 a = _PyLong_New(k);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2225 if (a == NULL) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2226 Py_DECREF(w);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2227 Py_DECREF(v);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2228 *prem = NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2229 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2230 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2231 v0 = v->ob_digit;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2232 w0 = w->ob_digit;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2233 wm1 = w0[size_w-1];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2234 wm2 = w0[size_w-2];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2235 for (vk = v0+k, ak = a->ob_digit + k; vk-- > v0;) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2236 /* inner loop: divide vk[0:size_w+1] by w0[0:size_w], giving
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2237 single-digit quotient q, remainder in vk[0:size_w]. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2238
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2239 SIGCHECK({
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2240 Py_DECREF(a);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2241 Py_DECREF(w);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2242 Py_DECREF(v);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2243 *prem = NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2244 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2245 });
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2246
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2247 /* estimate quotient digit q; may overestimate by 1 (rare) */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2248 vtop = vk[size_w];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2249 assert(vtop <= wm1);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2250 vv = ((twodigits)vtop << PyLong_SHIFT) | vk[size_w-1];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2251 q = (digit)(vv / wm1);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2252 r = (digit)(vv - (twodigits)wm1 * q); /* r = vv % wm1 */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2253 while ((twodigits)wm2 * q > (((twodigits)r << PyLong_SHIFT)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2254 | vk[size_w-2])) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2255 --q;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2256 r += wm1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2257 if (r >= PyLong_BASE)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2258 break;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2259 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2260 assert(q <= PyLong_BASE);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2261
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2262 /* subtract q*w0[0:size_w] from vk[0:size_w+1] */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2263 zhi = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2264 for (i = 0; i < size_w; ++i) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2265 /* invariants: -PyLong_BASE <= -q <= zhi <= 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2266 -PyLong_BASE * q <= z < PyLong_BASE */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2267 z = (sdigit)vk[i] + zhi -
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2268 (stwodigits)q * (stwodigits)w0[i];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2269 vk[i] = (digit)z & PyLong_MASK;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2270 zhi = (sdigit)Py_ARITHMETIC_RIGHT_SHIFT(stwodigits,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2271 z, PyLong_SHIFT);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2272 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2273
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2274 /* add w back if q was too large (this branch taken rarely) */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2275 assert((sdigit)vtop + zhi == -1 || (sdigit)vtop + zhi == 0);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2276 if ((sdigit)vtop + zhi < 0) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2277 carry = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2278 for (i = 0; i < size_w; ++i) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2279 carry += vk[i] + w0[i];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2280 vk[i] = carry & PyLong_MASK;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2281 carry >>= PyLong_SHIFT;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2282 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2283 --q;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2284 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2285
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2286 /* store quotient digit */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2287 assert(q < PyLong_BASE);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2288 *--ak = q;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2289 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2290
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2291 /* unshift remainder; we reuse w to store the result */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2292 carry = v_rshift(w0, v0, size_w, d);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2293 assert(carry==0);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2294 Py_DECREF(v);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2295
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2296 *prem = long_normalize(w);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2297 return long_normalize(a);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2298 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2299
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2300 /* For a nonzero PyLong a, express a in the form x * 2**e, with 0.5 <=
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2301 abs(x) < 1.0 and e >= 0; return x and put e in *e. Here x is
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2302 rounded to DBL_MANT_DIG significant bits using round-half-to-even.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2303 If a == 0, return 0.0 and set *e = 0. If the resulting exponent
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2304 e is larger than PY_SSIZE_T_MAX, raise OverflowError and return
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2305 -1.0. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2306
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2307 /* attempt to define 2.0**DBL_MANT_DIG as a compile-time constant */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2308 #if DBL_MANT_DIG == 53
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2309 #define EXP2_DBL_MANT_DIG 9007199254740992.0
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2310 #else
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2311 #define EXP2_DBL_MANT_DIG (ldexp(1.0, DBL_MANT_DIG))
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2312 #endif
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2313
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2314 double
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2315 _PyLong_Frexp(PyLongObject *a, Py_ssize_t *e)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2316 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2317 Py_ssize_t a_size, a_bits, shift_digits, shift_bits, x_size;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2318 /* See below for why x_digits is always large enough. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2319 digit rem, x_digits[2 + (DBL_MANT_DIG + 1) / PyLong_SHIFT];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2320 double dx;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2321 /* Correction term for round-half-to-even rounding. For a digit x,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2322 "x + half_even_correction[x & 7]" gives x rounded to the nearest
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2323 multiple of 4, rounding ties to a multiple of 8. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2324 static const int half_even_correction[8] = {0, -1, -2, 1, 0, -1, 2, 1};
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2325
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2326 a_size = ABS(Py_SIZE(a));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2327 if (a_size == 0) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2328 /* Special case for 0: significand 0.0, exponent 0. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2329 *e = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2330 return 0.0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2331 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2332 a_bits = bits_in_digit(a->ob_digit[a_size-1]);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2333 /* The following is an overflow-free version of the check
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2334 "if ((a_size - 1) * PyLong_SHIFT + a_bits > PY_SSIZE_T_MAX) ..." */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2335 if (a_size >= (PY_SSIZE_T_MAX - 1) / PyLong_SHIFT + 1 &&
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2336 (a_size > (PY_SSIZE_T_MAX - 1) / PyLong_SHIFT + 1 ||
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2337 a_bits > (PY_SSIZE_T_MAX - 1) % PyLong_SHIFT + 1))
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2338 goto overflow;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2339 a_bits = (a_size - 1) * PyLong_SHIFT + a_bits;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2340
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2341 /* Shift the first DBL_MANT_DIG + 2 bits of a into x_digits[0:x_size]
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2342 (shifting left if a_bits <= DBL_MANT_DIG + 2).
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2343
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2344 Number of digits needed for result: write // for floor division.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2345 Then if shifting left, we end up using
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2346
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2347 1 + a_size + (DBL_MANT_DIG + 2 - a_bits) // PyLong_SHIFT
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2348
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2349 digits. If shifting right, we use
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2350
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2351 a_size - (a_bits - DBL_MANT_DIG - 2) // PyLong_SHIFT
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2352
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2353 digits. Using a_size = 1 + (a_bits - 1) // PyLong_SHIFT along with
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2354 the inequalities
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2355
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2356 m // PyLong_SHIFT + n // PyLong_SHIFT <= (m + n) // PyLong_SHIFT
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2357 m // PyLong_SHIFT - n // PyLong_SHIFT <=
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2358 1 + (m - n - 1) // PyLong_SHIFT,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2359
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2360 valid for any integers m and n, we find that x_size satisfies
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2361
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2362 x_size <= 2 + (DBL_MANT_DIG + 1) // PyLong_SHIFT
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2363
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2364 in both cases.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2365 */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2366 if (a_bits <= DBL_MANT_DIG + 2) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2367 shift_digits = (DBL_MANT_DIG + 2 - a_bits) / PyLong_SHIFT;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2368 shift_bits = (DBL_MANT_DIG + 2 - a_bits) % PyLong_SHIFT;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2369 x_size = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2370 while (x_size < shift_digits)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2371 x_digits[x_size++] = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2372 rem = v_lshift(x_digits + x_size, a->ob_digit, a_size,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2373 (int)shift_bits);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2374 x_size += a_size;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2375 x_digits[x_size++] = rem;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2376 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2377 else {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2378 shift_digits = (a_bits - DBL_MANT_DIG - 2) / PyLong_SHIFT;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2379 shift_bits = (a_bits - DBL_MANT_DIG - 2) % PyLong_SHIFT;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2380 rem = v_rshift(x_digits, a->ob_digit + shift_digits,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2381 a_size - shift_digits, (int)shift_bits);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2382 x_size = a_size - shift_digits;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2383 /* For correct rounding below, we need the least significant
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2384 bit of x to be 'sticky' for this shift: if any of the bits
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2385 shifted out was nonzero, we set the least significant bit
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2386 of x. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2387 if (rem)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2388 x_digits[0] |= 1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2389 else
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2390 while (shift_digits > 0)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2391 if (a->ob_digit[--shift_digits]) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2392 x_digits[0] |= 1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2393 break;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2394 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2395 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2396 assert(1 <= x_size && x_size <= (Py_ssize_t)Py_ARRAY_LENGTH(x_digits));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2397
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2398 /* Round, and convert to double. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2399 x_digits[0] += half_even_correction[x_digits[0] & 7];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2400 dx = x_digits[--x_size];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2401 while (x_size > 0)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2402 dx = dx * PyLong_BASE + x_digits[--x_size];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2403
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2404 /* Rescale; make correction if result is 1.0. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2405 dx /= 4.0 * EXP2_DBL_MANT_DIG;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2406 if (dx == 1.0) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2407 if (a_bits == PY_SSIZE_T_MAX)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2408 goto overflow;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2409 dx = 0.5;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2410 a_bits += 1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2411 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2412
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2413 *e = a_bits;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2414 return Py_SIZE(a) < 0 ? -dx : dx;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2415
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2416 overflow:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2417 /* exponent > PY_SSIZE_T_MAX */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2418 PyErr_SetString(PyExc_OverflowError,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2419 "huge integer: number of bits overflows a Py_ssize_t");
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2420 *e = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2421 return -1.0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2422 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2423
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2424 /* Get a C double from a long int object. Rounds to the nearest double,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2425 using the round-half-to-even rule in the case of a tie. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2426
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2427 double
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2428 PyLong_AsDouble(PyObject *v)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2429 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2430 Py_ssize_t exponent;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2431 double x;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2432
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2433 if (v == NULL) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2434 PyErr_BadInternalCall();
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2435 return -1.0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2436 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2437 if (!PyLong_Check(v)) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2438 PyErr_SetString(PyExc_TypeError, "an integer is required");
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2439 return -1.0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2440 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2441 x = _PyLong_Frexp((PyLongObject *)v, &exponent);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2442 if ((x == -1.0 && PyErr_Occurred()) || exponent > DBL_MAX_EXP) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2443 PyErr_SetString(PyExc_OverflowError,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2444 "long int too large to convert to float");
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2445 return -1.0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2446 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2447 return ldexp(x, (int)exponent);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2448 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2449
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2450 /* Methods */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2451
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2452 static void
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2453 long_dealloc(PyObject *v)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2454 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2455 Py_TYPE(v)->tp_free(v);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2456 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2457
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2458 static int
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2459 long_compare(PyLongObject *a, PyLongObject *b)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2460 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2461 Py_ssize_t sign;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2462
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2463 if (Py_SIZE(a) != Py_SIZE(b)) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2464 sign = Py_SIZE(a) - Py_SIZE(b);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2465 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2466 else {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2467 Py_ssize_t i = ABS(Py_SIZE(a));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2468 while (--i >= 0 && a->ob_digit[i] == b->ob_digit[i])
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2469 ;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2470 if (i < 0)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2471 sign = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2472 else {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2473 sign = (sdigit)a->ob_digit[i] - (sdigit)b->ob_digit[i];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2474 if (Py_SIZE(a) < 0)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2475 sign = -sign;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2476 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2477 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2478 return sign < 0 ? -1 : sign > 0 ? 1 : 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2479 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2480
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2481 #define TEST_COND(cond) \
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2482 ((cond) ? Py_True : Py_False)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2483
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2484 static PyObject *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2485 long_richcompare(PyObject *self, PyObject *other, int op)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2486 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2487 int result;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2488 PyObject *v;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2489 CHECK_BINOP(self, other);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2490 if (self == other)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2491 result = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2492 else
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2493 result = long_compare((PyLongObject*)self, (PyLongObject*)other);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2494 /* Convert the return value to a Boolean */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2495 switch (op) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2496 case Py_EQ:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2497 v = TEST_COND(result == 0);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2498 break;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2499 case Py_NE:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2500 v = TEST_COND(result != 0);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2501 break;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2502 case Py_LE:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2503 v = TEST_COND(result <= 0);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2504 break;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2505 case Py_GE:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2506 v = TEST_COND(result >= 0);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2507 break;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2508 case Py_LT:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2509 v = TEST_COND(result == -1);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2510 break;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2511 case Py_GT:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2512 v = TEST_COND(result == 1);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2513 break;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2514 default:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2515 PyErr_BadArgument();
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2516 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2517 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2518 Py_INCREF(v);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2519 return v;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2520 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2521
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2522 static Py_hash_t
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2523 long_hash(PyLongObject *v)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2524 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2525 Py_uhash_t x;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2526 Py_ssize_t i;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2527 int sign;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2528
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2529 i = Py_SIZE(v);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2530 switch(i) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2531 case -1: return v->ob_digit[0]==1 ? -2 : -(sdigit)v->ob_digit[0];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2532 case 0: return 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2533 case 1: return v->ob_digit[0];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2534 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2535 sign = 1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2536 x = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2537 if (i < 0) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2538 sign = -1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2539 i = -(i);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2540 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2541 while (--i >= 0) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2542 /* Here x is a quantity in the range [0, _PyHASH_MODULUS); we
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2543 want to compute x * 2**PyLong_SHIFT + v->ob_digit[i] modulo
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2544 _PyHASH_MODULUS.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2545
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2546 The computation of x * 2**PyLong_SHIFT % _PyHASH_MODULUS
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2547 amounts to a rotation of the bits of x. To see this, write
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2548
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2549 x * 2**PyLong_SHIFT = y * 2**_PyHASH_BITS + z
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2550
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2551 where y = x >> (_PyHASH_BITS - PyLong_SHIFT) gives the top
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2552 PyLong_SHIFT bits of x (those that are shifted out of the
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2553 original _PyHASH_BITS bits, and z = (x << PyLong_SHIFT) &
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2554 _PyHASH_MODULUS gives the bottom _PyHASH_BITS - PyLong_SHIFT
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2555 bits of x, shifted up. Then since 2**_PyHASH_BITS is
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2556 congruent to 1 modulo _PyHASH_MODULUS, y*2**_PyHASH_BITS is
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2557 congruent to y modulo _PyHASH_MODULUS. So
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2558
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2559 x * 2**PyLong_SHIFT = y + z (mod _PyHASH_MODULUS).
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2560
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2561 The right-hand side is just the result of rotating the
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2562 _PyHASH_BITS bits of x left by PyLong_SHIFT places; since
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2563 not all _PyHASH_BITS bits of x are 1s, the same is true
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2564 after rotation, so 0 <= y+z < _PyHASH_MODULUS and y + z is
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2565 the reduction of x*2**PyLong_SHIFT modulo
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2566 _PyHASH_MODULUS. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2567 x = ((x << PyLong_SHIFT) & _PyHASH_MODULUS) |
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2568 (x >> (_PyHASH_BITS - PyLong_SHIFT));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2569 x += v->ob_digit[i];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2570 if (x >= _PyHASH_MODULUS)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2571 x -= _PyHASH_MODULUS;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2572 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2573 x = x * sign;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2574 if (x == (Py_uhash_t)-1)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2575 x = (Py_uhash_t)-2;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2576 return (Py_hash_t)x;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2577 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2578
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2579
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2580 /* Add the absolute values of two long integers. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2581
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2582 static PyLongObject *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2583 x_add(PyLongObject *a, PyLongObject *b)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2584 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2585 Py_ssize_t size_a = ABS(Py_SIZE(a)), size_b = ABS(Py_SIZE(b));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2586 PyLongObject *z;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2587 Py_ssize_t i;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2588 digit carry = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2589
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2590 /* Ensure a is the larger of the two: */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2591 if (size_a < size_b) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2592 { PyLongObject *temp = a; a = b; b = temp; }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2593 { Py_ssize_t size_temp = size_a;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2594 size_a = size_b;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2595 size_b = size_temp; }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2596 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2597 z = _PyLong_New(size_a+1);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2598 if (z == NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2599 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2600 for (i = 0; i < size_b; ++i) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2601 carry += a->ob_digit[i] + b->ob_digit[i];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2602 z->ob_digit[i] = carry & PyLong_MASK;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2603 carry >>= PyLong_SHIFT;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2604 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2605 for (; i < size_a; ++i) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2606 carry += a->ob_digit[i];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2607 z->ob_digit[i] = carry & PyLong_MASK;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2608 carry >>= PyLong_SHIFT;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2609 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2610 z->ob_digit[i] = carry;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2611 return long_normalize(z);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2612 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2613
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2614 /* Subtract the absolute values of two integers. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2615
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2616 static PyLongObject *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2617 x_sub(PyLongObject *a, PyLongObject *b)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2618 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2619 Py_ssize_t size_a = ABS(Py_SIZE(a)), size_b = ABS(Py_SIZE(b));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2620 PyLongObject *z;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2621 Py_ssize_t i;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2622 int sign = 1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2623 digit borrow = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2624
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2625 /* Ensure a is the larger of the two: */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2626 if (size_a < size_b) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2627 sign = -1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2628 { PyLongObject *temp = a; a = b; b = temp; }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2629 { Py_ssize_t size_temp = size_a;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2630 size_a = size_b;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2631 size_b = size_temp; }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2632 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2633 else if (size_a == size_b) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2634 /* Find highest digit where a and b differ: */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2635 i = size_a;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2636 while (--i >= 0 && a->ob_digit[i] == b->ob_digit[i])
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2637 ;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2638 if (i < 0)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2639 return (PyLongObject *)PyLong_FromLong(0);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2640 if (a->ob_digit[i] < b->ob_digit[i]) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2641 sign = -1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2642 { PyLongObject *temp = a; a = b; b = temp; }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2643 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2644 size_a = size_b = i+1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2645 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2646 z = _PyLong_New(size_a);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2647 if (z == NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2648 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2649 for (i = 0; i < size_b; ++i) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2650 /* The following assumes unsigned arithmetic
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2651 works module 2**N for some N>PyLong_SHIFT. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2652 borrow = a->ob_digit[i] - b->ob_digit[i] - borrow;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2653 z->ob_digit[i] = borrow & PyLong_MASK;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2654 borrow >>= PyLong_SHIFT;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2655 borrow &= 1; /* Keep only one sign bit */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2656 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2657 for (; i < size_a; ++i) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2658 borrow = a->ob_digit[i] - borrow;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2659 z->ob_digit[i] = borrow & PyLong_MASK;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2660 borrow >>= PyLong_SHIFT;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2661 borrow &= 1; /* Keep only one sign bit */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2662 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2663 assert(borrow == 0);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2664 if (sign < 0)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2665 NEGATE(z);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2666 return long_normalize(z);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2667 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2668
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2669 static PyObject *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2670 long_add(PyLongObject *a, PyLongObject *b)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2671 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2672 PyLongObject *z;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2673
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2674 CHECK_BINOP(a, b);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2675
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2676 if (ABS(Py_SIZE(a)) <= 1 && ABS(Py_SIZE(b)) <= 1) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2677 PyObject *result = PyLong_FromLong(MEDIUM_VALUE(a) +
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2678 MEDIUM_VALUE(b));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2679 return result;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2680 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2681 if (Py_SIZE(a) < 0) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2682 if (Py_SIZE(b) < 0) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2683 z = x_add(a, b);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2684 if (z != NULL && Py_SIZE(z) != 0)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2685 Py_SIZE(z) = -(Py_SIZE(z));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2686 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2687 else
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2688 z = x_sub(b, a);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2689 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2690 else {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2691 if (Py_SIZE(b) < 0)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2692 z = x_sub(a, b);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2693 else
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2694 z = x_add(a, b);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2695 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2696 return (PyObject *)z;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2697 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2698
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2699 static PyObject *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2700 long_sub(PyLongObject *a, PyLongObject *b)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2701 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2702 PyLongObject *z;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2703
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2704 CHECK_BINOP(a, b);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2705
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2706 if (ABS(Py_SIZE(a)) <= 1 && ABS(Py_SIZE(b)) <= 1) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2707 PyObject* r;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2708 r = PyLong_FromLong(MEDIUM_VALUE(a)-MEDIUM_VALUE(b));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2709 return r;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2710 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2711 if (Py_SIZE(a) < 0) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2712 if (Py_SIZE(b) < 0)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2713 z = x_sub(a, b);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2714 else
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2715 z = x_add(a, b);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2716 if (z != NULL && Py_SIZE(z) != 0)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2717 Py_SIZE(z) = -(Py_SIZE(z));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2718 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2719 else {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2720 if (Py_SIZE(b) < 0)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2721 z = x_add(a, b);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2722 else
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2723 z = x_sub(a, b);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2724 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2725 return (PyObject *)z;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2726 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2727
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2728 /* Grade school multiplication, ignoring the signs.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2729 * Returns the absolute value of the product, or NULL if error.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2730 */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2731 static PyLongObject *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2732 x_mul(PyLongObject *a, PyLongObject *b)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2733 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2734 PyLongObject *z;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2735 Py_ssize_t size_a = ABS(Py_SIZE(a));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2736 Py_ssize_t size_b = ABS(Py_SIZE(b));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2737 Py_ssize_t i;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2738
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2739 z = _PyLong_New(size_a + size_b);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2740 if (z == NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2741 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2742
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2743 memset(z->ob_digit, 0, Py_SIZE(z) * sizeof(digit));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2744 if (a == b) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2745 /* Efficient squaring per HAC, Algorithm 14.16:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2746 * http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2747 * Gives slightly less than a 2x speedup when a == b,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2748 * via exploiting that each entry in the multiplication
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2749 * pyramid appears twice (except for the size_a squares).
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2750 */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2751 for (i = 0; i < size_a; ++i) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2752 twodigits carry;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2753 twodigits f = a->ob_digit[i];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2754 digit *pz = z->ob_digit + (i << 1);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2755 digit *pa = a->ob_digit + i + 1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2756 digit *paend = a->ob_digit + size_a;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2757
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2758 SIGCHECK({
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2759 Py_DECREF(z);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2760 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2761 });
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2762
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2763 carry = *pz + f * f;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2764 *pz++ = (digit)(carry & PyLong_MASK);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2765 carry >>= PyLong_SHIFT;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2766 assert(carry <= PyLong_MASK);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2767
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2768 /* Now f is added in twice in each column of the
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2769 * pyramid it appears. Same as adding f<<1 once.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2770 */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2771 f <<= 1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2772 while (pa < paend) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2773 carry += *pz + *pa++ * f;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2774 *pz++ = (digit)(carry & PyLong_MASK);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2775 carry >>= PyLong_SHIFT;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2776 assert(carry <= (PyLong_MASK << 1));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2777 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2778 if (carry) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2779 carry += *pz;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2780 *pz++ = (digit)(carry & PyLong_MASK);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2781 carry >>= PyLong_SHIFT;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2782 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2783 if (carry)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2784 *pz += (digit)(carry & PyLong_MASK);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2785 assert((carry >> PyLong_SHIFT) == 0);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2786 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2787 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2788 else { /* a is not the same as b -- gradeschool long mult */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2789 for (i = 0; i < size_a; ++i) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2790 twodigits carry = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2791 twodigits f = a->ob_digit[i];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2792 digit *pz = z->ob_digit + i;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2793 digit *pb = b->ob_digit;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2794 digit *pbend = b->ob_digit + size_b;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2795
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2796 SIGCHECK({
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2797 Py_DECREF(z);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2798 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2799 });
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2800
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2801 while (pb < pbend) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2802 carry += *pz + *pb++ * f;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2803 *pz++ = (digit)(carry & PyLong_MASK);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2804 carry >>= PyLong_SHIFT;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2805 assert(carry <= PyLong_MASK);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2806 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2807 if (carry)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2808 *pz += (digit)(carry & PyLong_MASK);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2809 assert((carry >> PyLong_SHIFT) == 0);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2810 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2811 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2812 return long_normalize(z);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2813 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2814
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2815 /* A helper for Karatsuba multiplication (k_mul).
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2816 Takes a long "n" and an integer "size" representing the place to
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2817 split, and sets low and high such that abs(n) == (high << size) + low,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2818 viewing the shift as being by digits. The sign bit is ignored, and
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2819 the return values are >= 0.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2820 Returns 0 on success, -1 on failure.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2821 */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2822 static int
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2823 kmul_split(PyLongObject *n,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2824 Py_ssize_t size,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2825 PyLongObject **high,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2826 PyLongObject **low)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2827 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2828 PyLongObject *hi, *lo;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2829 Py_ssize_t size_lo, size_hi;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2830 const Py_ssize_t size_n = ABS(Py_SIZE(n));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2831
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2832 size_lo = MIN(size_n, size);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2833 size_hi = size_n - size_lo;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2834
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2835 if ((hi = _PyLong_New(size_hi)) == NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2836 return -1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2837 if ((lo = _PyLong_New(size_lo)) == NULL) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2838 Py_DECREF(hi);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2839 return -1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2840 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2841
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2842 memcpy(lo->ob_digit, n->ob_digit, size_lo * sizeof(digit));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2843 memcpy(hi->ob_digit, n->ob_digit + size_lo, size_hi * sizeof(digit));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2844
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2845 *high = long_normalize(hi);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2846 *low = long_normalize(lo);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2847 return 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2848 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2849
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2850 static PyLongObject *k_lopsided_mul(PyLongObject *a, PyLongObject *b);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2851
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2852 /* Karatsuba multiplication. Ignores the input signs, and returns the
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2853 * absolute value of the product (or NULL if error).
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2854 * See Knuth Vol. 2 Chapter 4.3.3 (Pp. 294-295).
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2855 */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2856 static PyLongObject *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2857 k_mul(PyLongObject *a, PyLongObject *b)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2858 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2859 Py_ssize_t asize = ABS(Py_SIZE(a));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2860 Py_ssize_t bsize = ABS(Py_SIZE(b));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2861 PyLongObject *ah = NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2862 PyLongObject *al = NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2863 PyLongObject *bh = NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2864 PyLongObject *bl = NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2865 PyLongObject *ret = NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2866 PyLongObject *t1, *t2, *t3;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2867 Py_ssize_t shift; /* the number of digits we split off */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2868 Py_ssize_t i;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2869
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2870 /* (ah*X+al)(bh*X+bl) = ah*bh*X*X + (ah*bl + al*bh)*X + al*bl
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2871 * Let k = (ah+al)*(bh+bl) = ah*bl + al*bh + ah*bh + al*bl
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2872 * Then the original product is
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2873 * ah*bh*X*X + (k - ah*bh - al*bl)*X + al*bl
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2874 * By picking X to be a power of 2, "*X" is just shifting, and it's
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2875 * been reduced to 3 multiplies on numbers half the size.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2876 */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2877
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2878 /* We want to split based on the larger number; fiddle so that b
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2879 * is largest.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2880 */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2881 if (asize > bsize) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2882 t1 = a;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2883 a = b;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2884 b = t1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2885
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2886 i = asize;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2887 asize = bsize;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2888 bsize = i;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2889 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2890
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2891 /* Use gradeschool math when either number is too small. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2892 i = a == b ? KARATSUBA_SQUARE_CUTOFF : KARATSUBA_CUTOFF;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2893 if (asize <= i) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2894 if (asize == 0)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2895 return (PyLongObject *)PyLong_FromLong(0);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2896 else
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2897 return x_mul(a, b);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2898 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2899
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2900 /* If a is small compared to b, splitting on b gives a degenerate
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2901 * case with ah==0, and Karatsuba may be (even much) less efficient
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2902 * than "grade school" then. However, we can still win, by viewing
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2903 * b as a string of "big digits", each of width a->ob_size. That
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2904 * leads to a sequence of balanced calls to k_mul.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2905 */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2906 if (2 * asize <= bsize)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2907 return k_lopsided_mul(a, b);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2908
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2909 /* Split a & b into hi & lo pieces. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2910 shift = bsize >> 1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2911 if (kmul_split(a, shift, &ah, &al) < 0) goto fail;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2912 assert(Py_SIZE(ah) > 0); /* the split isn't degenerate */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2913
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2914 if (a == b) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2915 bh = ah;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2916 bl = al;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2917 Py_INCREF(bh);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2918 Py_INCREF(bl);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2919 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2920 else if (kmul_split(b, shift, &bh, &bl) < 0) goto fail;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2921
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2922 /* The plan:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2923 * 1. Allocate result space (asize + bsize digits: that's always
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2924 * enough).
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2925 * 2. Compute ah*bh, and copy into result at 2*shift.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2926 * 3. Compute al*bl, and copy into result at 0. Note that this
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2927 * can't overlap with #2.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2928 * 4. Subtract al*bl from the result, starting at shift. This may
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2929 * underflow (borrow out of the high digit), but we don't care:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2930 * we're effectively doing unsigned arithmetic mod
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2931 * BASE**(sizea + sizeb), and so long as the *final* result fits,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2932 * borrows and carries out of the high digit can be ignored.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2933 * 5. Subtract ah*bh from the result, starting at shift.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2934 * 6. Compute (ah+al)*(bh+bl), and add it into the result starting
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2935 * at shift.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2936 */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2937
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2938 /* 1. Allocate result space. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2939 ret = _PyLong_New(asize + bsize);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2940 if (ret == NULL) goto fail;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2941 #ifdef Py_DEBUG
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2942 /* Fill with trash, to catch reference to uninitialized digits. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2943 memset(ret->ob_digit, 0xDF, Py_SIZE(ret) * sizeof(digit));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2944 #endif
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2945
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2946 /* 2. t1 <- ah*bh, and copy into high digits of result. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2947 if ((t1 = k_mul(ah, bh)) == NULL) goto fail;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2948 assert(Py_SIZE(t1) >= 0);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2949 assert(2*shift + Py_SIZE(t1) <= Py_SIZE(ret));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2950 memcpy(ret->ob_digit + 2*shift, t1->ob_digit,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2951 Py_SIZE(t1) * sizeof(digit));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2952
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2953 /* Zero-out the digits higher than the ah*bh copy. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2954 i = Py_SIZE(ret) - 2*shift - Py_SIZE(t1);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2955 if (i)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2956 memset(ret->ob_digit + 2*shift + Py_SIZE(t1), 0,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2957 i * sizeof(digit));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2958
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2959 /* 3. t2 <- al*bl, and copy into the low digits. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2960 if ((t2 = k_mul(al, bl)) == NULL) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2961 Py_DECREF(t1);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2962 goto fail;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2963 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2964 assert(Py_SIZE(t2) >= 0);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2965 assert(Py_SIZE(t2) <= 2*shift); /* no overlap with high digits */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2966 memcpy(ret->ob_digit, t2->ob_digit, Py_SIZE(t2) * sizeof(digit));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2967
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2968 /* Zero out remaining digits. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2969 i = 2*shift - Py_SIZE(t2); /* number of uninitialized digits */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2970 if (i)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2971 memset(ret->ob_digit + Py_SIZE(t2), 0, i * sizeof(digit));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2972
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2973 /* 4 & 5. Subtract ah*bh (t1) and al*bl (t2). We do al*bl first
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2974 * because it's fresher in cache.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2975 */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2976 i = Py_SIZE(ret) - shift; /* # digits after shift */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2977 (void)v_isub(ret->ob_digit + shift, i, t2->ob_digit, Py_SIZE(t2));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2978 Py_DECREF(t2);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2979
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2980 (void)v_isub(ret->ob_digit + shift, i, t1->ob_digit, Py_SIZE(t1));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2981 Py_DECREF(t1);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2982
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2983 /* 6. t3 <- (ah+al)(bh+bl), and add into result. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2984 if ((t1 = x_add(ah, al)) == NULL) goto fail;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2985 Py_DECREF(ah);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2986 Py_DECREF(al);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2987 ah = al = NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2988
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2989 if (a == b) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2990 t2 = t1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2991 Py_INCREF(t2);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2992 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2993 else if ((t2 = x_add(bh, bl)) == NULL) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2994 Py_DECREF(t1);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2995 goto fail;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2996 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2997 Py_DECREF(bh);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2998 Py_DECREF(bl);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
2999 bh = bl = NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3000
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3001 t3 = k_mul(t1, t2);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3002 Py_DECREF(t1);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3003 Py_DECREF(t2);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3004 if (t3 == NULL) goto fail;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3005 assert(Py_SIZE(t3) >= 0);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3006
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3007 /* Add t3. It's not obvious why we can't run out of room here.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3008 * See the (*) comment after this function.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3009 */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3010 (void)v_iadd(ret->ob_digit + shift, i, t3->ob_digit, Py_SIZE(t3));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3011 Py_DECREF(t3);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3012
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3013 return long_normalize(ret);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3014
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3015 fail:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3016 Py_XDECREF(ret);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3017 Py_XDECREF(ah);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3018 Py_XDECREF(al);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3019 Py_XDECREF(bh);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3020 Py_XDECREF(bl);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3021 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3022 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3023
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3024 /* (*) Why adding t3 can't "run out of room" above.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3025
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3026 Let f(x) mean the floor of x and c(x) mean the ceiling of x. Some facts
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3027 to start with:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3028
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3029 1. For any integer i, i = c(i/2) + f(i/2). In particular,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3030 bsize = c(bsize/2) + f(bsize/2).
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3031 2. shift = f(bsize/2)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3032 3. asize <= bsize
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3033 4. Since we call k_lopsided_mul if asize*2 <= bsize, asize*2 > bsize in this
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3034 routine, so asize > bsize/2 >= f(bsize/2) in this routine.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3035
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3036 We allocated asize + bsize result digits, and add t3 into them at an offset
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3037 of shift. This leaves asize+bsize-shift allocated digit positions for t3
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3038 to fit into, = (by #1 and #2) asize + f(bsize/2) + c(bsize/2) - f(bsize/2) =
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3039 asize + c(bsize/2) available digit positions.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3040
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3041 bh has c(bsize/2) digits, and bl at most f(size/2) digits. So bh+hl has
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3042 at most c(bsize/2) digits + 1 bit.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3043
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3044 If asize == bsize, ah has c(bsize/2) digits, else ah has at most f(bsize/2)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3045 digits, and al has at most f(bsize/2) digits in any case. So ah+al has at
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3046 most (asize == bsize ? c(bsize/2) : f(bsize/2)) digits + 1 bit.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3047
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3048 The product (ah+al)*(bh+bl) therefore has at most
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3049
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3050 c(bsize/2) + (asize == bsize ? c(bsize/2) : f(bsize/2)) digits + 2 bits
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3051
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3052 and we have asize + c(bsize/2) available digit positions. We need to show
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3053 this is always enough. An instance of c(bsize/2) cancels out in both, so
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3054 the question reduces to whether asize digits is enough to hold
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3055 (asize == bsize ? c(bsize/2) : f(bsize/2)) digits + 2 bits. If asize < bsize,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3056 then we're asking whether asize digits >= f(bsize/2) digits + 2 bits. By #4,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3057 asize is at least f(bsize/2)+1 digits, so this in turn reduces to whether 1
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3058 digit is enough to hold 2 bits. This is so since PyLong_SHIFT=15 >= 2. If
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3059 asize == bsize, then we're asking whether bsize digits is enough to hold
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3060 c(bsize/2) digits + 2 bits, or equivalently (by #1) whether f(bsize/2) digits
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3061 is enough to hold 2 bits. This is so if bsize >= 2, which holds because
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3062 bsize >= KARATSUBA_CUTOFF >= 2.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3063
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3064 Note that since there's always enough room for (ah+al)*(bh+bl), and that's
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3065 clearly >= each of ah*bh and al*bl, there's always enough room to subtract
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3066 ah*bh and al*bl too.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3067 */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3068
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3069 /* b has at least twice the digits of a, and a is big enough that Karatsuba
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3070 * would pay off *if* the inputs had balanced sizes. View b as a sequence
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3071 * of slices, each with a->ob_size digits, and multiply the slices by a,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3072 * one at a time. This gives k_mul balanced inputs to work with, and is
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3073 * also cache-friendly (we compute one double-width slice of the result
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3074 * at a time, then move on, never backtracking except for the helpful
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3075 * single-width slice overlap between successive partial sums).
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3076 */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3077 static PyLongObject *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3078 k_lopsided_mul(PyLongObject *a, PyLongObject *b)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3079 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3080 const Py_ssize_t asize = ABS(Py_SIZE(a));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3081 Py_ssize_t bsize = ABS(Py_SIZE(b));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3082 Py_ssize_t nbdone; /* # of b digits already multiplied */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3083 PyLongObject *ret;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3084 PyLongObject *bslice = NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3085
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3086 assert(asize > KARATSUBA_CUTOFF);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3087 assert(2 * asize <= bsize);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3088
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3089 /* Allocate result space, and zero it out. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3090 ret = _PyLong_New(asize + bsize);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3091 if (ret == NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3092 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3093 memset(ret->ob_digit, 0, Py_SIZE(ret) * sizeof(digit));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3094
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3095 /* Successive slices of b are copied into bslice. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3096 bslice = _PyLong_New(asize);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3097 if (bslice == NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3098 goto fail;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3099
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3100 nbdone = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3101 while (bsize > 0) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3102 PyLongObject *product;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3103 const Py_ssize_t nbtouse = MIN(bsize, asize);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3104
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3105 /* Multiply the next slice of b by a. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3106 memcpy(bslice->ob_digit, b->ob_digit + nbdone,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3107 nbtouse * sizeof(digit));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3108 Py_SIZE(bslice) = nbtouse;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3109 product = k_mul(a, bslice);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3110 if (product == NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3111 goto fail;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3112
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3113 /* Add into result. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3114 (void)v_iadd(ret->ob_digit + nbdone, Py_SIZE(ret) - nbdone,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3115 product->ob_digit, Py_SIZE(product));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3116 Py_DECREF(product);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3117
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3118 bsize -= nbtouse;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3119 nbdone += nbtouse;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3120 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3121
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3122 Py_DECREF(bslice);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3123 return long_normalize(ret);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3124
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3125 fail:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3126 Py_DECREF(ret);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3127 Py_XDECREF(bslice);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3128 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3129 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3130
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3131 static PyObject *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3132 long_mul(PyLongObject *a, PyLongObject *b)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3133 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3134 PyLongObject *z;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3135
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3136 CHECK_BINOP(a, b);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3137
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3138 /* fast path for single-digit multiplication */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3139 if (ABS(Py_SIZE(a)) <= 1 && ABS(Py_SIZE(b)) <= 1) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3140 stwodigits v = (stwodigits)(MEDIUM_VALUE(a)) * MEDIUM_VALUE(b);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3141 #ifdef HAVE_LONG_LONG
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3142 return PyLong_FromLongLong((PY_LONG_LONG)v);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3143 #else
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3144 /* if we don't have long long then we're almost certainly
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3145 using 15-bit digits, so v will fit in a long. In the
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3146 unlikely event that we're using 30-bit digits on a platform
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3147 without long long, a large v will just cause us to fall
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3148 through to the general multiplication code below. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3149 if (v >= LONG_MIN && v <= LONG_MAX)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3150 return PyLong_FromLong((long)v);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3151 #endif
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3152 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3153
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3154 z = k_mul(a, b);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3155 /* Negate if exactly one of the inputs is negative. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3156 if (((Py_SIZE(a) ^ Py_SIZE(b)) < 0) && z)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3157 NEGATE(z);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3158 return (PyObject *)z;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3159 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3160
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3161 /* The / and % operators are now defined in terms of divmod().
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3162 The expression a mod b has the value a - b*floor(a/b).
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3163 The long_divrem function gives the remainder after division of
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3164 |a| by |b|, with the sign of a. This is also expressed
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3165 as a - b*trunc(a/b), if trunc truncates towards zero.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3166 Some examples:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3167 a b a rem b a mod b
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3168 13 10 3 3
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3169 -13 10 -3 7
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3170 13 -10 3 -7
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3171 -13 -10 -3 -3
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3172 So, to get from rem to mod, we have to add b if a and b
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3173 have different signs. We then subtract one from the 'div'
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3174 part of the outcome to keep the invariant intact. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3175
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3176 /* Compute
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3177 * *pdiv, *pmod = divmod(v, w)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3178 * NULL can be passed for pdiv or pmod, in which case that part of
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3179 * the result is simply thrown away. The caller owns a reference to
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3180 * each of these it requests (does not pass NULL for).
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3181 */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3182 static int
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3183 l_divmod(PyLongObject *v, PyLongObject *w,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3184 PyLongObject **pdiv, PyLongObject **pmod)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3185 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3186 PyLongObject *div, *mod;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3187
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3188 if (long_divrem(v, w, &div, &mod) < 0)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3189 return -1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3190 if ((Py_SIZE(mod) < 0 && Py_SIZE(w) > 0) ||
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3191 (Py_SIZE(mod) > 0 && Py_SIZE(w) < 0)) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3192 PyLongObject *temp;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3193 PyLongObject *one;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3194 temp = (PyLongObject *) long_add(mod, w);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3195 Py_DECREF(mod);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3196 mod = temp;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3197 if (mod == NULL) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3198 Py_DECREF(div);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3199 return -1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3200 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3201 one = (PyLongObject *) PyLong_FromLong(1L);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3202 if (one == NULL ||
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3203 (temp = (PyLongObject *) long_sub(div, one)) == NULL) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3204 Py_DECREF(mod);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3205 Py_DECREF(div);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3206 Py_XDECREF(one);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3207 return -1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3208 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3209 Py_DECREF(one);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3210 Py_DECREF(div);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3211 div = temp;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3212 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3213 if (pdiv != NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3214 *pdiv = div;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3215 else
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3216 Py_DECREF(div);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3217
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3218 if (pmod != NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3219 *pmod = mod;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3220 else
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3221 Py_DECREF(mod);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3222
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3223 return 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3224 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3225
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3226 static PyObject *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3227 long_div(PyObject *a, PyObject *b)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3228 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3229 PyLongObject *div;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3230
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3231 CHECK_BINOP(a, b);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3232 if (l_divmod((PyLongObject*)a, (PyLongObject*)b, &div, NULL) < 0)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3233 div = NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3234 return (PyObject *)div;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3235 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3236
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3237 /* PyLong/PyLong -> float, with correctly rounded result. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3238
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3239 #define MANT_DIG_DIGITS (DBL_MANT_DIG / PyLong_SHIFT)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3240 #define MANT_DIG_BITS (DBL_MANT_DIG % PyLong_SHIFT)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3241
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3242 static PyObject *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3243 long_true_divide(PyObject *v, PyObject *w)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3244 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3245 PyLongObject *a, *b, *x;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3246 Py_ssize_t a_size, b_size, shift, extra_bits, diff, x_size, x_bits;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3247 digit mask, low;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3248 int inexact, negate, a_is_small, b_is_small;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3249 double dx, result;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3250
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3251 CHECK_BINOP(v, w);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3252 a = (PyLongObject *)v;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3253 b = (PyLongObject *)w;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3254
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3255 /*
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3256 Method in a nutshell:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3257
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3258 0. reduce to case a, b > 0; filter out obvious underflow/overflow
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3259 1. choose a suitable integer 'shift'
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3260 2. use integer arithmetic to compute x = floor(2**-shift*a/b)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3261 3. adjust x for correct rounding
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3262 4. convert x to a double dx with the same value
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3263 5. return ldexp(dx, shift).
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3264
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3265 In more detail:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3266
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3267 0. For any a, a/0 raises ZeroDivisionError; for nonzero b, 0/b
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3268 returns either 0.0 or -0.0, depending on the sign of b. For a and
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3269 b both nonzero, ignore signs of a and b, and add the sign back in
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3270 at the end. Now write a_bits and b_bits for the bit lengths of a
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3271 and b respectively (that is, a_bits = 1 + floor(log_2(a)); likewise
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3272 for b). Then
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3273
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3274 2**(a_bits - b_bits - 1) < a/b < 2**(a_bits - b_bits + 1).
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3275
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3276 So if a_bits - b_bits > DBL_MAX_EXP then a/b > 2**DBL_MAX_EXP and
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3277 so overflows. Similarly, if a_bits - b_bits < DBL_MIN_EXP -
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3278 DBL_MANT_DIG - 1 then a/b underflows to 0. With these cases out of
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3279 the way, we can assume that
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3280
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3281 DBL_MIN_EXP - DBL_MANT_DIG - 1 <= a_bits - b_bits <= DBL_MAX_EXP.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3282
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3283 1. The integer 'shift' is chosen so that x has the right number of
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3284 bits for a double, plus two or three extra bits that will be used
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3285 in the rounding decisions. Writing a_bits and b_bits for the
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3286 number of significant bits in a and b respectively, a
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3287 straightforward formula for shift is:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3288
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3289 shift = a_bits - b_bits - DBL_MANT_DIG - 2
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3290
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3291 This is fine in the usual case, but if a/b is smaller than the
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3292 smallest normal float then it can lead to double rounding on an
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3293 IEEE 754 platform, giving incorrectly rounded results. So we
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3294 adjust the formula slightly. The actual formula used is:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3295
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3296 shift = MAX(a_bits - b_bits, DBL_MIN_EXP) - DBL_MANT_DIG - 2
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3297
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3298 2. The quantity x is computed by first shifting a (left -shift bits
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3299 if shift <= 0, right shift bits if shift > 0) and then dividing by
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3300 b. For both the shift and the division, we keep track of whether
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3301 the result is inexact, in a flag 'inexact'; this information is
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3302 needed at the rounding stage.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3303
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3304 With the choice of shift above, together with our assumption that
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3305 a_bits - b_bits >= DBL_MIN_EXP - DBL_MANT_DIG - 1, it follows
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3306 that x >= 1.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3307
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3308 3. Now x * 2**shift <= a/b < (x+1) * 2**shift. We want to replace
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3309 this with an exactly representable float of the form
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3310
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3311 round(x/2**extra_bits) * 2**(extra_bits+shift).
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3312
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3313 For float representability, we need x/2**extra_bits <
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3314 2**DBL_MANT_DIG and extra_bits + shift >= DBL_MIN_EXP -
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3315 DBL_MANT_DIG. This translates to the condition:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3316
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3317 extra_bits >= MAX(x_bits, DBL_MIN_EXP - shift) - DBL_MANT_DIG
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3318
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3319 To round, we just modify the bottom digit of x in-place; this can
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3320 end up giving a digit with value > PyLONG_MASK, but that's not a
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3321 problem since digits can hold values up to 2*PyLONG_MASK+1.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3322
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3323 With the original choices for shift above, extra_bits will always
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3324 be 2 or 3. Then rounding under the round-half-to-even rule, we
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3325 round up iff the most significant of the extra bits is 1, and
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3326 either: (a) the computation of x in step 2 had an inexact result,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3327 or (b) at least one other of the extra bits is 1, or (c) the least
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3328 significant bit of x (above those to be rounded) is 1.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3329
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3330 4. Conversion to a double is straightforward; all floating-point
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3331 operations involved in the conversion are exact, so there's no
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3332 danger of rounding errors.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3333
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3334 5. Use ldexp(x, shift) to compute x*2**shift, the final result.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3335 The result will always be exactly representable as a double, except
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3336 in the case that it overflows. To avoid dependence on the exact
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3337 behaviour of ldexp on overflow, we check for overflow before
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3338 applying ldexp. The result of ldexp is adjusted for sign before
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3339 returning.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3340 */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3341
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3342 /* Reduce to case where a and b are both positive. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3343 a_size = ABS(Py_SIZE(a));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3344 b_size = ABS(Py_SIZE(b));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3345 negate = (Py_SIZE(a) < 0) ^ (Py_SIZE(b) < 0);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3346 if (b_size == 0) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3347 PyErr_SetString(PyExc_ZeroDivisionError,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3348 "division by zero");
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3349 goto error;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3350 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3351 if (a_size == 0)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3352 goto underflow_or_zero;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3353
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3354 /* Fast path for a and b small (exactly representable in a double).
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3355 Relies on floating-point division being correctly rounded; results
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3356 may be subject to double rounding on x86 machines that operate with
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3357 the x87 FPU set to 64-bit precision. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3358 a_is_small = a_size <= MANT_DIG_DIGITS ||
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3359 (a_size == MANT_DIG_DIGITS+1 &&
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3360 a->ob_digit[MANT_DIG_DIGITS] >> MANT_DIG_BITS == 0);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3361 b_is_small = b_size <= MANT_DIG_DIGITS ||
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3362 (b_size == MANT_DIG_DIGITS+1 &&
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3363 b->ob_digit[MANT_DIG_DIGITS] >> MANT_DIG_BITS == 0);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3364 if (a_is_small && b_is_small) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3365 double da, db;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3366 da = a->ob_digit[--a_size];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3367 while (a_size > 0)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3368 da = da * PyLong_BASE + a->ob_digit[--a_size];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3369 db = b->ob_digit[--b_size];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3370 while (b_size > 0)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3371 db = db * PyLong_BASE + b->ob_digit[--b_size];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3372 result = da / db;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3373 goto success;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3374 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3375
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3376 /* Catch obvious cases of underflow and overflow */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3377 diff = a_size - b_size;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3378 if (diff > PY_SSIZE_T_MAX/PyLong_SHIFT - 1)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3379 /* Extreme overflow */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3380 goto overflow;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3381 else if (diff < 1 - PY_SSIZE_T_MAX/PyLong_SHIFT)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3382 /* Extreme underflow */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3383 goto underflow_or_zero;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3384 /* Next line is now safe from overflowing a Py_ssize_t */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3385 diff = diff * PyLong_SHIFT + bits_in_digit(a->ob_digit[a_size - 1]) -
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3386 bits_in_digit(b->ob_digit[b_size - 1]);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3387 /* Now diff = a_bits - b_bits. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3388 if (diff > DBL_MAX_EXP)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3389 goto overflow;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3390 else if (diff < DBL_MIN_EXP - DBL_MANT_DIG - 1)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3391 goto underflow_or_zero;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3392
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3393 /* Choose value for shift; see comments for step 1 above. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3394 shift = MAX(diff, DBL_MIN_EXP) - DBL_MANT_DIG - 2;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3395
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3396 inexact = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3397
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3398 /* x = abs(a * 2**-shift) */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3399 if (shift <= 0) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3400 Py_ssize_t i, shift_digits = -shift / PyLong_SHIFT;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3401 digit rem;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3402 /* x = a << -shift */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3403 if (a_size >= PY_SSIZE_T_MAX - 1 - shift_digits) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3404 /* In practice, it's probably impossible to end up
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3405 here. Both a and b would have to be enormous,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3406 using close to SIZE_T_MAX bytes of memory each. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3407 PyErr_SetString(PyExc_OverflowError,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3408 "intermediate overflow during division");
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3409 goto error;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3410 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3411 x = _PyLong_New(a_size + shift_digits + 1);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3412 if (x == NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3413 goto error;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3414 for (i = 0; i < shift_digits; i++)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3415 x->ob_digit[i] = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3416 rem = v_lshift(x->ob_digit + shift_digits, a->ob_digit,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3417 a_size, -shift % PyLong_SHIFT);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3418 x->ob_digit[a_size + shift_digits] = rem;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3419 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3420 else {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3421 Py_ssize_t shift_digits = shift / PyLong_SHIFT;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3422 digit rem;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3423 /* x = a >> shift */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3424 assert(a_size >= shift_digits);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3425 x = _PyLong_New(a_size - shift_digits);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3426 if (x == NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3427 goto error;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3428 rem = v_rshift(x->ob_digit, a->ob_digit + shift_digits,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3429 a_size - shift_digits, shift % PyLong_SHIFT);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3430 /* set inexact if any of the bits shifted out is nonzero */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3431 if (rem)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3432 inexact = 1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3433 while (!inexact && shift_digits > 0)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3434 if (a->ob_digit[--shift_digits])
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3435 inexact = 1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3436 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3437 long_normalize(x);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3438 x_size = Py_SIZE(x);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3439
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3440 /* x //= b. If the remainder is nonzero, set inexact. We own the only
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3441 reference to x, so it's safe to modify it in-place. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3442 if (b_size == 1) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3443 digit rem = inplace_divrem1(x->ob_digit, x->ob_digit, x_size,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3444 b->ob_digit[0]);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3445 long_normalize(x);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3446 if (rem)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3447 inexact = 1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3448 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3449 else {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3450 PyLongObject *div, *rem;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3451 div = x_divrem(x, b, &rem);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3452 Py_DECREF(x);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3453 x = div;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3454 if (x == NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3455 goto error;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3456 if (Py_SIZE(rem))
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3457 inexact = 1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3458 Py_DECREF(rem);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3459 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3460 x_size = ABS(Py_SIZE(x));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3461 assert(x_size > 0); /* result of division is never zero */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3462 x_bits = (x_size-1)*PyLong_SHIFT+bits_in_digit(x->ob_digit[x_size-1]);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3463
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3464 /* The number of extra bits that have to be rounded away. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3465 extra_bits = MAX(x_bits, DBL_MIN_EXP - shift) - DBL_MANT_DIG;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3466 assert(extra_bits == 2 || extra_bits == 3);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3467
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3468 /* Round by directly modifying the low digit of x. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3469 mask = (digit)1 << (extra_bits - 1);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3470 low = x->ob_digit[0] | inexact;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3471 if (low & mask && low & (3*mask-1))
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3472 low += mask;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3473 x->ob_digit[0] = low & ~(mask-1U);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3474
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3475 /* Convert x to a double dx; the conversion is exact. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3476 dx = x->ob_digit[--x_size];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3477 while (x_size > 0)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3478 dx = dx * PyLong_BASE + x->ob_digit[--x_size];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3479 Py_DECREF(x);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3480
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3481 /* Check whether ldexp result will overflow a double. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3482 if (shift + x_bits >= DBL_MAX_EXP &&
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3483 (shift + x_bits > DBL_MAX_EXP || dx == ldexp(1.0, (int)x_bits)))
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3484 goto overflow;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3485 result = ldexp(dx, (int)shift);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3486
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3487 success:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3488 return PyFloat_FromDouble(negate ? -result : result);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3489
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3490 underflow_or_zero:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3491 return PyFloat_FromDouble(negate ? -0.0 : 0.0);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3492
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3493 overflow:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3494 PyErr_SetString(PyExc_OverflowError,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3495 "integer division result too large for a float");
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3496 error:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3497 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3498 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3499
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3500 static PyObject *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3501 long_mod(PyObject *a, PyObject *b)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3502 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3503 PyLongObject *mod;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3504
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3505 CHECK_BINOP(a, b);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3506
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3507 if (l_divmod((PyLongObject*)a, (PyLongObject*)b, NULL, &mod) < 0)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3508 mod = NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3509 return (PyObject *)mod;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3510 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3511
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3512 static PyObject *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3513 long_divmod(PyObject *a, PyObject *b)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3514 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3515 PyLongObject *div, *mod;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3516 PyObject *z;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3517
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3518 CHECK_BINOP(a, b);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3519
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3520 if (l_divmod((PyLongObject*)a, (PyLongObject*)b, &div, &mod) < 0) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3521 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3522 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3523 z = PyTuple_New(2);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3524 if (z != NULL) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3525 PyTuple_SetItem(z, 0, (PyObject *) div);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3526 PyTuple_SetItem(z, 1, (PyObject *) mod);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3527 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3528 else {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3529 Py_DECREF(div);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3530 Py_DECREF(mod);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3531 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3532 return z;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3533 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3534
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3535 /* pow(v, w, x) */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3536 static PyObject *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3537 long_pow(PyObject *v, PyObject *w, PyObject *x)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3538 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3539 PyLongObject *a, *b, *c; /* a,b,c = v,w,x */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3540 int negativeOutput = 0; /* if x<0 return negative output */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3541
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3542 PyLongObject *z = NULL; /* accumulated result */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3543 Py_ssize_t i, j, k; /* counters */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3544 PyLongObject *temp = NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3545
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3546 /* 5-ary values. If the exponent is large enough, table is
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3547 * precomputed so that table[i] == a**i % c for i in range(32).
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3548 */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3549 PyLongObject *table[32] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3550 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3551
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3552 /* a, b, c = v, w, x */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3553 CHECK_BINOP(v, w);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3554 a = (PyLongObject*)v; Py_INCREF(a);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3555 b = (PyLongObject*)w; Py_INCREF(b);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3556 if (PyLong_Check(x)) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3557 c = (PyLongObject *)x;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3558 Py_INCREF(x);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3559 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3560 else if (x == Py_None)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3561 c = NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3562 else {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3563 Py_DECREF(a);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3564 Py_DECREF(b);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3565 Py_RETURN_NOTIMPLEMENTED;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3566 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3567
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3568 if (Py_SIZE(b) < 0) { /* if exponent is negative */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3569 if (c) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3570 PyErr_SetString(PyExc_TypeError, "pow() 2nd argument "
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3571 "cannot be negative when 3rd argument specified");
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3572 goto Error;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3573 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3574 else {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3575 /* else return a float. This works because we know
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3576 that this calls float_pow() which converts its
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3577 arguments to double. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3578 Py_DECREF(a);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3579 Py_DECREF(b);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3580 return PyFloat_Type.tp_as_number->nb_power(v, w, x);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3581 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3582 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3583
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3584 if (c) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3585 /* if modulus == 0:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3586 raise ValueError() */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3587 if (Py_SIZE(c) == 0) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3588 PyErr_SetString(PyExc_ValueError,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3589 "pow() 3rd argument cannot be 0");
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3590 goto Error;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3591 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3592
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3593 /* if modulus < 0:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3594 negativeOutput = True
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3595 modulus = -modulus */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3596 if (Py_SIZE(c) < 0) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3597 negativeOutput = 1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3598 temp = (PyLongObject *)_PyLong_Copy(c);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3599 if (temp == NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3600 goto Error;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3601 Py_DECREF(c);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3602 c = temp;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3603 temp = NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3604 NEGATE(c);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3605 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3606
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3607 /* if modulus == 1:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3608 return 0 */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3609 if ((Py_SIZE(c) == 1) && (c->ob_digit[0] == 1)) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3610 z = (PyLongObject *)PyLong_FromLong(0L);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3611 goto Done;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3612 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3613
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3614 /* if base < 0:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3615 base = base % modulus
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3616 Having the base positive just makes things easier. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3617 if (Py_SIZE(a) < 0) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3618 if (l_divmod(a, c, NULL, &temp) < 0)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3619 goto Error;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3620 Py_DECREF(a);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3621 a = temp;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3622 temp = NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3623 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3624 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3625
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3626 /* At this point a, b, and c are guaranteed non-negative UNLESS
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3627 c is NULL, in which case a may be negative. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3628
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3629 z = (PyLongObject *)PyLong_FromLong(1L);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3630 if (z == NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3631 goto Error;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3632
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3633 /* Perform a modular reduction, X = X % c, but leave X alone if c
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3634 * is NULL.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3635 */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3636 #define REDUCE(X) \
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3637 do { \
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3638 if (c != NULL) { \
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3639 if (l_divmod(X, c, NULL, &temp) < 0) \
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3640 goto Error; \
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3641 Py_XDECREF(X); \
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3642 X = temp; \
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3643 temp = NULL; \
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3644 } \
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3645 } while(0)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3646
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3647 /* Multiply two values, then reduce the result:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3648 result = X*Y % c. If c is NULL, skip the mod. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3649 #define MULT(X, Y, result) \
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3650 do { \
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3651 temp = (PyLongObject *)long_mul(X, Y); \
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3652 if (temp == NULL) \
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3653 goto Error; \
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3654 Py_XDECREF(result); \
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3655 result = temp; \
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3656 temp = NULL; \
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3657 REDUCE(result); \
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3658 } while(0)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3659
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3660 if (Py_SIZE(b) <= FIVEARY_CUTOFF) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3661 /* Left-to-right binary exponentiation (HAC Algorithm 14.79) */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3662 /* http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3663 for (i = Py_SIZE(b) - 1; i >= 0; --i) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3664 digit bi = b->ob_digit[i];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3665
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3666 for (j = (digit)1 << (PyLong_SHIFT-1); j != 0; j >>= 1) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3667 MULT(z, z, z);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3668 if (bi & j)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3669 MULT(z, a, z);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3670 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3671 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3672 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3673 else {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3674 /* Left-to-right 5-ary exponentiation (HAC Algorithm 14.82) */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3675 Py_INCREF(z); /* still holds 1L */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3676 table[0] = z;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3677 for (i = 1; i < 32; ++i)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3678 MULT(table[i-1], a, table[i]);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3679
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3680 for (i = Py_SIZE(b) - 1; i >= 0; --i) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3681 const digit bi = b->ob_digit[i];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3682
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3683 for (j = PyLong_SHIFT - 5; j >= 0; j -= 5) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3684 const int index = (bi >> j) & 0x1f;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3685 for (k = 0; k < 5; ++k)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3686 MULT(z, z, z);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3687 if (index)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3688 MULT(z, table[index], z);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3689 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3690 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3691 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3692
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3693 if (negativeOutput && (Py_SIZE(z) != 0)) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3694 temp = (PyLongObject *)long_sub(z, c);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3695 if (temp == NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3696 goto Error;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3697 Py_DECREF(z);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3698 z = temp;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3699 temp = NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3700 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3701 goto Done;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3702
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3703 Error:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3704 if (z != NULL) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3705 Py_DECREF(z);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3706 z = NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3707 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3708 /* fall through */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3709 Done:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3710 if (Py_SIZE(b) > FIVEARY_CUTOFF) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3711 for (i = 0; i < 32; ++i)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3712 Py_XDECREF(table[i]);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3713 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3714 Py_DECREF(a);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3715 Py_DECREF(b);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3716 Py_XDECREF(c);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3717 Py_XDECREF(temp);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3718 return (PyObject *)z;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3719 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3720
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3721 static PyObject *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3722 long_invert(PyLongObject *v)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3723 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3724 /* Implement ~x as -(x+1) */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3725 PyLongObject *x;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3726 PyLongObject *w;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3727 if (ABS(Py_SIZE(v)) <=1)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3728 return PyLong_FromLong(-(MEDIUM_VALUE(v)+1));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3729 w = (PyLongObject *)PyLong_FromLong(1L);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3730 if (w == NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3731 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3732 x = (PyLongObject *) long_add(v, w);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3733 Py_DECREF(w);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3734 if (x == NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3735 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3736 Py_SIZE(x) = -(Py_SIZE(x));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3737 return (PyObject *)maybe_small_long(x);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3738 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3739
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3740 static PyObject *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3741 long_neg(PyLongObject *v)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3742 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3743 PyLongObject *z;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3744 if (ABS(Py_SIZE(v)) <= 1)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3745 return PyLong_FromLong(-MEDIUM_VALUE(v));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3746 z = (PyLongObject *)_PyLong_Copy(v);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3747 if (z != NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3748 Py_SIZE(z) = -(Py_SIZE(v));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3749 return (PyObject *)z;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3750 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3751
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3752 static PyObject *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3753 long_abs(PyLongObject *v)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3754 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3755 if (Py_SIZE(v) < 0)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3756 return long_neg(v);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3757 else
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3758 return long_long((PyObject *)v);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3759 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3760
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3761 static int
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3762 long_bool(PyLongObject *v)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3763 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3764 return Py_SIZE(v) != 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3765 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3766
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3767 static PyObject *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3768 long_rshift(PyLongObject *a, PyLongObject *b)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3769 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3770 PyLongObject *z = NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3771 Py_ssize_t shiftby, newsize, wordshift, loshift, hishift, i, j;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3772 digit lomask, himask;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3773
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3774 CHECK_BINOP(a, b);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3775
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3776 if (Py_SIZE(a) < 0) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3777 /* Right shifting negative numbers is harder */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3778 PyLongObject *a1, *a2;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3779 a1 = (PyLongObject *) long_invert(a);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3780 if (a1 == NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3781 goto rshift_error;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3782 a2 = (PyLongObject *) long_rshift(a1, b);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3783 Py_DECREF(a1);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3784 if (a2 == NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3785 goto rshift_error;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3786 z = (PyLongObject *) long_invert(a2);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3787 Py_DECREF(a2);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3788 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3789 else {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3790 shiftby = PyLong_AsSsize_t((PyObject *)b);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3791 if (shiftby == -1L && PyErr_Occurred())
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3792 goto rshift_error;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3793 if (shiftby < 0) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3794 PyErr_SetString(PyExc_ValueError,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3795 "negative shift count");
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3796 goto rshift_error;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3797 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3798 wordshift = shiftby / PyLong_SHIFT;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3799 newsize = ABS(Py_SIZE(a)) - wordshift;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3800 if (newsize <= 0)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3801 return PyLong_FromLong(0);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3802 loshift = shiftby % PyLong_SHIFT;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3803 hishift = PyLong_SHIFT - loshift;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3804 lomask = ((digit)1 << hishift) - 1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3805 himask = PyLong_MASK ^ lomask;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3806 z = _PyLong_New(newsize);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3807 if (z == NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3808 goto rshift_error;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3809 if (Py_SIZE(a) < 0)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3810 Py_SIZE(z) = -(Py_SIZE(z));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3811 for (i = 0, j = wordshift; i < newsize; i++, j++) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3812 z->ob_digit[i] = (a->ob_digit[j] >> loshift) & lomask;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3813 if (i+1 < newsize)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3814 z->ob_digit[i] |= (a->ob_digit[j+1] << hishift) & himask;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3815 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3816 z = long_normalize(z);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3817 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3818 rshift_error:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3819 return (PyObject *) maybe_small_long(z);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3820
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3821 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3822
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3823 static PyObject *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3824 long_lshift(PyObject *v, PyObject *w)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3825 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3826 /* This version due to Tim Peters */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3827 PyLongObject *a = (PyLongObject*)v;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3828 PyLongObject *b = (PyLongObject*)w;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3829 PyLongObject *z = NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3830 Py_ssize_t shiftby, oldsize, newsize, wordshift, remshift, i, j;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3831 twodigits accum;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3832
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3833 CHECK_BINOP(a, b);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3834
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3835 shiftby = PyLong_AsSsize_t((PyObject *)b);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3836 if (shiftby == -1L && PyErr_Occurred())
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3837 goto lshift_error;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3838 if (shiftby < 0) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3839 PyErr_SetString(PyExc_ValueError, "negative shift count");
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3840 goto lshift_error;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3841 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3842 /* wordshift, remshift = divmod(shiftby, PyLong_SHIFT) */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3843 wordshift = shiftby / PyLong_SHIFT;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3844 remshift = shiftby - wordshift * PyLong_SHIFT;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3845
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3846 oldsize = ABS(Py_SIZE(a));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3847 newsize = oldsize + wordshift;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3848 if (remshift)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3849 ++newsize;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3850 z = _PyLong_New(newsize);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3851 if (z == NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3852 goto lshift_error;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3853 if (Py_SIZE(a) < 0)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3854 NEGATE(z);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3855 for (i = 0; i < wordshift; i++)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3856 z->ob_digit[i] = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3857 accum = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3858 for (i = wordshift, j = 0; j < oldsize; i++, j++) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3859 accum |= (twodigits)a->ob_digit[j] << remshift;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3860 z->ob_digit[i] = (digit)(accum & PyLong_MASK);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3861 accum >>= PyLong_SHIFT;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3862 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3863 if (remshift)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3864 z->ob_digit[newsize-1] = (digit)accum;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3865 else
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3866 assert(!accum);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3867 z = long_normalize(z);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3868 lshift_error:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3869 return (PyObject *) maybe_small_long(z);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3870 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3871
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3872 /* Compute two's complement of digit vector a[0:m], writing result to
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3873 z[0:m]. The digit vector a need not be normalized, but should not
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3874 be entirely zero. a and z may point to the same digit vector. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3875
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3876 static void
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3877 v_complement(digit *z, digit *a, Py_ssize_t m)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3878 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3879 Py_ssize_t i;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3880 digit carry = 1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3881 for (i = 0; i < m; ++i) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3882 carry += a[i] ^ PyLong_MASK;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3883 z[i] = carry & PyLong_MASK;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3884 carry >>= PyLong_SHIFT;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3885 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3886 assert(carry == 0);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3887 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3888
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3889 /* Bitwise and/xor/or operations */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3890
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3891 static PyObject *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3892 long_bitwise(PyLongObject *a,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3893 int op, /* '&', '|', '^' */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3894 PyLongObject *b)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3895 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3896 int nega, negb, negz;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3897 Py_ssize_t size_a, size_b, size_z, i;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3898 PyLongObject *z;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3899
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3900 /* Bitwise operations for negative numbers operate as though
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3901 on a two's complement representation. So convert arguments
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3902 from sign-magnitude to two's complement, and convert the
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3903 result back to sign-magnitude at the end. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3904
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3905 /* If a is negative, replace it by its two's complement. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3906 size_a = ABS(Py_SIZE(a));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3907 nega = Py_SIZE(a) < 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3908 if (nega) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3909 z = _PyLong_New(size_a);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3910 if (z == NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3911 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3912 v_complement(z->ob_digit, a->ob_digit, size_a);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3913 a = z;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3914 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3915 else
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3916 /* Keep reference count consistent. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3917 Py_INCREF(a);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3918
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3919 /* Same for b. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3920 size_b = ABS(Py_SIZE(b));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3921 negb = Py_SIZE(b) < 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3922 if (negb) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3923 z = _PyLong_New(size_b);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3924 if (z == NULL) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3925 Py_DECREF(a);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3926 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3927 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3928 v_complement(z->ob_digit, b->ob_digit, size_b);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3929 b = z;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3930 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3931 else
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3932 Py_INCREF(b);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3933
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3934 /* Swap a and b if necessary to ensure size_a >= size_b. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3935 if (size_a < size_b) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3936 z = a; a = b; b = z;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3937 size_z = size_a; size_a = size_b; size_b = size_z;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3938 negz = nega; nega = negb; negb = negz;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3939 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3940
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3941 /* JRH: The original logic here was to allocate the result value (z)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3942 as the longer of the two operands. However, there are some cases
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3943 where the result is guaranteed to be shorter than that: AND of two
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3944 positives, OR of two negatives: use the shorter number. AND with
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3945 mixed signs: use the positive number. OR with mixed signs: use the
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3946 negative number.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3947 */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3948 switch (op) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3949 case '^':
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3950 negz = nega ^ negb;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3951 size_z = size_a;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3952 break;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3953 case '&':
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3954 negz = nega & negb;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3955 size_z = negb ? size_a : size_b;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3956 break;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3957 case '|':
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3958 negz = nega | negb;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3959 size_z = negb ? size_b : size_a;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3960 break;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3961 default:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3962 PyErr_BadArgument();
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3963 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3964 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3965
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3966 /* We allow an extra digit if z is negative, to make sure that
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3967 the final two's complement of z doesn't overflow. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3968 z = _PyLong_New(size_z + negz);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3969 if (z == NULL) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3970 Py_DECREF(a);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3971 Py_DECREF(b);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3972 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3973 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3974
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3975 /* Compute digits for overlap of a and b. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3976 switch(op) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3977 case '&':
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3978 for (i = 0; i < size_b; ++i)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3979 z->ob_digit[i] = a->ob_digit[i] & b->ob_digit[i];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3980 break;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3981 case '|':
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3982 for (i = 0; i < size_b; ++i)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3983 z->ob_digit[i] = a->ob_digit[i] | b->ob_digit[i];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3984 break;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3985 case '^':
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3986 for (i = 0; i < size_b; ++i)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3987 z->ob_digit[i] = a->ob_digit[i] ^ b->ob_digit[i];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3988 break;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3989 default:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3990 PyErr_BadArgument();
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3991 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3992 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3993
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3994 /* Copy any remaining digits of a, inverting if necessary. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3995 if (op == '^' && negb)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3996 for (; i < size_z; ++i)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3997 z->ob_digit[i] = a->ob_digit[i] ^ PyLong_MASK;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3998 else if (i < size_z)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
3999 memcpy(&z->ob_digit[i], &a->ob_digit[i],
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4000 (size_z-i)*sizeof(digit));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4001
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4002 /* Complement result if negative. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4003 if (negz) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4004 Py_SIZE(z) = -(Py_SIZE(z));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4005 z->ob_digit[size_z] = PyLong_MASK;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4006 v_complement(z->ob_digit, z->ob_digit, size_z+1);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4007 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4008
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4009 Py_DECREF(a);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4010 Py_DECREF(b);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4011 return (PyObject *)maybe_small_long(long_normalize(z));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4012 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4013
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4014 static PyObject *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4015 long_and(PyObject *a, PyObject *b)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4016 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4017 PyObject *c;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4018 CHECK_BINOP(a, b);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4019 c = long_bitwise((PyLongObject*)a, '&', (PyLongObject*)b);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4020 return c;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4021 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4022
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4023 static PyObject *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4024 long_xor(PyObject *a, PyObject *b)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4025 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4026 PyObject *c;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4027 CHECK_BINOP(a, b);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4028 c = long_bitwise((PyLongObject*)a, '^', (PyLongObject*)b);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4029 return c;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4030 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4031
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4032 static PyObject *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4033 long_or(PyObject *a, PyObject *b)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4034 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4035 PyObject *c;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4036 CHECK_BINOP(a, b);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4037 c = long_bitwise((PyLongObject*)a, '|', (PyLongObject*)b);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4038 return c;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4039 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4040
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4041 static PyObject *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4042 long_long(PyObject *v)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4043 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4044 if (PyLong_CheckExact(v))
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4045 Py_INCREF(v);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4046 else
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4047 v = _PyLong_Copy((PyLongObject *)v);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4048 return v;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4049 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4050
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4051 static PyObject *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4052 long_float(PyObject *v)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4053 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4054 double result;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4055 result = PyLong_AsDouble(v);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4056 if (result == -1.0 && PyErr_Occurred())
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4057 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4058 return PyFloat_FromDouble(result);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4059 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4060
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4061 static PyObject *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4062 long_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4063
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4064 static PyObject *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4065 long_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4066 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4067 PyObject *obase = NULL, *x = NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4068 long base;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4069 int overflow;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4070 static char *kwlist[] = {"x", "base", 0};
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4071
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4072 if (type != &PyLong_Type)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4073 return long_subtype_new(type, args, kwds); /* Wimp out */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4074 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OO:int", kwlist,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4075 &x, &obase))
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4076 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4077 if (x == NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4078 return PyLong_FromLong(0L);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4079 if (obase == NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4080 return PyNumber_Long(x);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4081
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4082 base = PyLong_AsLongAndOverflow(obase, &overflow);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4083 if (base == -1 && PyErr_Occurred())
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4084 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4085 if (overflow || (base != 0 && base < 2) || base > 36) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4086 PyErr_SetString(PyExc_ValueError,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4087 "int() arg 2 must be >= 2 and <= 36");
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4088 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4089 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4090
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4091 if (PyUnicode_Check(x))
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4092 return PyLong_FromUnicodeObject(x, (int)base);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4093 else if (PyByteArray_Check(x) || PyBytes_Check(x)) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4094 /* Since PyLong_FromString doesn't have a length parameter,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4095 * check here for possible NULs in the string. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4096 char *string;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4097 Py_ssize_t size = Py_SIZE(x);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4098 if (PyByteArray_Check(x))
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4099 string = PyByteArray_AS_STRING(x);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4100 else
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4101 string = PyBytes_AS_STRING(x);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4102 if (strlen(string) != (size_t)size) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4103 /* We only see this if there's a null byte in x,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4104 x is a bytes or buffer, *and* a base is given. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4105 PyErr_Format(PyExc_ValueError,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4106 "invalid literal for int() with base %d: %R",
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4107 (int)base, x);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4108 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4109 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4110 return PyLong_FromString(string, NULL, (int)base);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4111 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4112 else {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4113 PyErr_SetString(PyExc_TypeError,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4114 "int() can't convert non-string with explicit base");
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4115 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4116 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4117 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4118
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4119 /* Wimpy, slow approach to tp_new calls for subtypes of long:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4120 first create a regular long from whatever arguments we got,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4121 then allocate a subtype instance and initialize it from
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4122 the regular long. The regular long is then thrown away.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4123 */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4124 static PyObject *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4125 long_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4126 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4127 PyLongObject *tmp, *newobj;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4128 Py_ssize_t i, n;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4129
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4130 assert(PyType_IsSubtype(type, &PyLong_Type));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4131 tmp = (PyLongObject *)long_new(&PyLong_Type, args, kwds);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4132 if (tmp == NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4133 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4134 assert(PyLong_CheckExact(tmp));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4135 n = Py_SIZE(tmp);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4136 if (n < 0)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4137 n = -n;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4138 newobj = (PyLongObject *)type->tp_alloc(type, n);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4139 if (newobj == NULL) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4140 Py_DECREF(tmp);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4141 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4142 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4143 assert(PyLong_Check(newobj));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4144 Py_SIZE(newobj) = Py_SIZE(tmp);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4145 for (i = 0; i < n; i++)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4146 newobj->ob_digit[i] = tmp->ob_digit[i];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4147 Py_DECREF(tmp);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4148 return (PyObject *)newobj;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4149 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4150
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4151 static PyObject *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4152 long_getnewargs(PyLongObject *v)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4153 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4154 return Py_BuildValue("(N)", _PyLong_Copy(v));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4155 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4156
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4157 static PyObject *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4158 long_get0(PyLongObject *v, void *context) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4159 return PyLong_FromLong(0L);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4160 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4161
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4162 static PyObject *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4163 long_get1(PyLongObject *v, void *context) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4164 return PyLong_FromLong(1L);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4165 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4166
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4167 static PyObject *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4168 long__format__(PyObject *self, PyObject *args)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4169 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4170 PyObject *format_spec;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4171
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4172 if (!PyArg_ParseTuple(args, "U:__format__", &format_spec))
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4173 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4174 return _PyLong_FormatAdvanced(self, format_spec, 0,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4175 PyUnicode_GET_LENGTH(format_spec));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4176 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4177
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4178 /* Return a pair (q, r) such that a = b * q + r, and
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4179 abs(r) <= abs(b)/2, with equality possible only if q is even.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4180 In other words, q == a / b, rounded to the nearest integer using
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4181 round-half-to-even. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4182
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4183 PyObject *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4184 _PyLong_DivmodNear(PyObject *a, PyObject *b)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4185 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4186 PyLongObject *quo = NULL, *rem = NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4187 PyObject *one = NULL, *twice_rem, *result, *temp;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4188 int cmp, quo_is_odd, quo_is_neg;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4189
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4190 /* Equivalent Python code:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4191
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4192 def divmod_near(a, b):
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4193 q, r = divmod(a, b)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4194 # round up if either r / b > 0.5, or r / b == 0.5 and q is odd.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4195 # The expression r / b > 0.5 is equivalent to 2 * r > b if b is
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4196 # positive, 2 * r < b if b negative.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4197 greater_than_half = 2*r > b if b > 0 else 2*r < b
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4198 exactly_half = 2*r == b
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4199 if greater_than_half or exactly_half and q % 2 == 1:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4200 q += 1
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4201 r -= b
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4202 return q, r
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4203
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4204 */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4205 if (!PyLong_Check(a) || !PyLong_Check(b)) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4206 PyErr_SetString(PyExc_TypeError,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4207 "non-integer arguments in division");
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4208 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4209 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4210
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4211 /* Do a and b have different signs? If so, quotient is negative. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4212 quo_is_neg = (Py_SIZE(a) < 0) != (Py_SIZE(b) < 0);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4213
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4214 one = PyLong_FromLong(1L);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4215 if (one == NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4216 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4217
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4218 if (long_divrem((PyLongObject*)a, (PyLongObject*)b, &quo, &rem) < 0)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4219 goto error;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4220
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4221 /* compare twice the remainder with the divisor, to see
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4222 if we need to adjust the quotient and remainder */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4223 twice_rem = long_lshift((PyObject *)rem, one);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4224 if (twice_rem == NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4225 goto error;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4226 if (quo_is_neg) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4227 temp = long_neg((PyLongObject*)twice_rem);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4228 Py_DECREF(twice_rem);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4229 twice_rem = temp;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4230 if (twice_rem == NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4231 goto error;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4232 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4233 cmp = long_compare((PyLongObject *)twice_rem, (PyLongObject *)b);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4234 Py_DECREF(twice_rem);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4235
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4236 quo_is_odd = Py_SIZE(quo) != 0 && ((quo->ob_digit[0] & 1) != 0);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4237 if ((Py_SIZE(b) < 0 ? cmp < 0 : cmp > 0) || (cmp == 0 && quo_is_odd)) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4238 /* fix up quotient */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4239 if (quo_is_neg)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4240 temp = long_sub(quo, (PyLongObject *)one);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4241 else
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4242 temp = long_add(quo, (PyLongObject *)one);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4243 Py_DECREF(quo);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4244 quo = (PyLongObject *)temp;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4245 if (quo == NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4246 goto error;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4247 /* and remainder */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4248 if (quo_is_neg)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4249 temp = long_add(rem, (PyLongObject *)b);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4250 else
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4251 temp = long_sub(rem, (PyLongObject *)b);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4252 Py_DECREF(rem);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4253 rem = (PyLongObject *)temp;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4254 if (rem == NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4255 goto error;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4256 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4257
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4258 result = PyTuple_New(2);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4259 if (result == NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4260 goto error;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4261
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4262 /* PyTuple_SET_ITEM steals references */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4263 PyTuple_SET_ITEM(result, 0, (PyObject *)quo);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4264 PyTuple_SET_ITEM(result, 1, (PyObject *)rem);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4265 Py_DECREF(one);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4266 return result;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4267
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4268 error:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4269 Py_XDECREF(quo);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4270 Py_XDECREF(rem);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4271 Py_XDECREF(one);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4272 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4273 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4274
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4275 static PyObject *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4276 long_round(PyObject *self, PyObject *args)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4277 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4278 PyObject *o_ndigits=NULL, *temp, *result, *ndigits;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4279
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4280 /* To round an integer m to the nearest 10**n (n positive), we make use of
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4281 * the divmod_near operation, defined by:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4282 *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4283 * divmod_near(a, b) = (q, r)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4284 *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4285 * where q is the nearest integer to the quotient a / b (the
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4286 * nearest even integer in the case of a tie) and r == a - q * b.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4287 * Hence q * b = a - r is the nearest multiple of b to a,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4288 * preferring even multiples in the case of a tie.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4289 *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4290 * So the nearest multiple of 10**n to m is:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4291 *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4292 * m - divmod_near(m, 10**n)[1].
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4293 */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4294 if (!PyArg_ParseTuple(args, "|O", &o_ndigits))
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4295 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4296 if (o_ndigits == NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4297 return long_long(self);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4298
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4299 ndigits = PyNumber_Index(o_ndigits);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4300 if (ndigits == NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4301 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4302
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4303 /* if ndigits >= 0 then no rounding is necessary; return self unchanged */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4304 if (Py_SIZE(ndigits) >= 0) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4305 Py_DECREF(ndigits);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4306 return long_long(self);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4307 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4308
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4309 /* result = self - divmod_near(self, 10 ** -ndigits)[1] */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4310 temp = long_neg((PyLongObject*)ndigits);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4311 Py_DECREF(ndigits);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4312 ndigits = temp;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4313 if (ndigits == NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4314 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4315
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4316 result = PyLong_FromLong(10L);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4317 if (result == NULL) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4318 Py_DECREF(ndigits);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4319 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4320 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4321
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4322 temp = long_pow(result, ndigits, Py_None);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4323 Py_DECREF(ndigits);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4324 Py_DECREF(result);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4325 result = temp;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4326 if (result == NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4327 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4328
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4329 temp = _PyLong_DivmodNear(self, result);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4330 Py_DECREF(result);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4331 result = temp;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4332 if (result == NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4333 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4334
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4335 temp = long_sub((PyLongObject *)self,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4336 (PyLongObject *)PyTuple_GET_ITEM(result, 1));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4337 Py_DECREF(result);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4338 result = temp;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4339
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4340 return result;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4341 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4342
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4343 static PyObject *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4344 long_sizeof(PyLongObject *v)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4345 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4346 Py_ssize_t res;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4347
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4348 res = offsetof(PyLongObject, ob_digit) + ABS(Py_SIZE(v))*sizeof(digit);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4349 return PyLong_FromSsize_t(res);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4350 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4351
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4352 static PyObject *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4353 long_bit_length(PyLongObject *v)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4354 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4355 PyLongObject *result, *x, *y;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4356 Py_ssize_t ndigits, msd_bits = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4357 digit msd;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4358
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4359 assert(v != NULL);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4360 assert(PyLong_Check(v));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4361
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4362 ndigits = ABS(Py_SIZE(v));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4363 if (ndigits == 0)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4364 return PyLong_FromLong(0);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4365
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4366 msd = v->ob_digit[ndigits-1];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4367 while (msd >= 32) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4368 msd_bits += 6;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4369 msd >>= 6;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4370 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4371 msd_bits += (long)(BitLengthTable[msd]);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4372
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4373 if (ndigits <= PY_SSIZE_T_MAX/PyLong_SHIFT)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4374 return PyLong_FromSsize_t((ndigits-1)*PyLong_SHIFT + msd_bits);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4375
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4376 /* expression above may overflow; use Python integers instead */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4377 result = (PyLongObject *)PyLong_FromSsize_t(ndigits - 1);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4378 if (result == NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4379 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4380 x = (PyLongObject *)PyLong_FromLong(PyLong_SHIFT);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4381 if (x == NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4382 goto error;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4383 y = (PyLongObject *)long_mul(result, x);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4384 Py_DECREF(x);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4385 if (y == NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4386 goto error;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4387 Py_DECREF(result);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4388 result = y;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4389
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4390 x = (PyLongObject *)PyLong_FromLong((long)msd_bits);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4391 if (x == NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4392 goto error;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4393 y = (PyLongObject *)long_add(result, x);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4394 Py_DECREF(x);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4395 if (y == NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4396 goto error;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4397 Py_DECREF(result);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4398 result = y;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4399
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4400 return (PyObject *)result;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4401
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4402 error:
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4403 Py_DECREF(result);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4404 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4405 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4406
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4407 PyDoc_STRVAR(long_bit_length_doc,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4408 "int.bit_length() -> int\n\
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4409 \n\
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4410 Number of bits necessary to represent self in binary.\n\
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4411 >>> bin(37)\n\
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4412 '0b100101'\n\
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4413 >>> (37).bit_length()\n\
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4414 6");
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4415
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4416 #if 0
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4417 static PyObject *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4418 long_is_finite(PyObject *v)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4419 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4420 Py_RETURN_TRUE;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4421 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4422 #endif
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4423
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4424
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4425 static PyObject *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4426 long_to_bytes(PyLongObject *v, PyObject *args, PyObject *kwds)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4427 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4428 PyObject *byteorder_str;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4429 PyObject *is_signed_obj = NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4430 Py_ssize_t length;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4431 int little_endian;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4432 int is_signed;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4433 PyObject *bytes;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4434 static char *kwlist[] = {"length", "byteorder", "signed", NULL};
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4435
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4436 if (!PyArg_ParseTupleAndKeywords(args, kwds, "nU|O:to_bytes", kwlist,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4437 &length, &byteorder_str,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4438 &is_signed_obj))
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4439 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4440
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4441 if (args != NULL && Py_SIZE(args) > 2) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4442 PyErr_SetString(PyExc_TypeError,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4443 "'signed' is a keyword-only argument");
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4444 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4445 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4446
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4447 if (!PyUnicode_CompareWithASCIIString(byteorder_str, "little"))
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4448 little_endian = 1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4449 else if (!PyUnicode_CompareWithASCIIString(byteorder_str, "big"))
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4450 little_endian = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4451 else {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4452 PyErr_SetString(PyExc_ValueError,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4453 "byteorder must be either 'little' or 'big'");
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4454 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4455 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4456
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4457 if (is_signed_obj != NULL) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4458 int cmp = PyObject_IsTrue(is_signed_obj);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4459 if (cmp < 0)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4460 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4461 is_signed = cmp ? 1 : 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4462 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4463 else {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4464 /* If the signed argument was omitted, use False as the
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4465 default. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4466 is_signed = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4467 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4468
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4469 if (length < 0) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4470 PyErr_SetString(PyExc_ValueError,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4471 "length argument must be non-negative");
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4472 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4473 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4474
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4475 bytes = PyBytes_FromStringAndSize(NULL, length);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4476 if (bytes == NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4477 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4478
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4479 if (_PyLong_AsByteArray(v, (unsigned char *)PyBytes_AS_STRING(bytes),
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4480 length, little_endian, is_signed) < 0) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4481 Py_DECREF(bytes);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4482 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4483 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4484
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4485 return bytes;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4486 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4487
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4488 PyDoc_STRVAR(long_to_bytes_doc,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4489 "int.to_bytes(length, byteorder, *, signed=False) -> bytes\n\
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4490 \n\
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4491 Return an array of bytes representing an integer.\n\
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4492 \n\
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4493 The integer is represented using length bytes. An OverflowError is\n\
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4494 raised if the integer is not representable with the given number of\n\
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4495 bytes.\n\
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4496 \n\
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4497 The byteorder argument determines the byte order used to represent the\n\
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4498 integer. If byteorder is 'big', the most significant byte is at the\n\
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4499 beginning of the byte array. If byteorder is 'little', the most\n\
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4500 significant byte is at the end of the byte array. To request the native\n\
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4501 byte order of the host system, use `sys.byteorder' as the byte order value.\n\
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4502 \n\
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4503 The signed keyword-only argument determines whether two's complement is\n\
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4504 used to represent the integer. If signed is False and a negative integer\n\
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4505 is given, an OverflowError is raised.");
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4506
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4507 static PyObject *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4508 long_from_bytes(PyTypeObject *type, PyObject *args, PyObject *kwds)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4509 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4510 PyObject *byteorder_str;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4511 PyObject *is_signed_obj = NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4512 int little_endian;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4513 int is_signed;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4514 PyObject *obj;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4515 PyObject *bytes;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4516 PyObject *long_obj;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4517 static char *kwlist[] = {"bytes", "byteorder", "signed", NULL};
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4518
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4519 if (!PyArg_ParseTupleAndKeywords(args, kwds, "OU|O:from_bytes", kwlist,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4520 &obj, &byteorder_str,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4521 &is_signed_obj))
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4522 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4523
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4524 if (args != NULL && Py_SIZE(args) > 2) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4525 PyErr_SetString(PyExc_TypeError,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4526 "'signed' is a keyword-only argument");
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4527 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4528 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4529
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4530 if (!PyUnicode_CompareWithASCIIString(byteorder_str, "little"))
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4531 little_endian = 1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4532 else if (!PyUnicode_CompareWithASCIIString(byteorder_str, "big"))
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4533 little_endian = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4534 else {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4535 PyErr_SetString(PyExc_ValueError,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4536 "byteorder must be either 'little' or 'big'");
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4537 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4538 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4539
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4540 if (is_signed_obj != NULL) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4541 int cmp = PyObject_IsTrue(is_signed_obj);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4542 if (cmp < 0)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4543 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4544 is_signed = cmp ? 1 : 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4545 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4546 else {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4547 /* If the signed argument was omitted, use False as the
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4548 default. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4549 is_signed = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4550 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4551
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4552 bytes = PyObject_Bytes(obj);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4553 if (bytes == NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4554 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4555
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4556 long_obj = _PyLong_FromByteArray(
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4557 (unsigned char *)PyBytes_AS_STRING(bytes), Py_SIZE(bytes),
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4558 little_endian, is_signed);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4559 Py_DECREF(bytes);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4560
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4561 /* If from_bytes() was used on subclass, allocate new subclass
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4562 * instance, initialize it with decoded long value and return it.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4563 */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4564 if (type != &PyLong_Type && PyType_IsSubtype(type, &PyLong_Type)) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4565 PyLongObject *newobj;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4566 int i;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4567 Py_ssize_t n = ABS(Py_SIZE(long_obj));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4568
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4569 newobj = (PyLongObject *)type->tp_alloc(type, n);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4570 if (newobj == NULL) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4571 Py_DECREF(long_obj);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4572 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4573 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4574 assert(PyLong_Check(newobj));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4575 Py_SIZE(newobj) = Py_SIZE(long_obj);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4576 for (i = 0; i < n; i++) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4577 newobj->ob_digit[i] =
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4578 ((PyLongObject *)long_obj)->ob_digit[i];
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4579 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4580 Py_DECREF(long_obj);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4581 return (PyObject *)newobj;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4582 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4583
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4584 return long_obj;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4585 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4586
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4587 PyDoc_STRVAR(long_from_bytes_doc,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4588 "int.from_bytes(bytes, byteorder, *, signed=False) -> int\n\
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4589 \n\
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4590 Return the integer represented by the given array of bytes.\n\
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4591 \n\
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4592 The bytes argument must either support the buffer protocol or be an\n\
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4593 iterable object producing bytes. Bytes and bytearray are examples of\n\
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4594 built-in objects that support the buffer protocol.\n\
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4595 \n\
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4596 The byteorder argument determines the byte order used to represent the\n\
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4597 integer. If byteorder is 'big', the most significant byte is at the\n\
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4598 beginning of the byte array. If byteorder is 'little', the most\n\
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4599 significant byte is at the end of the byte array. To request the native\n\
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4600 byte order of the host system, use `sys.byteorder' as the byte order value.\n\
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4601 \n\
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4602 The signed keyword-only argument indicates whether two's complement is\n\
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4603 used to represent the integer.");
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4604
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4605 static PyMethodDef long_methods[] = {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4606 {"conjugate", (PyCFunction)long_long, METH_NOARGS,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4607 "Returns self, the complex conjugate of any int."},
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4608 {"bit_length", (PyCFunction)long_bit_length, METH_NOARGS,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4609 long_bit_length_doc},
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4610 #if 0
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4611 {"is_finite", (PyCFunction)long_is_finite, METH_NOARGS,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4612 "Returns always True."},
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4613 #endif
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4614 {"to_bytes", (PyCFunction)long_to_bytes,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4615 METH_VARARGS|METH_KEYWORDS, long_to_bytes_doc},
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4616 {"from_bytes", (PyCFunction)long_from_bytes,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4617 METH_VARARGS|METH_KEYWORDS|METH_CLASS, long_from_bytes_doc},
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4618 {"__trunc__", (PyCFunction)long_long, METH_NOARGS,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4619 "Truncating an Integral returns itself."},
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4620 {"__floor__", (PyCFunction)long_long, METH_NOARGS,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4621 "Flooring an Integral returns itself."},
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4622 {"__ceil__", (PyCFunction)long_long, METH_NOARGS,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4623 "Ceiling of an Integral returns itself."},
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4624 {"__round__", (PyCFunction)long_round, METH_VARARGS,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4625 "Rounding an Integral returns itself.\n"
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4626 "Rounding with an ndigits argument also returns an integer."},
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4627 {"__getnewargs__", (PyCFunction)long_getnewargs, METH_NOARGS},
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4628 {"__format__", (PyCFunction)long__format__, METH_VARARGS},
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4629 {"__sizeof__", (PyCFunction)long_sizeof, METH_NOARGS,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4630 "Returns size in memory, in bytes"},
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4631 {NULL, NULL} /* sentinel */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4632 };
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4633
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4634 static PyGetSetDef long_getset[] = {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4635 {"real",
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4636 (getter)long_long, (setter)NULL,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4637 "the real part of a complex number",
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4638 NULL},
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4639 {"imag",
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4640 (getter)long_get0, (setter)NULL,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4641 "the imaginary part of a complex number",
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4642 NULL},
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4643 {"numerator",
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4644 (getter)long_long, (setter)NULL,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4645 "the numerator of a rational number in lowest terms",
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4646 NULL},
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4647 {"denominator",
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4648 (getter)long_get1, (setter)NULL,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4649 "the denominator of a rational number in lowest terms",
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4650 NULL},
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4651 {NULL} /* Sentinel */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4652 };
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4653
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4654 PyDoc_STRVAR(long_doc,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4655 "int(x[, base]) -> integer\n\
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4656 \n\
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4657 Convert a string or number to an integer, if possible. A floating\n\
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4658 point argument will be truncated towards zero (this does not include a\n\
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4659 string representation of a floating point number!) When converting a\n\
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4660 string, use the optional base. It is an error to supply a base when\n\
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4661 converting a non-string.");
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4662
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4663 static PyNumberMethods long_as_number = {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4664 (binaryfunc)long_add, /*nb_add*/
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4665 (binaryfunc)long_sub, /*nb_subtract*/
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4666 (binaryfunc)long_mul, /*nb_multiply*/
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4667 long_mod, /*nb_remainder*/
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4668 long_divmod, /*nb_divmod*/
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4669 long_pow, /*nb_power*/
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4670 (unaryfunc)long_neg, /*nb_negative*/
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4671 (unaryfunc)long_long, /*tp_positive*/
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4672 (unaryfunc)long_abs, /*tp_absolute*/
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4673 (inquiry)long_bool, /*tp_bool*/
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4674 (unaryfunc)long_invert, /*nb_invert*/
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4675 long_lshift, /*nb_lshift*/
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4676 (binaryfunc)long_rshift, /*nb_rshift*/
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4677 long_and, /*nb_and*/
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4678 long_xor, /*nb_xor*/
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4679 long_or, /*nb_or*/
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4680 long_long, /*nb_int*/
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4681 0, /*nb_reserved*/
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4682 long_float, /*nb_float*/
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4683 0, /* nb_inplace_add */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4684 0, /* nb_inplace_subtract */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4685 0, /* nb_inplace_multiply */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4686 0, /* nb_inplace_remainder */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4687 0, /* nb_inplace_power */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4688 0, /* nb_inplace_lshift */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4689 0, /* nb_inplace_rshift */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4690 0, /* nb_inplace_and */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4691 0, /* nb_inplace_xor */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4692 0, /* nb_inplace_or */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4693 long_div, /* nb_floor_divide */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4694 long_true_divide, /* nb_true_divide */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4695 0, /* nb_inplace_floor_divide */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4696 0, /* nb_inplace_true_divide */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4697 long_long, /* nb_index */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4698 };
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4699
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4700 PyTypeObject PyLong_Type = {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4701 PyVarObject_HEAD_INIT(&PyType_Type, 0)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4702 "int", /* tp_name */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4703 offsetof(PyLongObject, ob_digit), /* tp_basicsize */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4704 sizeof(digit), /* tp_itemsize */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4705 long_dealloc, /* tp_dealloc */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4706 0, /* tp_print */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4707 0, /* tp_getattr */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4708 0, /* tp_setattr */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4709 0, /* tp_reserved */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4710 long_to_decimal_string, /* tp_repr */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4711 &long_as_number, /* tp_as_number */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4712 0, /* tp_as_sequence */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4713 0, /* tp_as_mapping */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4714 (hashfunc)long_hash, /* tp_hash */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4715 0, /* tp_call */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4716 long_to_decimal_string, /* tp_str */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4717 PyObject_GenericGetAttr, /* tp_getattro */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4718 0, /* tp_setattro */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4719 0, /* tp_as_buffer */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4720 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4721 Py_TPFLAGS_LONG_SUBCLASS, /* tp_flags */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4722 long_doc, /* tp_doc */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4723 0, /* tp_traverse */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4724 0, /* tp_clear */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4725 long_richcompare, /* tp_richcompare */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4726 0, /* tp_weaklistoffset */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4727 0, /* tp_iter */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4728 0, /* tp_iternext */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4729 long_methods, /* tp_methods */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4730 0, /* tp_members */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4731 long_getset, /* tp_getset */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4732 0, /* tp_base */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4733 0, /* tp_dict */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4734 0, /* tp_descr_get */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4735 0, /* tp_descr_set */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4736 0, /* tp_dictoffset */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4737 0, /* tp_init */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4738 0, /* tp_alloc */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4739 long_new, /* tp_new */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4740 PyObject_Del, /* tp_free */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4741 };
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4742
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4743 static PyTypeObject Int_InfoType;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4744
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4745 PyDoc_STRVAR(int_info__doc__,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4746 "sys.int_info\n\
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4747 \n\
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4748 A struct sequence that holds information about Python's\n\
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4749 internal representation of integers. The attributes are read only.");
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4750
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4751 static PyStructSequence_Field int_info_fields[] = {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4752 {"bits_per_digit", "size of a digit in bits"},
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4753 {"sizeof_digit", "size in bytes of the C type used to represent a digit"},
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4754 {NULL, NULL}
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4755 };
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4756
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4757 static PyStructSequence_Desc int_info_desc = {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4758 "sys.int_info", /* name */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4759 int_info__doc__, /* doc */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4760 int_info_fields, /* fields */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4761 2 /* number of fields */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4762 };
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4763
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4764 PyObject *
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4765 PyLong_GetInfo(void)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4766 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4767 PyObject* int_info;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4768 int field = 0;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4769 int_info = PyStructSequence_New(&Int_InfoType);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4770 if (int_info == NULL)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4771 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4772 PyStructSequence_SET_ITEM(int_info, field++,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4773 PyLong_FromLong(PyLong_SHIFT));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4774 PyStructSequence_SET_ITEM(int_info, field++,
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4775 PyLong_FromLong(sizeof(digit)));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4776 if (PyErr_Occurred()) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4777 Py_CLEAR(int_info);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4778 return NULL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4779 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4780 return int_info;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4781 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4782
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4783 int
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4784 _PyLong_Init(void)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4785 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4786 #if NSMALLNEGINTS + NSMALLPOSINTS > 0
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4787 int ival, size;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4788 PyLongObject *v = small_ints;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4789
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4790 for (ival = -NSMALLNEGINTS; ival < NSMALLPOSINTS; ival++, v++) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4791 size = (ival < 0) ? -1 : ((ival == 0) ? 0 : 1);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4792 if (Py_TYPE(v) == &PyLong_Type) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4793 /* The element is already initialized, most likely
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4794 * the Python interpreter was initialized before.
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4795 */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4796 Py_ssize_t refcnt;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4797 PyObject* op = (PyObject*)v;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4798
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4799 refcnt = Py_REFCNT(op) < 0 ? 0 : Py_REFCNT(op);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4800 _Py_NewReference(op);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4801 /* _Py_NewReference sets the ref count to 1 but
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4802 * the ref count might be larger. Set the refcnt
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4803 * to the original refcnt + 1 */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4804 Py_REFCNT(op) = refcnt + 1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4805 assert(Py_SIZE(op) == size);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4806 assert(v->ob_digit[0] == abs(ival));
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4807 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4808 else {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4809 PyObject_INIT(v, &PyLong_Type);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4810 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4811 Py_SIZE(v) = size;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4812 v->ob_digit[0] = abs(ival);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4813 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4814 #endif
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4815 /* initialize int_info */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4816 if (Int_InfoType.tp_name == 0)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4817 PyStructSequence_InitType(&Int_InfoType, &int_info_desc);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4818
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4819 return 1;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4820 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4821
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4822 void
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4823 PyLong_Fini(void)
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4824 {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4825 /* Integers are currently statically allocated. Py_DECREF is not
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4826 needed, but Python must forget about the reference or multiple
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4827 reinitializations will fail. */
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4828 #if NSMALLNEGINTS + NSMALLPOSINTS > 0
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4829 int i;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4830 PyLongObject *v = small_ints;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4831 for (i = 0; i < NSMALLNEGINTS + NSMALLPOSINTS; i++, v++) {
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4832 _Py_DEC_REFTOTAL;
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4833 _Py_ForgetReference((PyObject*)v);
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4834 }
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4835 #endif
7f74363f4c82 Added some files for the python port
windel
parents:
diff changeset
4836 }