1 | /* |
2 | * This file is part of the MicroPython project, http://micropython.org/ |
3 | * |
4 | * The MIT License (MIT) |
5 | * |
6 | * Copyright (c) 2013, 2014 Damien P. George |
7 | * |
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
9 | * of this software and associated documentation files (the "Software"), to deal |
10 | * in the Software without restriction, including without limitation the rights |
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
12 | * copies of the Software, and to permit persons to whom the Software is |
13 | * furnished to do so, subject to the following conditions: |
14 | * |
15 | * The above copyright notice and this permission notice shall be included in |
16 | * all copies or substantial portions of the Software. |
17 | * |
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
24 | * THE SOFTWARE. |
25 | */ |
26 | |
27 | #include <string.h> |
28 | #include <stdio.h> |
29 | #include <assert.h> |
30 | |
31 | #include "py/parsenumbase.h" |
32 | #include "py/smallint.h" |
33 | #include "py/objint.h" |
34 | #include "py/runtime.h" |
35 | |
36 | #if MICROPY_PY_BUILTINS_FLOAT |
37 | #include <math.h> |
38 | #endif |
39 | |
40 | #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_MPZ |
41 | |
42 | #if MICROPY_PY_SYS_MAXSIZE |
43 | // Export value for sys.maxsize |
44 | // *FORMAT-OFF* |
45 | #define DIG_MASK ((MPZ_LONG_1 << MPZ_DIG_SIZE) - 1) |
46 | STATIC const mpz_dig_t maxsize_dig[] = { |
47 | #define NUM_DIG 1 |
48 | (MP_SSIZE_MAX >> MPZ_DIG_SIZE * 0) & DIG_MASK, |
49 | #if (MP_SSIZE_MAX >> MPZ_DIG_SIZE * 0) > DIG_MASK |
50 | #undef NUM_DIG |
51 | #define NUM_DIG 2 |
52 | (MP_SSIZE_MAX >> MPZ_DIG_SIZE * 1) & DIG_MASK, |
53 | #if (MP_SSIZE_MAX >> MPZ_DIG_SIZE * 1) > DIG_MASK |
54 | #undef NUM_DIG |
55 | #define NUM_DIG 3 |
56 | (MP_SSIZE_MAX >> MPZ_DIG_SIZE * 2) & DIG_MASK, |
57 | #if (MP_SSIZE_MAX >> MPZ_DIG_SIZE * 2) > DIG_MASK |
58 | #undef NUM_DIG |
59 | #define NUM_DIG 4 |
60 | (MP_SSIZE_MAX >> MPZ_DIG_SIZE * 3) & DIG_MASK, |
61 | #if (MP_SSIZE_MAX >> MPZ_DIG_SIZE * 3) > DIG_MASK |
62 | #error cannot encode MP_SSIZE_MAX as mpz |
63 | #endif |
64 | #endif |
65 | #endif |
66 | #endif |
67 | }; |
68 | // *FORMAT-ON* |
69 | const mp_obj_int_t mp_sys_maxsize_obj = { |
70 | {&mp_type_int}, |
71 | {.fixed_dig = 1, .len = NUM_DIG, .alloc = NUM_DIG, .dig = (mpz_dig_t *)maxsize_dig} |
72 | }; |
73 | #undef DIG_MASK |
74 | #undef NUM_DIG |
75 | #endif |
76 | |
77 | mp_obj_int_t *mp_obj_int_new_mpz(void) { |
78 | mp_obj_int_t *o = m_new_obj(mp_obj_int_t); |
79 | o->base.type = &mp_type_int; |
80 | mpz_init_zero(&o->mpz); |
81 | return o; |
82 | } |
83 | |
84 | // This routine expects you to pass in a buffer and size (in *buf and buf_size). |
85 | // If, for some reason, this buffer is too small, then it will allocate a |
86 | // buffer and return the allocated buffer and size in *buf and *buf_size. It |
87 | // is the callers responsibility to free this allocated buffer. |
88 | // |
89 | // The resulting formatted string will be returned from this function and the |
90 | // formatted size will be in *fmt_size. |
91 | // |
92 | // This particular routine should only be called for the mpz representation of the int. |
93 | char *mp_obj_int_formatted_impl(char **buf, size_t *buf_size, size_t *fmt_size, mp_const_obj_t self_in, |
94 | int base, const char *prefix, char base_char, char comma) { |
95 | assert(mp_obj_is_type(self_in, &mp_type_int)); |
96 | const mp_obj_int_t *self = MP_OBJ_TO_PTR(self_in); |
97 | |
98 | size_t needed_size = mp_int_format_size(mpz_max_num_bits(&self->mpz), base, prefix, comma); |
99 | if (needed_size > *buf_size) { |
100 | *buf = m_new(char, needed_size); |
101 | *buf_size = needed_size; |
102 | } |
103 | char *str = *buf; |
104 | |
105 | *fmt_size = mpz_as_str_inpl(&self->mpz, base, prefix, base_char, comma, str); |
106 | |
107 | return str; |
108 | } |
109 | |
110 | mp_obj_t mp_obj_int_from_bytes_impl(bool big_endian, size_t len, const byte *buf) { |
111 | mp_obj_int_t *o = mp_obj_int_new_mpz(); |
112 | mpz_set_from_bytes(&o->mpz, big_endian, len, buf); |
113 | return MP_OBJ_FROM_PTR(o); |
114 | } |
115 | |
116 | void mp_obj_int_to_bytes_impl(mp_obj_t self_in, bool big_endian, size_t len, byte *buf) { |
117 | assert(mp_obj_is_type(self_in, &mp_type_int)); |
118 | mp_obj_int_t *self = MP_OBJ_TO_PTR(self_in); |
119 | mpz_as_bytes(&self->mpz, big_endian, len, buf); |
120 | } |
121 | |
122 | int mp_obj_int_sign(mp_obj_t self_in) { |
123 | if (mp_obj_is_small_int(self_in)) { |
124 | mp_int_t val = MP_OBJ_SMALL_INT_VALUE(self_in); |
125 | if (val < 0) { |
126 | return -1; |
127 | } else if (val > 0) { |
128 | return 1; |
129 | } else { |
130 | return 0; |
131 | } |
132 | } |
133 | mp_obj_int_t *self = MP_OBJ_TO_PTR(self_in); |
134 | if (self->mpz.len == 0) { |
135 | return 0; |
136 | } else if (self->mpz.neg == 0) { |
137 | return 1; |
138 | } else { |
139 | return -1; |
140 | } |
141 | } |
142 | |
143 | mp_obj_t mp_obj_int_unary_op(mp_unary_op_t op, mp_obj_t o_in) { |
144 | mp_obj_int_t *o = MP_OBJ_TO_PTR(o_in); |
145 | switch (op) { |
146 | case MP_UNARY_OP_BOOL: |
147 | return mp_obj_new_bool(!mpz_is_zero(&o->mpz)); |
148 | case MP_UNARY_OP_HASH: |
149 | return MP_OBJ_NEW_SMALL_INT(mpz_hash(&o->mpz)); |
150 | case MP_UNARY_OP_POSITIVE: |
151 | return o_in; |
152 | case MP_UNARY_OP_NEGATIVE: { mp_obj_int_t *o2 = mp_obj_int_new_mpz(); |
153 | mpz_neg_inpl(&o2->mpz, &o->mpz); |
154 | return MP_OBJ_FROM_PTR(o2); |
155 | } |
156 | case MP_UNARY_OP_INVERT: { mp_obj_int_t *o2 = mp_obj_int_new_mpz(); |
157 | mpz_not_inpl(&o2->mpz, &o->mpz); |
158 | return MP_OBJ_FROM_PTR(o2); |
159 | } |
160 | case MP_UNARY_OP_ABS: { |
161 | mp_obj_int_t *self = MP_OBJ_TO_PTR(o_in); |
162 | if (self->mpz.neg == 0) { |
163 | return o_in; |
164 | } |
165 | mp_obj_int_t *self2 = mp_obj_int_new_mpz(); |
166 | mpz_abs_inpl(&self2->mpz, &self->mpz); |
167 | return MP_OBJ_FROM_PTR(self2); |
168 | } |
169 | default: |
170 | return MP_OBJ_NULL; // op not supported |
171 | } |
172 | } |
173 | |
174 | mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { |
175 | const mpz_t *zlhs; |
176 | const mpz_t *zrhs; |
177 | mpz_t z_int; |
178 | mpz_dig_t z_int_dig[MPZ_NUM_DIG_FOR_INT]; |
179 | |
180 | // lhs could be a small int (eg small-int + mpz) |
181 | if (mp_obj_is_small_int(lhs_in)) { |
182 | mpz_init_fixed_from_int(&z_int, z_int_dig, MPZ_NUM_DIG_FOR_INT, MP_OBJ_SMALL_INT_VALUE(lhs_in)); |
183 | zlhs = &z_int; |
184 | } else { |
185 | assert(mp_obj_is_type(lhs_in, &mp_type_int)); |
186 | zlhs = &((mp_obj_int_t *)MP_OBJ_TO_PTR(lhs_in))->mpz; |
187 | } |
188 | |
189 | // if rhs is small int, then lhs was not (otherwise mp_binary_op handles it) |
190 | if (mp_obj_is_small_int(rhs_in)) { |
191 | mpz_init_fixed_from_int(&z_int, z_int_dig, MPZ_NUM_DIG_FOR_INT, MP_OBJ_SMALL_INT_VALUE(rhs_in)); |
192 | zrhs = &z_int; |
193 | } else if (mp_obj_is_type(rhs_in, &mp_type_int)) { |
194 | zrhs = &((mp_obj_int_t *)MP_OBJ_TO_PTR(rhs_in))->mpz; |
195 | #if MICROPY_PY_BUILTINS_FLOAT |
196 | } else if (mp_obj_is_float(rhs_in)) { |
197 | return mp_obj_float_binary_op(op, mpz_as_float(zlhs), rhs_in); |
198 | #endif |
199 | #if MICROPY_PY_BUILTINS_COMPLEX |
200 | } else if (mp_obj_is_type(rhs_in, &mp_type_complex)) { |
201 | return mp_obj_complex_binary_op(op, mpz_as_float(zlhs), 0, rhs_in); |
202 | #endif |
203 | } else { |
204 | // delegate to generic function to check for extra cases |
205 | return mp_obj_int_binary_op_extra_cases(op, lhs_in, rhs_in); |
206 | } |
207 | |
208 | #if MICROPY_PY_BUILTINS_FLOAT |
209 | if (op == MP_BINARY_OP_TRUE_DIVIDE || op == MP_BINARY_OP_INPLACE_TRUE_DIVIDE) { |
210 | if (mpz_is_zero(zrhs)) { |
211 | goto zero_division_error; |
212 | } |
213 | mp_float_t flhs = mpz_as_float(zlhs); |
214 | mp_float_t frhs = mpz_as_float(zrhs); |
215 | return mp_obj_new_float(flhs / frhs); |
216 | } |
217 | #endif |
218 | |
219 | if (op >= MP_BINARY_OP_INPLACE_OR && op < MP_BINARY_OP_CONTAINS) { |
220 | mp_obj_int_t *res = mp_obj_int_new_mpz(); |
221 | |
222 | switch (op) { |
223 | case MP_BINARY_OP_ADD: |
224 | case MP_BINARY_OP_INPLACE_ADD: |
225 | mpz_add_inpl(&res->mpz, zlhs, zrhs); |
226 | break; |
227 | case MP_BINARY_OP_SUBTRACT: |
228 | case MP_BINARY_OP_INPLACE_SUBTRACT: |
229 | mpz_sub_inpl(&res->mpz, zlhs, zrhs); |
230 | break; |
231 | case MP_BINARY_OP_MULTIPLY: |
232 | case MP_BINARY_OP_INPLACE_MULTIPLY: |
233 | mpz_mul_inpl(&res->mpz, zlhs, zrhs); |
234 | break; |
235 | case MP_BINARY_OP_FLOOR_DIVIDE: |
236 | case MP_BINARY_OP_INPLACE_FLOOR_DIVIDE: { |
237 | if (mpz_is_zero(zrhs)) { |
238 | zero_division_error: |
239 | mp_raise_msg(&mp_type_ZeroDivisionError, MP_ERROR_TEXT("divide by zero" )); |
240 | } |
241 | mpz_t rem; |
242 | mpz_init_zero(&rem); |
243 | mpz_divmod_inpl(&res->mpz, &rem, zlhs, zrhs); |
244 | mpz_deinit(&rem); |
245 | break; |
246 | } |
247 | case MP_BINARY_OP_MODULO: |
248 | case MP_BINARY_OP_INPLACE_MODULO: { |
249 | if (mpz_is_zero(zrhs)) { |
250 | goto zero_division_error; |
251 | } |
252 | mpz_t quo; |
253 | mpz_init_zero(&quo); |
254 | mpz_divmod_inpl(&quo, &res->mpz, zlhs, zrhs); |
255 | mpz_deinit(&quo); |
256 | break; |
257 | } |
258 | |
259 | case MP_BINARY_OP_AND: |
260 | case MP_BINARY_OP_INPLACE_AND: |
261 | mpz_and_inpl(&res->mpz, zlhs, zrhs); |
262 | break; |
263 | case MP_BINARY_OP_OR: |
264 | case MP_BINARY_OP_INPLACE_OR: |
265 | mpz_or_inpl(&res->mpz, zlhs, zrhs); |
266 | break; |
267 | case MP_BINARY_OP_XOR: |
268 | case MP_BINARY_OP_INPLACE_XOR: |
269 | mpz_xor_inpl(&res->mpz, zlhs, zrhs); |
270 | break; |
271 | |
272 | case MP_BINARY_OP_LSHIFT: |
273 | case MP_BINARY_OP_INPLACE_LSHIFT: |
274 | case MP_BINARY_OP_RSHIFT: |
275 | case MP_BINARY_OP_INPLACE_RSHIFT: { |
276 | mp_int_t irhs = mp_obj_int_get_checked(rhs_in); |
277 | if (irhs < 0) { |
278 | mp_raise_ValueError(MP_ERROR_TEXT("negative shift count" )); |
279 | } |
280 | if (op == MP_BINARY_OP_LSHIFT || op == MP_BINARY_OP_INPLACE_LSHIFT) { |
281 | mpz_shl_inpl(&res->mpz, zlhs, irhs); |
282 | } else { |
283 | mpz_shr_inpl(&res->mpz, zlhs, irhs); |
284 | } |
285 | break; |
286 | } |
287 | |
288 | case MP_BINARY_OP_POWER: |
289 | case MP_BINARY_OP_INPLACE_POWER: |
290 | if (mpz_is_neg(zrhs)) { |
291 | #if MICROPY_PY_BUILTINS_FLOAT |
292 | return mp_obj_float_binary_op(op, mpz_as_float(zlhs), rhs_in); |
293 | #else |
294 | mp_raise_ValueError(MP_ERROR_TEXT("negative power with no float support" )); |
295 | #endif |
296 | } |
297 | mpz_pow_inpl(&res->mpz, zlhs, zrhs); |
298 | break; |
299 | |
300 | default: { |
301 | assert(op == MP_BINARY_OP_DIVMOD); |
302 | if (mpz_is_zero(zrhs)) { |
303 | goto zero_division_error; |
304 | } |
305 | mp_obj_int_t *quo = mp_obj_int_new_mpz(); |
306 | mpz_divmod_inpl(&quo->mpz, &res->mpz, zlhs, zrhs); |
307 | mp_obj_t tuple[2] = {MP_OBJ_FROM_PTR(quo), MP_OBJ_FROM_PTR(res)}; |
308 | return mp_obj_new_tuple(2, tuple); |
309 | } |
310 | } |
311 | |
312 | return MP_OBJ_FROM_PTR(res); |
313 | |
314 | } else { |
315 | int cmp = mpz_cmp(zlhs, zrhs); |
316 | switch (op) { |
317 | case MP_BINARY_OP_LESS: |
318 | return mp_obj_new_bool(cmp < 0); |
319 | case MP_BINARY_OP_MORE: |
320 | return mp_obj_new_bool(cmp > 0); |
321 | case MP_BINARY_OP_LESS_EQUAL: |
322 | return mp_obj_new_bool(cmp <= 0); |
323 | case MP_BINARY_OP_MORE_EQUAL: |
324 | return mp_obj_new_bool(cmp >= 0); |
325 | case MP_BINARY_OP_EQUAL: |
326 | return mp_obj_new_bool(cmp == 0); |
327 | |
328 | default: |
329 | return MP_OBJ_NULL; // op not supported |
330 | } |
331 | } |
332 | } |
333 | |
334 | #if MICROPY_PY_BUILTINS_POW3 |
335 | STATIC mpz_t *mp_mpz_for_int(mp_obj_t arg, mpz_t *temp) { |
336 | if (mp_obj_is_small_int(arg)) { |
337 | mpz_init_from_int(temp, MP_OBJ_SMALL_INT_VALUE(arg)); |
338 | return temp; |
339 | } else { |
340 | mp_obj_int_t *arp_p = MP_OBJ_TO_PTR(arg); |
341 | return &(arp_p->mpz); |
342 | } |
343 | } |
344 | |
345 | mp_obj_t mp_obj_int_pow3(mp_obj_t base, mp_obj_t exponent, mp_obj_t modulus) { |
346 | if (!mp_obj_is_int(base) || !mp_obj_is_int(exponent) || !mp_obj_is_int(modulus)) { |
347 | mp_raise_TypeError(MP_ERROR_TEXT("pow() with 3 arguments requires integers" )); |
348 | } else { |
349 | mp_obj_t result = mp_obj_new_int_from_ull(0); // Use the _from_ull version as this forces an mpz int |
350 | mp_obj_int_t *res_p = (mp_obj_int_t *)MP_OBJ_TO_PTR(result); |
351 | |
352 | mpz_t l_temp, r_temp, m_temp; |
353 | mpz_t *lhs = mp_mpz_for_int(base, &l_temp); |
354 | mpz_t *rhs = mp_mpz_for_int(exponent, &r_temp); |
355 | mpz_t *mod = mp_mpz_for_int(modulus, &m_temp); |
356 | |
357 | mpz_pow3_inpl(&(res_p->mpz), lhs, rhs, mod); |
358 | |
359 | if (lhs == &l_temp) { |
360 | mpz_deinit(lhs); |
361 | } |
362 | if (rhs == &r_temp) { |
363 | mpz_deinit(rhs); |
364 | } |
365 | if (mod == &m_temp) { |
366 | mpz_deinit(mod); |
367 | } |
368 | return result; |
369 | } |
370 | } |
371 | #endif |
372 | |
373 | mp_obj_t mp_obj_new_int(mp_int_t value) { |
374 | if (MP_SMALL_INT_FITS(value)) { |
375 | return MP_OBJ_NEW_SMALL_INT(value); |
376 | } |
377 | return mp_obj_new_int_from_ll(value); |
378 | } |
379 | |
380 | mp_obj_t mp_obj_new_int_from_ll(long long val) { |
381 | mp_obj_int_t *o = mp_obj_int_new_mpz(); |
382 | mpz_set_from_ll(&o->mpz, val, true); |
383 | return MP_OBJ_FROM_PTR(o); |
384 | } |
385 | |
386 | mp_obj_t mp_obj_new_int_from_ull(unsigned long long val) { |
387 | mp_obj_int_t *o = mp_obj_int_new_mpz(); |
388 | mpz_set_from_ll(&o->mpz, val, false); |
389 | return MP_OBJ_FROM_PTR(o); |
390 | } |
391 | |
392 | mp_obj_t mp_obj_new_int_from_uint(mp_uint_t value) { |
393 | // SMALL_INT accepts only signed numbers, so make sure the input |
394 | // value fits completely in the small-int positive range. |
395 | if ((value & ~MP_SMALL_INT_POSITIVE_MASK) == 0) { |
396 | return MP_OBJ_NEW_SMALL_INT(value); |
397 | } |
398 | return mp_obj_new_int_from_ull(value); |
399 | } |
400 | |
401 | mp_obj_t mp_obj_new_int_from_str_len(const char **str, size_t len, bool neg, unsigned int base) { |
402 | mp_obj_int_t *o = mp_obj_int_new_mpz(); |
403 | size_t n = mpz_set_from_str(&o->mpz, *str, len, neg, base); |
404 | *str += n; |
405 | return MP_OBJ_FROM_PTR(o); |
406 | } |
407 | |
408 | mp_int_t mp_obj_int_get_truncated(mp_const_obj_t self_in) { |
409 | if (mp_obj_is_small_int(self_in)) { |
410 | return MP_OBJ_SMALL_INT_VALUE(self_in); |
411 | } else { |
412 | const mp_obj_int_t *self = MP_OBJ_TO_PTR(self_in); |
413 | // hash returns actual int value if it fits in mp_int_t |
414 | return mpz_hash(&self->mpz); |
415 | } |
416 | } |
417 | |
418 | mp_int_t mp_obj_int_get_checked(mp_const_obj_t self_in) { |
419 | if (mp_obj_is_small_int(self_in)) { |
420 | return MP_OBJ_SMALL_INT_VALUE(self_in); |
421 | } else { |
422 | const mp_obj_int_t *self = MP_OBJ_TO_PTR(self_in); |
423 | mp_int_t value; |
424 | if (mpz_as_int_checked(&self->mpz, &value)) { |
425 | return value; |
426 | } else { |
427 | // overflow |
428 | mp_raise_msg(&mp_type_OverflowError, MP_ERROR_TEXT("overflow converting long int to machine word" )); |
429 | } |
430 | } |
431 | } |
432 | |
433 | mp_uint_t mp_obj_int_get_uint_checked(mp_const_obj_t self_in) { |
434 | if (mp_obj_is_small_int(self_in)) { |
435 | if (MP_OBJ_SMALL_INT_VALUE(self_in) >= 0) { |
436 | return MP_OBJ_SMALL_INT_VALUE(self_in); |
437 | } |
438 | } else { |
439 | const mp_obj_int_t *self = MP_OBJ_TO_PTR(self_in); |
440 | mp_uint_t value; |
441 | if (mpz_as_uint_checked(&self->mpz, &value)) { |
442 | return value; |
443 | } |
444 | } |
445 | |
446 | mp_raise_msg(&mp_type_OverflowError, MP_ERROR_TEXT("overflow converting long int to machine word" )); |
447 | } |
448 | |
449 | #if MICROPY_PY_BUILTINS_FLOAT |
450 | mp_float_t mp_obj_int_as_float_impl(mp_obj_t self_in) { |
451 | assert(mp_obj_is_type(self_in, &mp_type_int)); |
452 | mp_obj_int_t *self = MP_OBJ_TO_PTR(self_in); |
453 | return mpz_as_float(&self->mpz); |
454 | } |
455 | #endif |
456 | |
457 | #endif |
458 | |