objint_mpz.c 11.5 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/*
 * This file is part of the Micro Python project, http://micropython.org/
 *
 * The MIT License (MIT)
 *
 * Copyright (c) 2013, 2014 Damien P. George
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

27
28
#include <stdint.h>
#include <string.h>
29
#include <stdio.h>
30
#include <assert.h>
31

32
#include "mpconfig.h"
33
34
35
#include "nlr.h"
#include "misc.h"
#include "qstr.h"
36
#include "parsenumbase.h"
37
#include "obj.h"
38
#include "smallint.h"
39
40
41
#include "mpz.h"
#include "objint.h"
#include "runtime0.h"
42
#include "runtime.h"
43
44
45

#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_MPZ

46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#if MICROPY_PY_SYS_MAXSIZE
// Export value for sys.maxsize
#define DIG_MASK ((1 << MPZ_DIG_SIZE) - 1)
STATIC const mpz_dig_t maxsize_dig[MPZ_NUM_DIG_FOR_INT] = {
    (INT_MAX >> MPZ_DIG_SIZE * 0) & DIG_MASK,
    (INT_MAX >> MPZ_DIG_SIZE * 1) & DIG_MASK,
    (INT_MAX >> MPZ_DIG_SIZE * 2) & DIG_MASK,
    #if (INT_MAX >> MPZ_DIG_SIZE * 2) > DIG_MASK
    (INT_MAX >> MPZ_DIG_SIZE * 3) & DIG_MASK,
    (INT_MAX >> MPZ_DIG_SIZE * 4) & DIG_MASK,
//    (INT_MAX >> MPZ_DIG_SIZE * 5) & DIG_MASK,
    #endif
};
const mp_obj_int_t mp_maxsize_obj = {
    {&mp_type_int},
    {.fixed_dig = 1, .len = MPZ_NUM_DIG_FOR_INT, .alloc = MPZ_NUM_DIG_FOR_INT, .dig = (mpz_dig_t*)maxsize_dig}
};
#undef DIG_MASK
#endif

66
67
STATIC mp_obj_int_t *mp_obj_int_new_mpz(void) {
    mp_obj_int_t *o = m_new_obj(mp_obj_int_t);
68
    o->base.type = &mp_type_int;
69
70
71
72
    mpz_init_zero(&o->mpz);
    return o;
}

73
74
75
76
77
78
79
// This routine expects you to pass in a buffer and size (in *buf and buf_size).
// If, for some reason, this buffer is too small, then it will allocate a
// buffer and return the allocated buffer and size in *buf and *buf_size. It
// is the callers responsibility to free this allocated buffer.
//
// The resulting formatted string will be returned from this function and the
// formatted size will be in *fmt_size.
80
81
//
// This particular routine should only be called for the mpz representation of the int.
Paul Sokolovsky's avatar
Paul Sokolovsky committed
82
char *mp_obj_int_formatted_impl(char **buf, int *buf_size, int *fmt_size, mp_const_obj_t self_in,
83
84
                                int base, const char *prefix, char base_char, char comma) {
    assert(MP_OBJ_IS_TYPE(self_in, &mp_type_int));
Paul Sokolovsky's avatar
Paul Sokolovsky committed
85
    const mp_obj_int_t *self = self_in;
86

87
    uint needed_size = mpz_as_str_size_formatted(&self->mpz, base, prefix, comma);
88
89
90
91
92
93
    if (needed_size > *buf_size) {
        *buf = m_new(char, needed_size);
        *buf_size = needed_size;
    }
    char *str = *buf;

94
    *fmt_size = mpz_as_str_inpl(&self->mpz, base, prefix, base_char, comma, str);
95
96
97
98

    return str;
}

Damien George's avatar
Damien George committed
99
100
101
102
103
104
105
106
mp_int_t mp_obj_int_hash(mp_obj_t self_in) {
    if (MP_OBJ_IS_SMALL_INT(self_in)) {
        return MP_OBJ_SMALL_INT_VALUE(self_in);
    }
    mp_obj_int_t *self = self_in;
    return mpz_hash(&self->mpz);
}

107
108
109
bool mp_obj_int_is_positive(mp_obj_t self_in) {
    if (MP_OBJ_IS_SMALL_INT(self_in)) {
        return MP_OBJ_SMALL_INT_VALUE(self_in) >= 0;
110
    }
111
112
    mp_obj_int_t *self = self_in;
    return !self->mpz.neg;
113
114
}

115
mp_obj_t mp_obj_int_unary_op(mp_uint_t op, mp_obj_t o_in) {
116
117
    mp_obj_int_t *o = o_in;
    switch (op) {
Damien George's avatar
Damien George committed
118
119
120
121
        case MP_UNARY_OP_BOOL: return MP_BOOL(!mpz_is_zero(&o->mpz));
        case MP_UNARY_OP_POSITIVE: return o_in;
        case MP_UNARY_OP_NEGATIVE: { mp_obj_int_t *o2 = mp_obj_int_new_mpz(); mpz_neg_inpl(&o2->mpz, &o->mpz); return o2; }
        case MP_UNARY_OP_INVERT: { mp_obj_int_t *o2 = mp_obj_int_new_mpz(); mpz_not_inpl(&o2->mpz, &o->mpz); return o2; }
122
        default: return MP_OBJ_NULL; // op not supported
123
124
125
    }
}

126
mp_obj_t mp_obj_int_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
127
    const mpz_t *zlhs;
128
129
130
    const mpz_t *zrhs;
    mpz_t z_int;
    mpz_dig_t z_int_dig[MPZ_NUM_DIG_FOR_INT];
131

132
133
134
135
    // lhs could be a small int (eg small-int + mpz)
    if (MP_OBJ_IS_SMALL_INT(lhs_in)) {
        mpz_init_fixed_from_int(&z_int, z_int_dig, MPZ_NUM_DIG_FOR_INT, MP_OBJ_SMALL_INT_VALUE(lhs_in));
        zlhs = &z_int;
136
    } else if (MP_OBJ_IS_TYPE(lhs_in, &mp_type_int)) {
137
138
        zlhs = &((mp_obj_int_t*)lhs_in)->mpz;
    } else {
139
        // unsupported type
140
        return MP_OBJ_NULL;
141
142
    }

Damien George's avatar
Damien George committed
143
    // if rhs is small int, then lhs was not (otherwise mp_binary_op handles it)
144
    if (MP_OBJ_IS_SMALL_INT(rhs_in)) {
145
146
        mpz_init_fixed_from_int(&z_int, z_int_dig, MPZ_NUM_DIG_FOR_INT, MP_OBJ_SMALL_INT_VALUE(rhs_in));
        zrhs = &z_int;
147
    } else if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_int)) {
148
        zrhs = &((mp_obj_int_t*)rhs_in)->mpz;
149
#if MICROPY_PY_BUILTINS_FLOAT
150
151
    } else if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_float)) {
        return mp_obj_float_binary_op(op, mpz_as_float(zlhs), rhs_in);
152
#if MICROPY_PY_BUILTINS_COMPLEX
153
154
    } else if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_complex)) {
        return mp_obj_complex_binary_op(op, mpz_as_float(zlhs), 0, rhs_in);
155
#endif
156
#endif
157
    } else {
158
159
        // delegate to generic function to check for extra cases
        return mp_obj_int_binary_op_extra_cases(op, lhs_in, rhs_in);
160
161
    }

162
    if (0) {
163
#if MICROPY_PY_BUILTINS_FLOAT
Damien George's avatar
Damien George committed
164
    } else if (op == MP_BINARY_OP_TRUE_DIVIDE || op == MP_BINARY_OP_INPLACE_TRUE_DIVIDE) {
165
166
        mp_float_t flhs = mpz_as_float(zlhs);
        mp_float_t frhs = mpz_as_float(zrhs);
167
        return mp_obj_new_float(flhs / frhs);
168
#endif
169

Damien George's avatar
Damien George committed
170
    } else if (op <= MP_BINARY_OP_INPLACE_POWER) {
171
172
173
        mp_obj_int_t *res = mp_obj_int_new_mpz();

        switch (op) {
Damien George's avatar
Damien George committed
174
175
            case MP_BINARY_OP_ADD:
            case MP_BINARY_OP_INPLACE_ADD:
176
177
                mpz_add_inpl(&res->mpz, zlhs, zrhs);
                break;
Damien George's avatar
Damien George committed
178
179
            case MP_BINARY_OP_SUBTRACT:
            case MP_BINARY_OP_INPLACE_SUBTRACT:
180
181
                mpz_sub_inpl(&res->mpz, zlhs, zrhs);
                break;
Damien George's avatar
Damien George committed
182
183
            case MP_BINARY_OP_MULTIPLY:
            case MP_BINARY_OP_INPLACE_MULTIPLY:
184
185
                mpz_mul_inpl(&res->mpz, zlhs, zrhs);
                break;
Damien George's avatar
Damien George committed
186
187
            case MP_BINARY_OP_FLOOR_DIVIDE:
            case MP_BINARY_OP_INPLACE_FLOOR_DIVIDE: {
188
189
                mpz_t rem; mpz_init_zero(&rem);
                mpz_divmod_inpl(&res->mpz, &rem, zlhs, zrhs);
190
                if (zlhs->neg != zrhs->neg) {
191
192
193
194
195
                    if (!mpz_is_zero(&rem)) {
                        mpz_t mpzone; mpz_init_from_int(&mpzone, -1);
                        mpz_add_inpl(&res->mpz, &res->mpz, &mpzone);
                    }
                }
196
197
198
                mpz_deinit(&rem);
                break;
            }
Damien George's avatar
Damien George committed
199
200
            case MP_BINARY_OP_MODULO:
            case MP_BINARY_OP_INPLACE_MODULO: {
Damien George's avatar
Damien George committed
201
202
203
                mpz_t quo; mpz_init_zero(&quo);
                mpz_divmod_inpl(&quo, &res->mpz, zlhs, zrhs);
                mpz_deinit(&quo);
204
205
                // Check signs and do Python style modulo
                if (zlhs->neg != zrhs->neg) {
206
207
                    mpz_add_inpl(&res->mpz, &res->mpz, zrhs);
                }
Damien George's avatar
Damien George committed
208
209
                break;
            }
210

Damien George's avatar
Damien George committed
211
212
            case MP_BINARY_OP_AND:
            case MP_BINARY_OP_INPLACE_AND:
213
214
                mpz_and_inpl(&res->mpz, zlhs, zrhs);
                break;
Damien George's avatar
Damien George committed
215
216
            case MP_BINARY_OP_OR:
            case MP_BINARY_OP_INPLACE_OR:
217
218
                mpz_or_inpl(&res->mpz, zlhs, zrhs);
                break;
Damien George's avatar
Damien George committed
219
220
            case MP_BINARY_OP_XOR:
            case MP_BINARY_OP_INPLACE_XOR:
221
222
                mpz_xor_inpl(&res->mpz, zlhs, zrhs);
                break;
223

Damien George's avatar
Damien George committed
224
225
226
227
            case MP_BINARY_OP_LSHIFT:
            case MP_BINARY_OP_INPLACE_LSHIFT:
            case MP_BINARY_OP_RSHIFT:
            case MP_BINARY_OP_INPLACE_RSHIFT: {
228
                mp_int_t irhs = mp_obj_int_get_checked(rhs_in);
229
                if (irhs < 0) {
230
                    nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "negative shift count"));
231
                }
Damien George's avatar
Damien George committed
232
                if (op == MP_BINARY_OP_LSHIFT || op == MP_BINARY_OP_INPLACE_LSHIFT) {
233
234
235
236
237
238
                    mpz_shl_inpl(&res->mpz, zlhs, irhs);
                } else {
                    mpz_shr_inpl(&res->mpz, zlhs, irhs);
                }
                break;
            }
239

Damien George's avatar
Damien George committed
240
241
            case MP_BINARY_OP_POWER:
            case MP_BINARY_OP_INPLACE_POWER:
242
243
244
245
                mpz_pow_inpl(&res->mpz, zlhs, zrhs);
                break;

            default:
246
                return MP_OBJ_NULL; // op not supported
247
248
249
250
251
252
253
        }

        return res;

    } else {
        int cmp = mpz_cmp(zlhs, zrhs);
        switch (op) {
Damien George's avatar
Damien George committed
254
            case MP_BINARY_OP_LESS:
255
                return MP_BOOL(cmp < 0);
Damien George's avatar
Damien George committed
256
            case MP_BINARY_OP_MORE:
257
                return MP_BOOL(cmp > 0);
Damien George's avatar
Damien George committed
258
            case MP_BINARY_OP_LESS_EQUAL:
259
                return MP_BOOL(cmp <= 0);
Damien George's avatar
Damien George committed
260
            case MP_BINARY_OP_MORE_EQUAL:
261
                return MP_BOOL(cmp >= 0);
Damien George's avatar
Damien George committed
262
            case MP_BINARY_OP_EQUAL:
263
264
265
                return MP_BOOL(cmp == 0);

            default:
266
                return MP_OBJ_NULL; // op not supported
267
268
269
270
        }
    }
}

271
mp_obj_t mp_obj_new_int(mp_int_t value) {
272
    if (MP_SMALL_INT_FITS(value)) {
273
274
275
276
277
278
279
        return MP_OBJ_NEW_SMALL_INT(value);
    }
    return mp_obj_new_int_from_ll(value);
}

mp_obj_t mp_obj_new_int_from_ll(long long val) {
    mp_obj_int_t *o = mp_obj_int_new_mpz();
280
    mpz_set_from_ll(&o->mpz, val);
281
282
283
    return o;
}

284
mp_obj_t mp_obj_new_int_from_uint(mp_uint_t value) {
285
286
287
288
289
290
291
292
    // SMALL_INT accepts only signed numbers, of one bit less size
    // than word size, which totals 2 bits less for unsigned numbers.
    if ((value & (WORD_MSBIT_HIGH | (WORD_MSBIT_HIGH >> 1))) == 0) {
        return MP_OBJ_NEW_SMALL_INT(value);
    }
    return mp_obj_new_int_from_ll(value);
}

293
mp_obj_t mp_obj_new_int_from_str_len(const char **str, uint len, bool neg, uint base) {
294
    mp_obj_int_t *o = mp_obj_int_new_mpz();
295
296
    uint n = mpz_set_from_str(&o->mpz, *str, len, neg, base);
    *str += n;
297
298
299
    return o;
}

300
mp_int_t mp_obj_int_get(mp_const_obj_t self_in) {
301
302
    if (MP_OBJ_IS_SMALL_INT(self_in)) {
        return MP_OBJ_SMALL_INT_VALUE(self_in);
303
    } else {
304
        const mp_obj_int_t *self = self_in;
305
306
        // TODO this is a hack until we remove mp_obj_int_get function entirely
        return mpz_hash(&self->mpz);
307
308
309
    }
}

310
mp_int_t mp_obj_int_get_checked(mp_const_obj_t self_in) {
311
312
313
    if (MP_OBJ_IS_SMALL_INT(self_in)) {
        return MP_OBJ_SMALL_INT_VALUE(self_in);
    } else {
Paul Sokolovsky's avatar
Paul Sokolovsky committed
314
        const mp_obj_int_t *self = self_in;
315
        mp_int_t value;
316
317
318
319
        if (mpz_as_int_checked(&self->mpz, &value)) {
            return value;
        } else {
            // overflow
320
            nlr_raise(mp_obj_new_exception_msg(&mp_type_OverflowError, "overflow converting long int to machine word"));
321
322
        }
    }
323
324
}

325
#if MICROPY_PY_BUILTINS_FLOAT
326
327
328
329
330
331
332
333
334
335
mp_float_t mp_obj_int_as_float(mp_obj_t self_in) {
    if (MP_OBJ_IS_SMALL_INT(self_in)) {
        return MP_OBJ_SMALL_INT_VALUE(self_in);
    } else {
        mp_obj_int_t *self = self_in;
        return mpz_as_float(&self->mpz);
    }
}
#endif

336
#endif