blob: 6410ecc64d77ffeecb75c1ac3d807fde91afea0d [file] [log] [blame]
Damien George438c88d2014-02-22 19:25:23 +00001#include <stdint.h>
2#include <string.h>
Rachel Dowdall56402792014-03-22 20:19:24 +00003#include <stdio.h>
Damien George438c88d2014-02-22 19:25:23 +00004
5#include "nlr.h"
6#include "misc.h"
7#include "mpconfig.h"
8#include "qstr.h"
Damien George06201ff2014-03-01 19:50:50 +00009#include "parsenumbase.h"
Damien George438c88d2014-02-22 19:25:23 +000010#include "obj.h"
11#include "mpz.h"
12#include "objint.h"
13#include "runtime0.h"
Damien George660aef62014-04-02 12:22:07 +010014#include "runtime.h"
Damien George438c88d2014-02-22 19:25:23 +000015
16#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_MPZ
17
18STATIC mp_obj_int_t *mp_obj_int_new_mpz(void) {
19 mp_obj_int_t *o = m_new_obj(mp_obj_int_t);
Damien George3e1a5c12014-03-29 13:43:38 +000020 o->base.type = &mp_type_int;
Damien George438c88d2014-02-22 19:25:23 +000021 mpz_init_zero(&o->mpz);
22 return o;
23}
24
Dave Hylandsc4029e52014-04-07 11:19:51 -070025// This routine expects you to pass in a buffer and size (in *buf and buf_size).
26// If, for some reason, this buffer is too small, then it will allocate a
27// buffer and return the allocated buffer and size in *buf and *buf_size. It
28// is the callers responsibility to free this allocated buffer.
29//
30// The resulting formatted string will be returned from this function and the
31// formatted size will be in *fmt_size.
32char *mp_obj_int_formatted(char **buf, int *buf_size, int *fmt_size, mp_obj_t self_in,
33 int base, const char *prefix, char base_char, char comma) {
34 mpz_t small_mpz;
35 mpz_t *mpz;
36 mpz_dig_t small_dig[(sizeof(mp_small_int_t) * 8 + MPZ_DIG_SIZE - 1) / MPZ_DIG_SIZE];
37
Damien George438c88d2014-02-22 19:25:23 +000038 if (MP_OBJ_IS_SMALL_INT(self_in)) {
Dave Hylandsc4029e52014-04-07 11:19:51 -070039 mpz_init_fixed_from_int(&small_mpz, small_dig,
40 sizeof(small_dig) / sizeof(small_dig[0]),
41 MP_OBJ_SMALL_INT_VALUE(self_in));
42 mpz = &small_mpz;
Damien George438c88d2014-02-22 19:25:23 +000043 } else {
Damien George438c88d2014-02-22 19:25:23 +000044 mp_obj_int_t *self = self_in;
Dave Hylandsc4029e52014-04-07 11:19:51 -070045 mpz = &self->mpz;
Damien George438c88d2014-02-22 19:25:23 +000046 }
Dave Hylandsc4029e52014-04-07 11:19:51 -070047
48 uint needed_size = mpz_as_str_size_formatted(mpz, base, prefix, comma);
49 if (needed_size > *buf_size) {
50 *buf = m_new(char, needed_size);
51 *buf_size = needed_size;
52 }
53 char *str = *buf;
54
55 *fmt_size = mpz_as_str_inpl(mpz, base, prefix, base_char, comma, str);
56
57 return str;
58}
59
60bool mp_obj_int_is_positive(mp_obj_t self_in) {
61 if (MP_OBJ_IS_SMALL_INT(self_in)) {
62 return MP_OBJ_SMALL_INT_VALUE(self_in) >= 0;
63 }
64 mp_obj_int_t *self = self_in;
65 return !self->mpz.neg;
Damien George438c88d2014-02-22 19:25:23 +000066}
67
Damien Georgee8208a72014-04-04 15:08:23 +010068mp_obj_t mp_obj_int_unary_op(int op, mp_obj_t o_in) {
Damien George438c88d2014-02-22 19:25:23 +000069 mp_obj_int_t *o = o_in;
70 switch (op) {
Damien Georged17926d2014-03-30 13:35:08 +010071 case MP_UNARY_OP_BOOL: return MP_BOOL(!mpz_is_zero(&o->mpz));
72 case MP_UNARY_OP_POSITIVE: return o_in;
73 case MP_UNARY_OP_NEGATIVE: { mp_obj_int_t *o2 = mp_obj_int_new_mpz(); mpz_neg_inpl(&o2->mpz, &o->mpz); return o2; }
74 case MP_UNARY_OP_INVERT: { mp_obj_int_t *o2 = mp_obj_int_new_mpz(); mpz_not_inpl(&o2->mpz, &o->mpz); return o2; }
Damien George438c88d2014-02-22 19:25:23 +000075 default: return NULL; // op not supported
76 }
77}
78
Damien Georgee8208a72014-04-04 15:08:23 +010079mp_obj_t mp_obj_int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
Damien Georgecd8b2ba2014-03-19 23:15:25 +000080 const mpz_t *zlhs;
Damien George06201ff2014-03-01 19:50:50 +000081 const mpz_t *zrhs;
82 mpz_t z_int;
83 mpz_dig_t z_int_dig[MPZ_NUM_DIG_FOR_INT];
Damien George438c88d2014-02-22 19:25:23 +000084
Damien Georgecd8b2ba2014-03-19 23:15:25 +000085 // lhs could be a small int (eg small-int + mpz)
86 if (MP_OBJ_IS_SMALL_INT(lhs_in)) {
87 mpz_init_fixed_from_int(&z_int, z_int_dig, MPZ_NUM_DIG_FOR_INT, MP_OBJ_SMALL_INT_VALUE(lhs_in));
88 zlhs = &z_int;
Damien George3e1a5c12014-03-29 13:43:38 +000089 } else if (MP_OBJ_IS_TYPE(lhs_in, &mp_type_int)) {
Damien Georgecd8b2ba2014-03-19 23:15:25 +000090 zlhs = &((mp_obj_int_t*)lhs_in)->mpz;
91 } else {
Damien George0aa5d512014-03-29 17:28:20 +000092 // unsupported type
Damien Georgecd8b2ba2014-03-19 23:15:25 +000093 return MP_OBJ_NULL;
94 }
95
Damien Georged17926d2014-03-30 13:35:08 +010096 // if rhs is small int, then lhs was not (otherwise mp_binary_op handles it)
Damien George438c88d2014-02-22 19:25:23 +000097 if (MP_OBJ_IS_SMALL_INT(rhs_in)) {
Damien George06201ff2014-03-01 19:50:50 +000098 mpz_init_fixed_from_int(&z_int, z_int_dig, MPZ_NUM_DIG_FOR_INT, MP_OBJ_SMALL_INT_VALUE(rhs_in));
99 zrhs = &z_int;
Damien George3e1a5c12014-03-29 13:43:38 +0000100 } else if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_int)) {
Damien George438c88d2014-02-22 19:25:23 +0000101 zrhs = &((mp_obj_int_t*)rhs_in)->mpz;
Damien George0aa5d512014-03-29 17:28:20 +0000102#if MICROPY_ENABLE_FLOAT
103 } else if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_float)) {
104 return mp_obj_float_binary_op(op, mpz_as_float(zlhs), rhs_in);
105 } else if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_complex)) {
106 return mp_obj_complex_binary_op(op, mpz_as_float(zlhs), 0, rhs_in);
107#endif
Damien George438c88d2014-02-22 19:25:23 +0000108 } else {
Damien Georgee8208a72014-04-04 15:08:23 +0100109 // delegate to generic function to check for extra cases
110 return mp_obj_int_binary_op_extra_cases(op, lhs_in, rhs_in);
Damien George438c88d2014-02-22 19:25:23 +0000111 }
112
Damien George52608102014-03-08 15:04:54 +0000113 if (0) {
114#if MICROPY_ENABLE_FLOAT
Damien Georged17926d2014-03-30 13:35:08 +0100115 } else if (op == MP_BINARY_OP_TRUE_DIVIDE || op == MP_BINARY_OP_INPLACE_TRUE_DIVIDE) {
Damien George52608102014-03-08 15:04:54 +0000116 mp_float_t flhs = mpz_as_float(zlhs);
117 mp_float_t frhs = mpz_as_float(zrhs);
Damien George438c88d2014-02-22 19:25:23 +0000118 return mp_obj_new_float(flhs / frhs);
Damien George52608102014-03-08 15:04:54 +0000119#endif
Damien George438c88d2014-02-22 19:25:23 +0000120
Damien Georged17926d2014-03-30 13:35:08 +0100121 } else if (op <= MP_BINARY_OP_INPLACE_POWER) {
Damien George438c88d2014-02-22 19:25:23 +0000122 mp_obj_int_t *res = mp_obj_int_new_mpz();
123
124 switch (op) {
Damien Georged17926d2014-03-30 13:35:08 +0100125 case MP_BINARY_OP_ADD:
126 case MP_BINARY_OP_INPLACE_ADD:
Damien George438c88d2014-02-22 19:25:23 +0000127 mpz_add_inpl(&res->mpz, zlhs, zrhs);
128 break;
Damien Georged17926d2014-03-30 13:35:08 +0100129 case MP_BINARY_OP_SUBTRACT:
130 case MP_BINARY_OP_INPLACE_SUBTRACT:
Damien George438c88d2014-02-22 19:25:23 +0000131 mpz_sub_inpl(&res->mpz, zlhs, zrhs);
132 break;
Damien Georged17926d2014-03-30 13:35:08 +0100133 case MP_BINARY_OP_MULTIPLY:
134 case MP_BINARY_OP_INPLACE_MULTIPLY:
Damien George438c88d2014-02-22 19:25:23 +0000135 mpz_mul_inpl(&res->mpz, zlhs, zrhs);
136 break;
Damien Georged17926d2014-03-30 13:35:08 +0100137 case MP_BINARY_OP_FLOOR_DIVIDE:
138 case MP_BINARY_OP_INPLACE_FLOOR_DIVIDE: {
Damien George438c88d2014-02-22 19:25:23 +0000139 mpz_t rem; mpz_init_zero(&rem);
140 mpz_divmod_inpl(&res->mpz, &rem, zlhs, zrhs);
Damien Georgeecf5b772014-04-04 11:13:51 +0000141 if (zlhs->neg != zrhs->neg) {
Rachel Dowdall56402792014-03-22 20:19:24 +0000142 if (!mpz_is_zero(&rem)) {
143 mpz_t mpzone; mpz_init_from_int(&mpzone, -1);
144 mpz_add_inpl(&res->mpz, &res->mpz, &mpzone);
145 }
146 }
Damien George438c88d2014-02-22 19:25:23 +0000147 mpz_deinit(&rem);
148 break;
149 }
Damien Georged17926d2014-03-30 13:35:08 +0100150 case MP_BINARY_OP_MODULO:
151 case MP_BINARY_OP_INPLACE_MODULO: {
Damien George2d7ff072014-03-20 16:28:41 +0000152 mpz_t quo; mpz_init_zero(&quo);
153 mpz_divmod_inpl(&quo, &res->mpz, zlhs, zrhs);
154 mpz_deinit(&quo);
Damien Georgeecf5b772014-04-04 11:13:51 +0000155 // Check signs and do Python style modulo
156 if (zlhs->neg != zrhs->neg) {
Rachel Dowdallcde86312014-03-22 17:29:27 +0000157 mpz_add_inpl(&res->mpz, &res->mpz, zrhs);
158 }
Damien George2d7ff072014-03-20 16:28:41 +0000159 break;
160 }
Damien George438c88d2014-02-22 19:25:23 +0000161
Damien Georged17926d2014-03-30 13:35:08 +0100162 case MP_BINARY_OP_AND:
163 case MP_BINARY_OP_INPLACE_AND:
Paul Sokolovsky57207b82014-03-23 01:52:36 +0200164 mpz_and_inpl(&res->mpz, zlhs, zrhs);
165 break;
Damien Georged17926d2014-03-30 13:35:08 +0100166 case MP_BINARY_OP_OR:
167 case MP_BINARY_OP_INPLACE_OR:
Paul Sokolovsky57207b82014-03-23 01:52:36 +0200168 mpz_or_inpl(&res->mpz, zlhs, zrhs);
169 break;
Damien Georged17926d2014-03-30 13:35:08 +0100170 case MP_BINARY_OP_XOR:
171 case MP_BINARY_OP_INPLACE_XOR:
Paul Sokolovsky57207b82014-03-23 01:52:36 +0200172 mpz_xor_inpl(&res->mpz, zlhs, zrhs);
173 break;
Damien George438c88d2014-02-22 19:25:23 +0000174
Damien Georged17926d2014-03-30 13:35:08 +0100175 case MP_BINARY_OP_LSHIFT:
176 case MP_BINARY_OP_INPLACE_LSHIFT:
177 case MP_BINARY_OP_RSHIFT:
178 case MP_BINARY_OP_INPLACE_RSHIFT: {
Damien George06201ff2014-03-01 19:50:50 +0000179 // TODO check conversion overflow
180 machine_int_t irhs = mpz_as_int(zrhs);
181 if (irhs < 0) {
Damien Georgeea13f402014-04-05 18:32:08 +0100182 nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "negative shift count"));
Damien George06201ff2014-03-01 19:50:50 +0000183 }
Damien Georged17926d2014-03-30 13:35:08 +0100184 if (op == MP_BINARY_OP_LSHIFT || op == MP_BINARY_OP_INPLACE_LSHIFT) {
Damien George06201ff2014-03-01 19:50:50 +0000185 mpz_shl_inpl(&res->mpz, zlhs, irhs);
186 } else {
187 mpz_shr_inpl(&res->mpz, zlhs, irhs);
188 }
189 break;
190 }
Damien George438c88d2014-02-22 19:25:23 +0000191
Damien Georged17926d2014-03-30 13:35:08 +0100192 case MP_BINARY_OP_POWER:
193 case MP_BINARY_OP_INPLACE_POWER:
Damien George438c88d2014-02-22 19:25:23 +0000194 mpz_pow_inpl(&res->mpz, zlhs, zrhs);
195 break;
196
197 default:
198 return MP_OBJ_NULL;
199 }
200
201 return res;
202
203 } else {
204 int cmp = mpz_cmp(zlhs, zrhs);
205 switch (op) {
Damien Georged17926d2014-03-30 13:35:08 +0100206 case MP_BINARY_OP_LESS:
Damien George438c88d2014-02-22 19:25:23 +0000207 return MP_BOOL(cmp < 0);
Damien Georged17926d2014-03-30 13:35:08 +0100208 case MP_BINARY_OP_MORE:
Damien George438c88d2014-02-22 19:25:23 +0000209 return MP_BOOL(cmp > 0);
Damien Georged17926d2014-03-30 13:35:08 +0100210 case MP_BINARY_OP_LESS_EQUAL:
Damien George438c88d2014-02-22 19:25:23 +0000211 return MP_BOOL(cmp <= 0);
Damien Georged17926d2014-03-30 13:35:08 +0100212 case MP_BINARY_OP_MORE_EQUAL:
Damien George438c88d2014-02-22 19:25:23 +0000213 return MP_BOOL(cmp >= 0);
Damien Georged17926d2014-03-30 13:35:08 +0100214 case MP_BINARY_OP_EQUAL:
Damien George438c88d2014-02-22 19:25:23 +0000215 return MP_BOOL(cmp == 0);
Damien Georged17926d2014-03-30 13:35:08 +0100216 case MP_BINARY_OP_NOT_EQUAL:
Damien George438c88d2014-02-22 19:25:23 +0000217 return MP_BOOL(cmp != 0);
218
219 default:
220 return MP_OBJ_NULL;
221 }
222 }
223}
224
225mp_obj_t mp_obj_new_int(machine_int_t value) {
226 if (MP_OBJ_FITS_SMALL_INT(value)) {
227 return MP_OBJ_NEW_SMALL_INT(value);
228 }
229 return mp_obj_new_int_from_ll(value);
230}
231
232mp_obj_t mp_obj_new_int_from_ll(long long val) {
233 mp_obj_int_t *o = mp_obj_int_new_mpz();
Damien George9d68e9c2014-03-12 15:38:15 +0000234 mpz_set_from_ll(&o->mpz, val);
Damien George438c88d2014-02-22 19:25:23 +0000235 return o;
236}
237
238mp_obj_t mp_obj_new_int_from_uint(machine_uint_t value) {
239 // SMALL_INT accepts only signed numbers, of one bit less size
240 // than word size, which totals 2 bits less for unsigned numbers.
241 if ((value & (WORD_MSBIT_HIGH | (WORD_MSBIT_HIGH >> 1))) == 0) {
242 return MP_OBJ_NEW_SMALL_INT(value);
243 }
244 return mp_obj_new_int_from_ll(value);
245}
246
247mp_obj_t mp_obj_new_int_from_long_str(const char *str) {
248 mp_obj_int_t *o = mp_obj_int_new_mpz();
249 uint len = strlen(str);
Damien George06201ff2014-03-01 19:50:50 +0000250 int base = 0;
251 int skip = mp_parse_num_base(str, len, &base);
252 str += skip;
253 len -= skip;
254 uint n = mpz_set_from_str(&o->mpz, str, len, false, base);
Damien George438c88d2014-02-22 19:25:23 +0000255 if (n != len) {
Damien Georgeea13f402014-04-05 18:32:08 +0100256 nlr_raise(mp_obj_new_exception_msg(&mp_type_SyntaxError, "invalid syntax for number"));
Damien George438c88d2014-02-22 19:25:23 +0000257 }
258 return o;
259}
260
261machine_int_t mp_obj_int_get(mp_obj_t self_in) {
262 if (MP_OBJ_IS_SMALL_INT(self_in)) {
263 return MP_OBJ_SMALL_INT_VALUE(self_in);
Damien Georgeeabdf672014-03-22 20:54:01 +0000264 } else {
265 mp_obj_int_t *self = self_in;
266 return mpz_as_int(&self->mpz);
Damien George438c88d2014-02-22 19:25:23 +0000267 }
Damien George438c88d2014-02-22 19:25:23 +0000268}
269
270machine_int_t mp_obj_int_get_checked(mp_obj_t self_in) {
Damien George8270e382014-04-03 11:00:54 +0000271 if (MP_OBJ_IS_SMALL_INT(self_in)) {
272 return MP_OBJ_SMALL_INT_VALUE(self_in);
273 } else {
274 mp_obj_int_t *self = self_in;
275 machine_int_t value;
276 if (mpz_as_int_checked(&self->mpz, &value)) {
277 return value;
278 } else {
279 // overflow
Damien Georgeea13f402014-04-05 18:32:08 +0100280 nlr_raise(mp_obj_new_exception_msg(&mp_type_OverflowError, "overflow converting long int to machine word"));
Damien George8270e382014-04-03 11:00:54 +0000281 }
282 }
Damien George438c88d2014-02-22 19:25:23 +0000283}
284
Damien Georgeeabdf672014-03-22 20:54:01 +0000285#if MICROPY_ENABLE_FLOAT
286mp_float_t mp_obj_int_as_float(mp_obj_t self_in) {
287 if (MP_OBJ_IS_SMALL_INT(self_in)) {
288 return MP_OBJ_SMALL_INT_VALUE(self_in);
289 } else {
290 mp_obj_int_t *self = self_in;
291 return mpz_as_float(&self->mpz);
292 }
293}
294#endif
295
Damien George438c88d2014-02-22 19:25:23 +0000296#endif