1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2 * gmpy_convert.c *
3 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
4 * Python interface to the GMP or MPIR, MPFR, and MPC multiple precision *
5 * libraries. *
6 * *
7 * Copyright 2000 - 2009 Alex Martelli *
8 * *
9 * Copyright 2008 - 2021 Case Van Horsen *
10 * *
11 * This file is part of GMPY2. *
12 * *
13 * GMPY2 is free software: you can redistribute it and/or modify it under *
14 * the terms of the GNU Lesser General Public License as published by the *
15 * Free Software Foundation, either version 3 of the License, or (at your *
16 * option) any later version. *
17 * *
18 * GMPY2 is distributed in the hope that it will be useful, but WITHOUT *
19 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
20 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public *
21 * License for more details. *
22 * *
23 * You should have received a copy of the GNU Lesser General Public *
24 * License along with GMPY2; if not, see <http://www.gnu.org/licenses/> *
25 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
26
27 /* This file contains all the conversion functions for gmpy2.
28 *
29 * Overview
30 * --------
31 * gmpy2 tries to optimize the performance and accuracy of conversions from
32 * other numeric types. gmpy2 uses a LBYL (Look Before You Leap) approach and
33 * identifies the numeric type before conversion before conversion to a gmpy2
34 * type. The basic operations (+, -, *, /) are optimized to directly work with
35 * some basic types such as C longs or doubles.
36 */
37
38 /* ======================================================================== *
39 * Miscellaneous helper functions. *
40 * ======================================================================== */
41
42 /* Since macros are used in gmpy2's codebase, these functions are skipped
43 * until they are needed for the C API in the future.
44 */
45
46 #if 0
47 static int GMPy_isInteger(PyObject *obj)
48 {
49 return IS_INTEGER(obj) ? 1 : 0;
50 }
51
52 static int GMPy_isFraction(PyObject *obj)
53 {
54 return (!strcmp(Py_TYPE(obj)->tp_name, "Fraction")) ? 1 : 0;
55 }
56
57 static int GMPy_isRational(PyObject *obj)
58 {
59 return IS_RATIONAL(obj) ? 1 : 0;
60 }
61
62 static int GMPy_isReal(PyObject *obj)
63 {
64 return IS_REAL(obj) ? 1 : 0;
65 }
66
67 static int GMPy_isComplex(PyObject *obj)
68 {
69 return IS_COMPLEX(obj) ? 1 : 0;
70 }
71 #endif
72
73 /* GMPy_ObjectType(PyObject *obj) returns an integer that identifies the
74 * object's type. See gmpy2_convert.h for details.
75 *
76 * Exceptions are never raised.
77 */
78
GMPy_ObjectType(PyObject * obj)79 static int GMPy_ObjectType(PyObject *obj)
80 {
81 /* Tests are sorted by order by (best guess of) most common argument type.
82 * Tests that require attribute lookups are done last.
83 */
84
85 if (MPZ_Check(obj)) return OBJ_TYPE_MPZ;
86
87 if (MPFR_Check(obj)) return OBJ_TYPE_MPFR;
88
89 if (MPC_Check(obj)) return OBJ_TYPE_MPC;
90
91 if (MPQ_Check(obj)) return OBJ_TYPE_MPQ;
92
93 if (XMPZ_Check(obj)) return OBJ_TYPE_XMPZ;
94
95 if (PyIntOrLong_Check(obj)) return OBJ_TYPE_PyInteger;
96
97 if (PyFloat_Check(obj)) return OBJ_TYPE_PyFloat;
98
99 if (PyComplex_Check(obj)) return OBJ_TYPE_PyComplex;
100
101 if (IS_FRACTION(obj)) return OBJ_TYPE_PyFraction;
102
103 /* Now we look for the presence of __mpz__, __mpq__, __mpfr__, and __mpc__.
104 * Since a type may define more than one of the special methods, we perform
105 * the checks in reverse order.
106 */
107
108 if (HAS_MPC_CONVERSION(obj)) return OBJ_TYPE_HAS_MPC;
109
110 if (HAS_MPFR_CONVERSION(obj)) return OBJ_TYPE_HAS_MPFR;
111
112 if (HAS_MPQ_CONVERSION(obj)) return OBJ_TYPE_HAS_MPQ;
113
114 if (HAS_MPZ_CONVERSION(obj)) return OBJ_TYPE_HAS_MPZ;
115
116 return OBJ_TYPE_UNKNOWN;
117 }
118
119 static PyObject *
GMPy_RemoveUnderscoreASCII(PyObject * s)120 GMPy_RemoveUnderscoreASCII(PyObject *s)
121 {
122 PyObject *ascii_str = NULL, *temp = NULL, *filtered = NULL, *under = NULL, *blank = NULL;
123
124 if (PyBytes_CheckExact(s)) {
125 temp = PyUnicode_DecodeASCII(PyBytes_AS_STRING(s), PyBytes_GET_SIZE(s), "strict");
126 if (!temp) {
127 VALUE_ERROR("string contains non-ASCII characters");
128 return NULL;
129 }
130 }
131 else if (PyUnicode_Check(s)) {
132 Py_INCREF(s);
133 temp = s;
134 }
135 else {
136 TYPE_ERROR("object is not string or Unicode");
137 return NULL;
138 }
139
140 if ((under = PyUnicode_FromString("_")) &&
141 (blank = PyUnicode_FromString(""))) {
142 filtered = PyUnicode_Replace(temp, under, blank, -1);
143 }
144 Py_XDECREF(under);
145 Py_XDECREF(blank);
146 Py_XDECREF(temp);
147
148 if (!filtered) {
149 return NULL;
150 }
151
152 ascii_str = PyUnicode_AsASCIIString(filtered);
153 Py_DECREF(filtered);
154 if (!ascii_str) {
155 VALUE_ERROR("string contains non-ASCII characters");
156 return NULL;
157 }
158
159 return ascii_str;
160 }
161
162 /* mpz_set_PyStr converts a Python "string" into a mpz_t structure. It accepts
163 * a sequence of bytes (i.e. str in Python 2, bytes in Python 3) or a Unicode
164 * string (i.e. unicode in Python 3, str in Python 3). Returns -1 on error,
165 * 1 if successful.
166 */
167
168 static int
mpz_set_PyStr(mpz_ptr z,PyObject * s,int base)169 mpz_set_PyStr(mpz_ptr z, PyObject *s, int base)
170 {
171 char *cp;
172 Py_ssize_t len;
173 PyObject *ascii_str = ascii_str = GMPy_RemoveUnderscoreASCII(s);
174
175 if (!ascii_str) return -1;
176
177 len = PyBytes_Size(ascii_str);
178 cp = PyBytes_AsString(ascii_str);
179
180
181 /* Check for leading base indicators. */
182 if (base == 0) {
183 if (len > 2 && cp[0] == '0') {
184 if (cp[1] == 'b') { base = 2; cp += 2; }
185 else if (cp[1] == 'o') { base = 8; cp += 2; }
186 else if (cp[1] == 'x') { base = 16; cp += 2; }
187 else { base = 10; }
188 }
189 else {
190 base = 10;
191 }
192 }
193 else if (cp[0] == '0') {
194 /* If the specified base matches the leading base indicators, then
195 * we need to skip the base indicators.
196 */
197 if (cp[1] =='b' && base == 2) { cp += 2; }
198 else if (cp[1] =='o' && base == 8) { cp += 2; }
199 else if (cp[1] =='x' && base == 16) { cp += 2; }
200 }
201
202 /* delegate rest to GMP's _set_str function */
203 if (-1 == mpz_set_str(z, cp, base)) {
204 VALUE_ERROR("invalid digits");
205 Py_DECREF(ascii_str);
206 return -1;
207 }
208 Py_DECREF(ascii_str);
209 return 1;
210 }
211
212 /* Format an mpz into any base (2 to 62). Bits in the option parameter
213 * control various behaviors:
214 * bit 0: if set, output is wrapped with mpz(...) or xmpz(...)
215 * bit 1: if set, a '+' is included for positive numbers
216 * bit 2: if set, a ' ' is included for positive nubmers
217 * bit 3: if set, a '0b', '0o', or '0x' is included for binary, octal, hex
218 * bit 4: if set, no prefix is included for binary, octal, hex
219 *
220 * Note: if neither bit 3 or 4 is set, prefixes that match the platform
221 * default are included.
222 *
223 * If base < 0, capital letters are used.
224 *
225 * If which = 0, then mpz formatting is used (if bit 0 set). Otherwise xmpz
226 * formatting is used (if bit 0 is set).
227 */
228
229 static char* _ztag = "mpz(";
230 static char* _xztag = "xmpz(";
231
232 static PyObject *
mpz_ascii(mpz_t z,int base,int option,int which)233 mpz_ascii(mpz_t z, int base, int option, int which)
234 {
235 PyObject *result;
236 char *buffer, *p;
237 int negative = 0;
238 size_t size;
239
240 if (
241 !(
242 ((base >= -36) && (base <= -2)) ||
243 ((base >= 2) && (base <= 62))
244 )
245 ) {
246 VALUE_ERROR("base must be in the interval 2 ... 62");
247 return NULL;
248 }
249
250 /* Allocate extra space for:
251 *
252 * minus sign and trailing NULL byte (2)
253 * 'xmpz()' tag (6)
254 * '0x' prefix (2)
255 * -----
256 * 10
257 *
258 * And add one more to be sure...
259 */
260
261 size = mpz_sizeinbase(z, (base < 0 ? -base : base)) + 11;
262 TEMP_ALLOC(buffer, size);
263
264 if (mpz_sgn(z) < 0) {
265 negative = 1;
266 mpz_neg(z, z);
267 }
268
269 p = buffer;
270 if (option & 1) {
271 if (which)
272 strcpy(p, _xztag);
273 else
274 strcpy(p, _ztag);
275 p += strlen(p);
276 }
277
278 if (negative) {
279 *(p++) = '-';
280 }
281 else {
282 if (option & 2)
283 *(p++) = '+';
284 else if (option & 4)
285 *(p++) = ' ';
286 }
287
288 if (option & 8) {
289 if (base == 2) { *(p++) = '0'; *(p++) = 'b'; }
290 else if (base == 8) { *(p++) = '0'; *(p++) = 'o'; }
291 else if (base == 16) { *(p++) = '0'; *(p++) = 'x'; }
292 else if (base == -16) { *(p++) = '0'; *(p++) = 'X'; }
293 }
294 else if (!(option & 24)) {
295 #ifdef PY2
296 if (base == 8) { *(p++) = '0'; }
297 #else
298 if (base == 2) { *(p++) = '0'; *(p++) = 'b'; }
299 else if (base == 8) { *(p++) = '0'; *(p++) = 'o'; }
300 #endif
301 else if (base == 16) { *(p++) = '0'; *(p++) = 'x'; }
302 else if (base == -16) { *(p++) = '0'; *(p++) = 'X'; }
303 }
304
305 /* Call GMP. */
306 mpz_get_str(p, base, z);
307 p = buffer + strlen(buffer);
308
309 if (option & 1)
310 *(p++) = ')';
311 *(p++) = '\00';
312
313 result = Py_BuildValue("s", buffer);
314 if (negative == 1) {
315 mpz_neg(z, z);
316 }
317 TEMP_FREE(buffer, size);
318 return result;
319 }
320