blob: 3fb2548c4d2705b968b16e5718c1e0fde142231e [file] [log] [blame]
Damien George04b91472014-05-03 23:27:38 +01001/*
2 * This file is part of the Micro Python 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
Damien George438c88d2014-02-22 19:25:23 +000027#include <string.h>
28#include <assert.h>
29
Damien George51dfcb42015-01-01 20:27:54 +000030#include "py/mpz.h"
Damien George438c88d2014-02-22 19:25:23 +000031
32#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_MPZ
33
Damien George06201ff2014-03-01 19:50:50 +000034#define DIG_SIZE (MPZ_DIG_SIZE)
stijn0e557fa2014-10-30 14:39:22 +010035#define DIG_MASK ((MPZ_LONG_1 << DIG_SIZE) - 1)
36#define DIG_MSB (MPZ_LONG_1 << (DIG_SIZE - 1))
37#define DIG_BASE (MPZ_LONG_1 << DIG_SIZE)
Damien George438c88d2014-02-22 19:25:23 +000038
39/*
Damien George06201ff2014-03-01 19:50:50 +000040 mpz is an arbitrary precision integer type with a public API.
41
42 mpn functions act on non-negative integers represented by an array of generalised
43 digits (eg a word per digit). You also need to specify separately the length of the
44 array. There is no public API for mpn. Rather, the functions are used by mpz to
45 implement its features.
46
47 Integer values are stored little endian (first digit is first in memory).
48
49 Definition of normalise: ?
Damien George438c88d2014-02-22 19:25:23 +000050*/
51
52/* compares i with j
53 returns sign(i - j)
54 assumes i, j are normalised
55*/
Damien George42f3de92014-10-03 17:44:14 +000056STATIC int mpn_cmp(const mpz_dig_t *idig, mp_uint_t ilen, const mpz_dig_t *jdig, mp_uint_t jlen) {
Damien George438c88d2014-02-22 19:25:23 +000057 if (ilen < jlen) { return -1; }
58 if (ilen > jlen) { return 1; }
59
60 for (idig += ilen, jdig += ilen; ilen > 0; --ilen) {
Damien George9a21d2e2014-09-06 17:15:34 +010061 mpz_dbl_dig_signed_t cmp = (mpz_dbl_dig_t)*(--idig) - (mpz_dbl_dig_t)*(--jdig);
Damien George438c88d2014-02-22 19:25:23 +000062 if (cmp < 0) { return -1; }
63 if (cmp > 0) { return 1; }
64 }
65
66 return 0;
67}
68
Damien Georgec5ac2ac2014-02-26 16:56:30 +000069/* computes i = j << n
70 returns number of digits in i
Damien George06201ff2014-03-01 19:50:50 +000071 assumes enough memory in i; assumes normalised j; assumes n > 0
Damien Georgec5ac2ac2014-02-26 16:56:30 +000072 can have i, j pointing to same memory
73*/
Damien Georgeafb1cf72014-09-05 20:37:06 +010074STATIC mp_uint_t mpn_shl(mpz_dig_t *idig, mpz_dig_t *jdig, mp_uint_t jlen, mp_uint_t n) {
75 mp_uint_t n_whole = (n + DIG_SIZE - 1) / DIG_SIZE;
76 mp_uint_t n_part = n % DIG_SIZE;
Damien Georgebb4a43f2014-03-12 15:36:06 +000077 if (n_part == 0) {
78 n_part = DIG_SIZE;
79 }
Damien Georgec5ac2ac2014-02-26 16:56:30 +000080
Damien George06201ff2014-03-01 19:50:50 +000081 // start from the high end of the digit arrays
82 idig += jlen + n_whole - 1;
83 jdig += jlen - 1;
Damien Georgec5ac2ac2014-02-26 16:56:30 +000084
Damien George06201ff2014-03-01 19:50:50 +000085 // shift the digits
86 mpz_dbl_dig_t d = 0;
Damien Georgeafb1cf72014-09-05 20:37:06 +010087 for (mp_uint_t i = jlen; i > 0; i--, idig--, jdig--) {
Damien George06201ff2014-03-01 19:50:50 +000088 d |= *jdig;
Damien George5d9b8162014-08-07 14:27:48 +000089 *idig = (d >> (DIG_SIZE - n_part)) & DIG_MASK;
Damien George06201ff2014-03-01 19:50:50 +000090 d <<= DIG_SIZE;
Damien Georgec5ac2ac2014-02-26 16:56:30 +000091 }
92
Damien George06201ff2014-03-01 19:50:50 +000093 // store remaining bits
Damien George5d9b8162014-08-07 14:27:48 +000094 *idig = (d >> (DIG_SIZE - n_part)) & DIG_MASK;
Damien George06201ff2014-03-01 19:50:50 +000095 idig -= n_whole - 1;
Damien Georgebb4a43f2014-03-12 15:36:06 +000096 memset(idig, 0, (n_whole - 1) * sizeof(mpz_dig_t));
Damien George06201ff2014-03-01 19:50:50 +000097
98 // work out length of result
99 jlen += n_whole;
Damien Georgef66ee4d2015-04-22 23:16:49 +0100100 while (jlen != 0 && idig[jlen - 1] == 0) {
Damien George06201ff2014-03-01 19:50:50 +0000101 jlen--;
Damien Georgec5ac2ac2014-02-26 16:56:30 +0000102 }
103
Damien George06201ff2014-03-01 19:50:50 +0000104 // return length of result
Damien Georgec5ac2ac2014-02-26 16:56:30 +0000105 return jlen;
106}
Damien Georgec5ac2ac2014-02-26 16:56:30 +0000107
Damien George438c88d2014-02-22 19:25:23 +0000108/* computes i = j >> n
109 returns number of digits in i
Damien George06201ff2014-03-01 19:50:50 +0000110 assumes enough memory in i; assumes normalised j; assumes n > 0
Damien George438c88d2014-02-22 19:25:23 +0000111 can have i, j pointing to same memory
112*/
Damien Georgeafb1cf72014-09-05 20:37:06 +0100113STATIC mp_uint_t mpn_shr(mpz_dig_t *idig, mpz_dig_t *jdig, mp_uint_t jlen, mp_uint_t n) {
114 mp_uint_t n_whole = n / DIG_SIZE;
115 mp_uint_t n_part = n % DIG_SIZE;
Damien George438c88d2014-02-22 19:25:23 +0000116
117 if (n_whole >= jlen) {
118 return 0;
119 }
120
121 jdig += n_whole;
122 jlen -= n_whole;
123
Damien Georgeafb1cf72014-09-05 20:37:06 +0100124 for (mp_uint_t i = jlen; i > 0; i--, idig++, jdig++) {
Damien George438c88d2014-02-22 19:25:23 +0000125 mpz_dbl_dig_t d = *jdig;
Damien Georgec5ac2ac2014-02-26 16:56:30 +0000126 if (i > 1) {
Damien George9a21d2e2014-09-06 17:15:34 +0100127 d |= (mpz_dbl_dig_t)jdig[1] << DIG_SIZE;
Damien Georgec5ac2ac2014-02-26 16:56:30 +0000128 }
Damien George438c88d2014-02-22 19:25:23 +0000129 d >>= n_part;
130 *idig = d & DIG_MASK;
131 }
132
133 if (idig[-1] == 0) {
Damien George06201ff2014-03-01 19:50:50 +0000134 jlen--;
Damien George438c88d2014-02-22 19:25:23 +0000135 }
136
137 return jlen;
138}
139
140/* computes i = j + k
141 returns number of digits in i
142 assumes enough memory in i; assumes normalised j, k; assumes jlen >= klen
143 can have i, j, k pointing to same memory
144*/
Damien Georgeafb1cf72014-09-05 20:37:06 +0100145STATIC mp_uint_t mpn_add(mpz_dig_t *idig, const mpz_dig_t *jdig, mp_uint_t jlen, const mpz_dig_t *kdig, mp_uint_t klen) {
Damien George438c88d2014-02-22 19:25:23 +0000146 mpz_dig_t *oidig = idig;
147 mpz_dbl_dig_t carry = 0;
148
149 jlen -= klen;
150
151 for (; klen > 0; --klen, ++idig, ++jdig, ++kdig) {
Damien George9a21d2e2014-09-06 17:15:34 +0100152 carry += (mpz_dbl_dig_t)*jdig + (mpz_dbl_dig_t)*kdig;
Damien George438c88d2014-02-22 19:25:23 +0000153 *idig = carry & DIG_MASK;
154 carry >>= DIG_SIZE;
155 }
156
157 for (; jlen > 0; --jlen, ++idig, ++jdig) {
158 carry += *jdig;
159 *idig = carry & DIG_MASK;
160 carry >>= DIG_SIZE;
161 }
162
163 if (carry != 0) {
164 *idig++ = carry;
165 }
166
167 return idig - oidig;
168}
169
170/* computes i = j - k
171 returns number of digits in i
172 assumes enough memory in i; assumes normalised j, k; assumes j >= k
173 can have i, j, k pointing to same memory
174*/
Damien Georgeafb1cf72014-09-05 20:37:06 +0100175STATIC mp_uint_t mpn_sub(mpz_dig_t *idig, const mpz_dig_t *jdig, mp_uint_t jlen, const mpz_dig_t *kdig, mp_uint_t klen) {
Damien George438c88d2014-02-22 19:25:23 +0000176 mpz_dig_t *oidig = idig;
177 mpz_dbl_dig_signed_t borrow = 0;
178
179 jlen -= klen;
180
181 for (; klen > 0; --klen, ++idig, ++jdig, ++kdig) {
Damien George9a21d2e2014-09-06 17:15:34 +0100182 borrow += (mpz_dbl_dig_t)*jdig - (mpz_dbl_dig_t)*kdig;
Damien George438c88d2014-02-22 19:25:23 +0000183 *idig = borrow & DIG_MASK;
184 borrow >>= DIG_SIZE;
185 }
186
Damien Georgeaca14122014-02-24 21:32:52 +0000187 for (; jlen > 0; --jlen, ++idig, ++jdig) {
Damien George438c88d2014-02-22 19:25:23 +0000188 borrow += *jdig;
189 *idig = borrow & DIG_MASK;
190 borrow >>= DIG_SIZE;
191 }
192
193 for (--idig; idig >= oidig && *idig == 0; --idig) {
194 }
195
196 return idig + 1 - oidig;
197}
198
Doug Currie2e2e15c2016-01-30 22:35:58 -0500199STATIC mp_uint_t mpn_remove_trailing_zeros(mpz_dig_t *oidig, mpz_dig_t *idig) {
200 for (--idig; idig >= oidig && *idig == 0; --idig) {
201 }
202 return idig + 1 - oidig;
203}
204
205#if MICROPY_OPT_MPZ_BITWISE
206
Paul Sokolovsky57207b82014-03-23 01:52:36 +0200207/* computes i = j & k
208 returns number of digits in i
Damien Georgeff8dd3f2015-01-20 12:47:20 +0000209 assumes enough memory in i; assumes normalised j, k; assumes jlen >= klen (jlen argument not needed)
Paul Sokolovsky57207b82014-03-23 01:52:36 +0200210 can have i, j, k pointing to same memory
211*/
Damien Georgeff8dd3f2015-01-20 12:47:20 +0000212STATIC mp_uint_t mpn_and(mpz_dig_t *idig, const mpz_dig_t *jdig, const mpz_dig_t *kdig, mp_uint_t klen) {
Paul Sokolovsky57207b82014-03-23 01:52:36 +0200213 mpz_dig_t *oidig = idig;
214
Paul Sokolovsky57207b82014-03-23 01:52:36 +0200215 for (; klen > 0; --klen, ++idig, ++jdig, ++kdig) {
216 *idig = *jdig & *kdig;
217 }
218
Doug Currie2e2e15c2016-01-30 22:35:58 -0500219 return mpn_remove_trailing_zeros(oidig, idig);
Paul Sokolovsky57207b82014-03-23 01:52:36 +0200220}
221
Doug Currie2e2e15c2016-01-30 22:35:58 -0500222#endif
223
224/* i = -((-j) & (-k)) = ~((~j + 1) & (~k + 1)) + 1
225 i = (j & (-k)) = (j & (~k + 1)) = ( j & (~k + 1))
226 i = ((-j) & k) = ((~j + 1) & k) = ((~j + 1) & k )
227 computes general form:
228 i = (im ^ (((j ^ jm) + jc) & ((k ^ km) + kc))) + ic where Xm = Xc == 0 ? 0 : DIG_MASK
Damien Georgef55cf102014-05-29 15:01:49 +0100229 returns number of digits in i
Doug Currie2e2e15c2016-01-30 22:35:58 -0500230 assumes enough memory in i; assumes normalised j, k; assumes length j >= length k
Damien Georgef55cf102014-05-29 15:01:49 +0100231 can have i, j, k pointing to same memory
232*/
Doug Currie2e2e15c2016-01-30 22:35:58 -0500233STATIC mp_uint_t mpn_and_neg(mpz_dig_t *idig, const mpz_dig_t *jdig, mp_uint_t jlen, const mpz_dig_t *kdig, mp_uint_t klen,
234 mpz_dbl_dig_t carryi, mpz_dbl_dig_t carryj, mpz_dbl_dig_t carryk) {
Damien Georgef55cf102014-05-29 15:01:49 +0100235 mpz_dig_t *oidig = idig;
Doug Currie2e2e15c2016-01-30 22:35:58 -0500236 mpz_dig_t imask = (0 == carryi) ? 0 : DIG_MASK;
237 mpz_dig_t jmask = (0 == carryj) ? 0 : DIG_MASK;
238 mpz_dig_t kmask = (0 == carryk) ? 0 : DIG_MASK;
Damien Georgef55cf102014-05-29 15:01:49 +0100239
Doug Currie2e2e15c2016-01-30 22:35:58 -0500240 for (; jlen > 0; ++idig, ++jdig) {
241 carryj += *jdig ^ jmask;
242 carryk += (--klen <= --jlen) ? (*kdig++ ^ kmask) : kmask;
243 carryi += ((carryj & carryk) ^ imask) & DIG_MASK;
244 *idig = carryi & DIG_MASK;
245 carryk >>= DIG_SIZE;
246 carryj >>= DIG_SIZE;
247 carryi >>= DIG_SIZE;
Damien Georgef55cf102014-05-29 15:01:49 +0100248 }
249
Doug Currie2e2e15c2016-01-30 22:35:58 -0500250 if (0 != carryi) {
251 *idig++ = carryi;
Damien Georgef55cf102014-05-29 15:01:49 +0100252 }
253
Doug Currie2e2e15c2016-01-30 22:35:58 -0500254 return mpn_remove_trailing_zeros(oidig, idig);
Damien Georgef55cf102014-05-29 15:01:49 +0100255}
256
Doug Currie2e2e15c2016-01-30 22:35:58 -0500257#if MICROPY_OPT_MPZ_BITWISE
258
Paul Sokolovsky57207b82014-03-23 01:52:36 +0200259/* computes i = j | k
260 returns number of digits in i
261 assumes enough memory in i; assumes normalised j, k; assumes jlen >= klen
262 can have i, j, k pointing to same memory
263*/
Damien Georgeafb1cf72014-09-05 20:37:06 +0100264STATIC mp_uint_t mpn_or(mpz_dig_t *idig, const mpz_dig_t *jdig, mp_uint_t jlen, const mpz_dig_t *kdig, mp_uint_t klen) {
Paul Sokolovsky57207b82014-03-23 01:52:36 +0200265 mpz_dig_t *oidig = idig;
266
267 jlen -= klen;
268
269 for (; klen > 0; --klen, ++idig, ++jdig, ++kdig) {
270 *idig = *jdig | *kdig;
271 }
272
273 for (; jlen > 0; --jlen, ++idig, ++jdig) {
274 *idig = *jdig;
275 }
276
277 return idig - oidig;
278}
279
Doug Currie2e2e15c2016-01-30 22:35:58 -0500280#endif
281
282/* i = -((-j) | (-k)) = ~((~j + 1) | (~k + 1)) + 1
283 i = -(j | (-k)) = -(j | (~k + 1)) = ~( j | (~k + 1)) + 1
284 i = -((-j) | k) = -((~j + 1) | k) = ~((~j + 1) | k ) + 1
285 computes general form:
286 i = ~(((j ^ jm) + jc) | ((k ^ km) + kc)) + 1 where Xm = Xc == 0 ? 0 : DIG_MASK
287 returns number of digits in i
288 assumes enough memory in i; assumes normalised j, k; assumes length j >= length k
289 can have i, j, k pointing to same memory
290*/
291
292#if MICROPY_OPT_MPZ_BITWISE
293
294STATIC mp_uint_t mpn_or_neg(mpz_dig_t *idig, const mpz_dig_t *jdig, mp_uint_t jlen, const mpz_dig_t *kdig, mp_uint_t klen,
295 mpz_dbl_dig_t carryj, mpz_dbl_dig_t carryk) {
296 mpz_dig_t *oidig = idig;
297 mpz_dbl_dig_t carryi = 1;
298 mpz_dig_t jmask = (0 == carryj) ? 0 : DIG_MASK;
299 mpz_dig_t kmask = (0 == carryk) ? 0 : DIG_MASK;
300
301 for (; jlen > 0; ++idig, ++jdig) {
302 carryj += *jdig ^ jmask;
303 carryk += (--klen <= --jlen) ? (*kdig++ ^ kmask) : kmask;
304 carryi += ((carryj | carryk) ^ DIG_MASK) & DIG_MASK;
305 *idig = carryi & DIG_MASK;
306 carryk >>= DIG_SIZE;
307 carryj >>= DIG_SIZE;
308 carryi >>= DIG_SIZE;
309 }
310
311 if (0 != carryi) {
312 *idig++ = carryi;
313 }
314
315 return mpn_remove_trailing_zeros(oidig, idig);
316}
317
318#else
319
320STATIC mp_uint_t mpn_or_neg(mpz_dig_t *idig, const mpz_dig_t *jdig, mp_uint_t jlen, const mpz_dig_t *kdig, mp_uint_t klen,
321 mpz_dbl_dig_t carryi, mpz_dbl_dig_t carryj, mpz_dbl_dig_t carryk) {
322 mpz_dig_t *oidig = idig;
323 mpz_dig_t imask = (0 == carryi) ? 0 : DIG_MASK;
324 mpz_dig_t jmask = (0 == carryj) ? 0 : DIG_MASK;
325 mpz_dig_t kmask = (0 == carryk) ? 0 : DIG_MASK;
326
327 for (; jlen > 0; ++idig, ++jdig) {
328 carryj += *jdig ^ jmask;
329 carryk += (--klen <= --jlen) ? (*kdig++ ^ kmask) : kmask;
330 carryi += ((carryj | carryk) ^ imask) & DIG_MASK;
331 *idig = carryi & DIG_MASK;
332 carryk >>= DIG_SIZE;
333 carryj >>= DIG_SIZE;
334 carryi >>= DIG_SIZE;
335 }
336
337 if (0 != carryi) {
338 *idig++ = carryi;
339 }
340
341 return mpn_remove_trailing_zeros(oidig, idig);
342}
343
344#endif
345
346#if MICROPY_OPT_MPZ_BITWISE
347
Paul Sokolovsky57207b82014-03-23 01:52:36 +0200348/* computes i = j ^ k
349 returns number of digits in i
350 assumes enough memory in i; assumes normalised j, k; assumes jlen >= klen
351 can have i, j, k pointing to same memory
352*/
Damien Georgeafb1cf72014-09-05 20:37:06 +0100353STATIC mp_uint_t mpn_xor(mpz_dig_t *idig, const mpz_dig_t *jdig, mp_uint_t jlen, const mpz_dig_t *kdig, mp_uint_t klen) {
Paul Sokolovsky57207b82014-03-23 01:52:36 +0200354 mpz_dig_t *oidig = idig;
355
356 jlen -= klen;
357
358 for (; klen > 0; --klen, ++idig, ++jdig, ++kdig) {
359 *idig = *jdig ^ *kdig;
360 }
361
362 for (; jlen > 0; --jlen, ++idig, ++jdig) {
363 *idig = *jdig;
364 }
365
Doug Currie2e2e15c2016-01-30 22:35:58 -0500366 return mpn_remove_trailing_zeros(oidig, idig);
367}
368
369#endif
370
371/* i = (-j) ^ (-k) = ~(j - 1) ^ ~(k - 1) = (j - 1) ^ (k - 1)
372 i = -(j ^ (-k)) = -(j ^ ~(k - 1)) = ~(j ^ ~(k - 1)) + 1 = (j ^ (k - 1)) + 1
373 i = -((-j) ^ k) = -(~(j - 1) ^ k) = ~(~(j - 1) ^ k) + 1 = ((j - 1) ^ k) + 1
374 computes general form:
375 i = ((j - 1 + jc) ^ (k - 1 + kc)) + ic
376 returns number of digits in i
377 assumes enough memory in i; assumes normalised j, k; assumes length j >= length k
378 can have i, j, k pointing to same memory
379*/
380STATIC mp_uint_t mpn_xor_neg(mpz_dig_t *idig, const mpz_dig_t *jdig, mp_uint_t jlen, const mpz_dig_t *kdig, mp_uint_t klen,
381 mpz_dbl_dig_t carryi, mpz_dbl_dig_t carryj, mpz_dbl_dig_t carryk) {
382 mpz_dig_t *oidig = idig;
383
384 for (; jlen > 0; ++idig, ++jdig) {
385 carryj += *jdig + DIG_MASK;
386 carryk += (--klen <= --jlen) ? (*kdig++ + DIG_MASK) : DIG_MASK;
387 carryi += (carryj ^ carryk) & DIG_MASK;
388 *idig = carryi & DIG_MASK;
389 carryk >>= DIG_SIZE;
390 carryj >>= DIG_SIZE;
391 carryi >>= DIG_SIZE;
Paul Sokolovskyb3be4712015-11-22 22:03:18 +0200392 }
393
Doug Currie2e2e15c2016-01-30 22:35:58 -0500394 if (0 != carryi) {
395 *idig++ = carryi;
396 }
397
398 return mpn_remove_trailing_zeros(oidig, idig);
Paul Sokolovsky57207b82014-03-23 01:52:36 +0200399}
400
Damien George438c88d2014-02-22 19:25:23 +0000401/* computes i = i * d1 + d2
402 returns number of digits in i
403 assumes enough memory in i; assumes normalised i; assumes dmul != 0
404*/
Damien Georgeafb1cf72014-09-05 20:37:06 +0100405STATIC mp_uint_t mpn_mul_dig_add_dig(mpz_dig_t *idig, mp_uint_t ilen, mpz_dig_t dmul, mpz_dig_t dadd) {
Damien George438c88d2014-02-22 19:25:23 +0000406 mpz_dig_t *oidig = idig;
407 mpz_dbl_dig_t carry = dadd;
408
409 for (; ilen > 0; --ilen, ++idig) {
Damien George9a21d2e2014-09-06 17:15:34 +0100410 carry += (mpz_dbl_dig_t)*idig * (mpz_dbl_dig_t)dmul; // will never overflow so long as DIG_SIZE <= 8*sizeof(mpz_dbl_dig_t)/2
Damien George438c88d2014-02-22 19:25:23 +0000411 *idig = carry & DIG_MASK;
412 carry >>= DIG_SIZE;
413 }
414
415 if (carry != 0) {
416 *idig++ = carry;
417 }
418
419 return idig - oidig;
420}
421
422/* computes i = j * k
423 returns number of digits in i
424 assumes enough memory in i; assumes i is zeroed; assumes normalised j, k
425 can have j, k point to same memory
426*/
Damien Georgeafb1cf72014-09-05 20:37:06 +0100427STATIC mp_uint_t mpn_mul(mpz_dig_t *idig, mpz_dig_t *jdig, mp_uint_t jlen, mpz_dig_t *kdig, mp_uint_t klen) {
Damien George438c88d2014-02-22 19:25:23 +0000428 mpz_dig_t *oidig = idig;
Damien Georgeafb1cf72014-09-05 20:37:06 +0100429 mp_uint_t ilen = 0;
Damien George438c88d2014-02-22 19:25:23 +0000430
431 for (; klen > 0; --klen, ++idig, ++kdig) {
432 mpz_dig_t *id = idig;
433 mpz_dbl_dig_t carry = 0;
434
Damien Georgeafb1cf72014-09-05 20:37:06 +0100435 mp_uint_t jl = jlen;
Damien George438c88d2014-02-22 19:25:23 +0000436 for (mpz_dig_t *jd = jdig; jl > 0; --jl, ++jd, ++id) {
Damien George9a21d2e2014-09-06 17:15:34 +0100437 carry += (mpz_dbl_dig_t)*id + (mpz_dbl_dig_t)*jd * (mpz_dbl_dig_t)*kdig; // will never overflow so long as DIG_SIZE <= 8*sizeof(mpz_dbl_dig_t)/2
Damien George438c88d2014-02-22 19:25:23 +0000438 *id = carry & DIG_MASK;
439 carry >>= DIG_SIZE;
440 }
441
442 if (carry != 0) {
443 *id++ = carry;
444 }
445
446 ilen = id - oidig;
447 }
448
449 return ilen;
450}
451
452/* natural_div - quo * den + new_num = old_num (ie num is replaced with rem)
453 assumes den != 0
454 assumes num_dig has enough memory to be extended by 1 digit
455 assumes quo_dig has enough memory (as many digits as num)
456 assumes quo_dig is filled with zeros
457 modifies den_dig memory, but restors it to original state at end
458*/
459
Damien George40f3c022014-07-03 13:25:24 +0100460STATIC void mpn_div(mpz_dig_t *num_dig, mp_uint_t *num_len, mpz_dig_t *den_dig, mp_uint_t den_len, mpz_dig_t *quo_dig, mp_uint_t *quo_len) {
Damien George438c88d2014-02-22 19:25:23 +0000461 mpz_dig_t *orig_num_dig = num_dig;
462 mpz_dig_t *orig_quo_dig = quo_dig;
463 mpz_dig_t norm_shift = 0;
464 mpz_dbl_dig_t lead_den_digit;
465
466 // handle simple cases
467 {
Damien George42f3de92014-10-03 17:44:14 +0000468 int cmp = mpn_cmp(num_dig, *num_len, den_dig, den_len);
Damien George438c88d2014-02-22 19:25:23 +0000469 if (cmp == 0) {
470 *num_len = 0;
471 quo_dig[0] = 1;
472 *quo_len = 1;
473 return;
474 } else if (cmp < 0) {
475 // numerator remains the same
476 *quo_len = 0;
477 return;
478 }
479 }
480
481 // count number of leading zeros in leading digit of denominator
482 {
483 mpz_dig_t d = den_dig[den_len - 1];
Damien George9a21d2e2014-09-06 17:15:34 +0100484 while ((d & DIG_MSB) == 0) {
Damien George438c88d2014-02-22 19:25:23 +0000485 d <<= 1;
486 ++norm_shift;
487 }
488 }
489
490 // normalise denomenator (leading bit of leading digit is 1)
491 for (mpz_dig_t *den = den_dig, carry = 0; den < den_dig + den_len; ++den) {
492 mpz_dig_t d = *den;
493 *den = ((d << norm_shift) | carry) & DIG_MASK;
Damien Georgedc3faea2016-05-08 21:38:43 +0100494 carry = (mpz_dbl_dig_t)d >> (DIG_SIZE - norm_shift);
Damien George438c88d2014-02-22 19:25:23 +0000495 }
496
497 // now need to shift numerator by same amount as denominator
498 // first, increase length of numerator in case we need more room to shift
499 num_dig[*num_len] = 0;
500 ++(*num_len);
501 for (mpz_dig_t *num = num_dig, carry = 0; num < num_dig + *num_len; ++num) {
502 mpz_dig_t n = *num;
503 *num = ((n << norm_shift) | carry) & DIG_MASK;
Damien Georgedc3faea2016-05-08 21:38:43 +0100504 carry = (mpz_dbl_dig_t)n >> (DIG_SIZE - norm_shift);
Damien George438c88d2014-02-22 19:25:23 +0000505 }
506
507 // cache the leading digit of the denominator
508 lead_den_digit = den_dig[den_len - 1];
509
510 // point num_dig to last digit in numerator
511 num_dig += *num_len - 1;
512
513 // calculate number of digits in quotient
514 *quo_len = *num_len - den_len;
515
516 // point to last digit to store for quotient
517 quo_dig += *quo_len - 1;
518
519 // keep going while we have enough digits to divide
520 while (*num_len > den_len) {
Damien George9a21d2e2014-09-06 17:15:34 +0100521 mpz_dbl_dig_t quo = ((mpz_dbl_dig_t)*num_dig << DIG_SIZE) | num_dig[-1];
Damien George438c88d2014-02-22 19:25:23 +0000522
523 // get approximate quotient
524 quo /= lead_den_digit;
525
Damien George9a21d2e2014-09-06 17:15:34 +0100526 // Multiply quo by den and subtract from num to get remainder.
527 // We have different code here to handle different compile-time
528 // configurations of mpz:
529 //
530 // 1. DIG_SIZE is stricly less than half the number of bits
531 // available in mpz_dbl_dig_t. In this case we can use a
532 // slightly more optimal (in time and space) routine that
533 // uses the extra bits in mpz_dbl_dig_signed_t to store a
534 // sign bit.
535 //
536 // 2. DIG_SIZE is exactly half the number of bits available in
537 // mpz_dbl_dig_t. In this (common) case we need to be careful
538 // not to overflow the borrow variable. And the shifting of
539 // borrow needs some special logic (it's a shift right with
540 // round up).
541
542 if (DIG_SIZE < 8 * sizeof(mpz_dbl_dig_t) / 2) {
Damien George438c88d2014-02-22 19:25:23 +0000543 mpz_dbl_dig_signed_t borrow = 0;
544
545 for (mpz_dig_t *n = num_dig - den_len, *d = den_dig; n < num_dig; ++n, ++d) {
Damien George9a21d2e2014-09-06 17:15:34 +0100546 borrow += (mpz_dbl_dig_t)*n - (mpz_dbl_dig_t)quo * (mpz_dbl_dig_t)*d; // will overflow if DIG_SIZE >= 8*sizeof(mpz_dbl_dig_t)/2
Damien George438c88d2014-02-22 19:25:23 +0000547 *n = borrow & DIG_MASK;
548 borrow >>= DIG_SIZE;
549 }
Damien George9a21d2e2014-09-06 17:15:34 +0100550 borrow += *num_dig; // will overflow if DIG_SIZE >= 8*sizeof(mpz_dbl_dig_t)/2
Damien George438c88d2014-02-22 19:25:23 +0000551 *num_dig = borrow & DIG_MASK;
552 borrow >>= DIG_SIZE;
553
554 // adjust quotient if it is too big
555 for (; borrow != 0; --quo) {
556 mpz_dbl_dig_t carry = 0;
557 for (mpz_dig_t *n = num_dig - den_len, *d = den_dig; n < num_dig; ++n, ++d) {
Damien George9a21d2e2014-09-06 17:15:34 +0100558 carry += (mpz_dbl_dig_t)*n + (mpz_dbl_dig_t)*d;
Damien George438c88d2014-02-22 19:25:23 +0000559 *n = carry & DIG_MASK;
560 carry >>= DIG_SIZE;
561 }
562 carry += *num_dig;
563 *num_dig = carry & DIG_MASK;
564 carry >>= DIG_SIZE;
565
566 borrow += carry;
567 }
Damien George9a21d2e2014-09-06 17:15:34 +0100568 } else { // DIG_SIZE == 8 * sizeof(mpz_dbl_dig_t) / 2
569 mpz_dbl_dig_t borrow = 0;
570
571 for (mpz_dig_t *n = num_dig - den_len, *d = den_dig; n < num_dig; ++n, ++d) {
572 mpz_dbl_dig_t x = (mpz_dbl_dig_t)quo * (mpz_dbl_dig_t)(*d);
573 if (x >= *n || *n - x <= borrow) {
574 borrow += (mpz_dbl_dig_t)x - (mpz_dbl_dig_t)*n;
575 *n = (-borrow) & DIG_MASK;
576 borrow = (borrow >> DIG_SIZE) + ((borrow & DIG_MASK) == 0 ? 0 : 1); // shift-right with round-up
577 } else {
578 *n = ((mpz_dbl_dig_t)*n - (mpz_dbl_dig_t)x - (mpz_dbl_dig_t)borrow) & DIG_MASK;
579 borrow = 0;
580 }
581 }
582 if (borrow >= *num_dig) {
583 borrow -= (mpz_dbl_dig_t)*num_dig;
584 *num_dig = (-borrow) & DIG_MASK;
585 borrow = (borrow >> DIG_SIZE) + ((borrow & DIG_MASK) == 0 ? 0 : 1); // shift-right with round-up
586 } else {
587 *num_dig = (*num_dig - borrow) & DIG_MASK;
588 borrow = 0;
589 }
590
591 // adjust quotient if it is too big
592 for (; borrow != 0; --quo) {
593 mpz_dbl_dig_t carry = 0;
594 for (mpz_dig_t *n = num_dig - den_len, *d = den_dig; n < num_dig; ++n, ++d) {
595 carry += (mpz_dbl_dig_t)*n + (mpz_dbl_dig_t)*d;
596 *n = carry & DIG_MASK;
597 carry >>= DIG_SIZE;
598 }
599 carry += (mpz_dbl_dig_t)*num_dig;
600 *num_dig = carry & DIG_MASK;
601 carry >>= DIG_SIZE;
602
603 //assert(borrow >= carry); // enable this to check the logic
604 borrow -= carry;
605 }
Damien George438c88d2014-02-22 19:25:23 +0000606 }
607
608 // store this digit of the quotient
609 *quo_dig = quo & DIG_MASK;
610 --quo_dig;
611
612 // move down to next digit of numerator
613 --num_dig;
614 --(*num_len);
615 }
616
617 // unnormalise denomenator
618 for (mpz_dig_t *den = den_dig + den_len - 1, carry = 0; den >= den_dig; --den) {
619 mpz_dig_t d = *den;
620 *den = ((d >> norm_shift) | carry) & DIG_MASK;
Damien Georgedc3faea2016-05-08 21:38:43 +0100621 carry = (mpz_dbl_dig_t)d << (DIG_SIZE - norm_shift);
Damien George438c88d2014-02-22 19:25:23 +0000622 }
623
624 // unnormalise numerator (remainder now)
625 for (mpz_dig_t *num = orig_num_dig + *num_len - 1, carry = 0; num >= orig_num_dig; --num) {
626 mpz_dig_t n = *num;
627 *num = ((n >> norm_shift) | carry) & DIG_MASK;
Damien Georgedc3faea2016-05-08 21:38:43 +0100628 carry = (mpz_dbl_dig_t)n << (DIG_SIZE - norm_shift);
Damien George438c88d2014-02-22 19:25:23 +0000629 }
630
631 // strip trailing zeros
632
633 while (*quo_len > 0 && orig_quo_dig[*quo_len - 1] == 0) {
634 --(*quo_len);
635 }
636
637 while (*num_len > 0 && orig_num_dig[*num_len - 1] == 0) {
638 --(*num_len);
639 }
640}
641
Damien George06201ff2014-03-01 19:50:50 +0000642#define MIN_ALLOC (2)
Damien George438c88d2014-02-22 19:25:23 +0000643
Damien George1c70cbf2014-08-30 00:38:16 +0100644STATIC const uint8_t log_base2_floor[] = {
Damien George438c88d2014-02-22 19:25:23 +0000645 0,
646 0, 1, 1, 2,
647 2, 2, 2, 3,
648 3, 3, 3, 3,
649 3, 3, 3, 4,
650 4, 4, 4, 4,
651 4, 4, 4, 4,
652 4, 4, 4, 4,
653 4, 4, 4, 5
654};
655
Damien George438c88d2014-02-22 19:25:23 +0000656void mpz_init_zero(mpz_t *z) {
Damien George438c88d2014-02-22 19:25:23 +0000657 z->neg = 0;
Damien George06201ff2014-03-01 19:50:50 +0000658 z->fixed_dig = 0;
659 z->alloc = 0;
Damien George438c88d2014-02-22 19:25:23 +0000660 z->len = 0;
661 z->dig = NULL;
662}
663
Damien George40f3c022014-07-03 13:25:24 +0100664void mpz_init_from_int(mpz_t *z, mp_int_t val) {
Damien George438c88d2014-02-22 19:25:23 +0000665 mpz_init_zero(z);
666 mpz_set_from_int(z, val);
667}
668
Damien Georgeafb1cf72014-09-05 20:37:06 +0100669void mpz_init_fixed_from_int(mpz_t *z, mpz_dig_t *dig, mp_uint_t alloc, mp_int_t val) {
Damien George06201ff2014-03-01 19:50:50 +0000670 z->neg = 0;
671 z->fixed_dig = 1;
672 z->alloc = alloc;
673 z->len = 0;
674 z->dig = dig;
675 mpz_set_from_int(z, val);
676}
677
Damien George438c88d2014-02-22 19:25:23 +0000678void mpz_deinit(mpz_t *z) {
Damien George06201ff2014-03-01 19:50:50 +0000679 if (z != NULL && !z->fixed_dig) {
Damien George438c88d2014-02-22 19:25:23 +0000680 m_del(mpz_dig_t, z->dig, z->alloc);
681 }
682}
683
Damien George848dd0e2015-03-12 15:59:40 +0000684#if 0
685these functions are unused
686
Damien George438c88d2014-02-22 19:25:23 +0000687mpz_t *mpz_zero(void) {
688 mpz_t *z = m_new_obj(mpz_t);
689 mpz_init_zero(z);
690 return z;
691}
692
Damien George40f3c022014-07-03 13:25:24 +0100693mpz_t *mpz_from_int(mp_int_t val) {
Damien George438c88d2014-02-22 19:25:23 +0000694 mpz_t *z = mpz_zero();
695 mpz_set_from_int(z, val);
696 return z;
697}
698
Damien George95307432014-09-10 22:10:33 +0100699mpz_t *mpz_from_ll(long long val, bool is_signed) {
Damien Georgebb4a43f2014-03-12 15:36:06 +0000700 mpz_t *z = mpz_zero();
Damien George95307432014-09-10 22:10:33 +0100701 mpz_set_from_ll(z, val, is_signed);
Damien Georgebb4a43f2014-03-12 15:36:06 +0000702 return z;
703}
704
David Steinberg6e0b6d02015-01-02 12:39:22 +0000705#if MICROPY_PY_BUILTINS_FLOAT
706mpz_t *mpz_from_float(mp_float_t val) {
707 mpz_t *z = mpz_zero();
708 mpz_set_from_float(z, val);
709 return z;
710}
711#endif
712
Damien Georgeafb1cf72014-09-05 20:37:06 +0100713mpz_t *mpz_from_str(const char *str, mp_uint_t len, bool neg, mp_uint_t base) {
Damien George438c88d2014-02-22 19:25:23 +0000714 mpz_t *z = mpz_zero();
715 mpz_set_from_str(z, str, len, neg, base);
716 return z;
717}
Damien George848dd0e2015-03-12 15:59:40 +0000718#endif
Damien George438c88d2014-02-22 19:25:23 +0000719
Damien George848dd0e2015-03-12 15:59:40 +0000720STATIC void mpz_free(mpz_t *z) {
Damien George438c88d2014-02-22 19:25:23 +0000721 if (z != NULL) {
722 m_del(mpz_dig_t, z->dig, z->alloc);
723 m_del_obj(mpz_t, z);
724 }
725}
726
Damien Georgeafb1cf72014-09-05 20:37:06 +0100727STATIC void mpz_need_dig(mpz_t *z, mp_uint_t need) {
Damien George438c88d2014-02-22 19:25:23 +0000728 if (need < MIN_ALLOC) {
Damien George06201ff2014-03-01 19:50:50 +0000729 need = MIN_ALLOC;
Damien George438c88d2014-02-22 19:25:23 +0000730 }
731
Damien George06201ff2014-03-01 19:50:50 +0000732 if (z->dig == NULL || z->alloc < need) {
733 if (z->fixed_dig) {
734 // cannot reallocate fixed buffers
735 assert(0);
736 return;
737 }
738 z->dig = m_renew(mpz_dig_t, z->dig, z->alloc, need);
739 z->alloc = need;
Damien George438c88d2014-02-22 19:25:23 +0000740 }
741}
742
Damien George848dd0e2015-03-12 15:59:40 +0000743STATIC mpz_t *mpz_clone(const mpz_t *src) {
Damien George438c88d2014-02-22 19:25:23 +0000744 mpz_t *z = m_new_obj(mpz_t);
Damien George438c88d2014-02-22 19:25:23 +0000745 z->neg = src->neg;
Damien George06201ff2014-03-01 19:50:50 +0000746 z->fixed_dig = 0;
747 z->alloc = src->alloc;
Damien George438c88d2014-02-22 19:25:23 +0000748 z->len = src->len;
749 if (src->dig == NULL) {
750 z->dig = NULL;
751 } else {
752 z->dig = m_new(mpz_dig_t, z->alloc);
753 memcpy(z->dig, src->dig, src->alloc * sizeof(mpz_dig_t));
754 }
755 return z;
756}
757
Damien George06201ff2014-03-01 19:50:50 +0000758/* sets dest = src
759 can have dest, src the same
760*/
Damien George438c88d2014-02-22 19:25:23 +0000761void mpz_set(mpz_t *dest, const mpz_t *src) {
762 mpz_need_dig(dest, src->len);
763 dest->neg = src->neg;
764 dest->len = src->len;
765 memcpy(dest->dig, src->dig, src->len * sizeof(mpz_dig_t));
766}
767
Damien George40f3c022014-07-03 13:25:24 +0100768void mpz_set_from_int(mpz_t *z, mp_int_t val) {
Damien George58056b02015-01-09 20:58:58 +0000769 if (val == 0) {
770 z->len = 0;
771 return;
772 }
773
Damien George06201ff2014-03-01 19:50:50 +0000774 mpz_need_dig(z, MPZ_NUM_DIG_FOR_INT);
Damien George438c88d2014-02-22 19:25:23 +0000775
Damien George40f3c022014-07-03 13:25:24 +0100776 mp_uint_t uval;
Damien George438c88d2014-02-22 19:25:23 +0000777 if (val < 0) {
778 z->neg = 1;
Damien Georgebb4a43f2014-03-12 15:36:06 +0000779 uval = -val;
Damien George438c88d2014-02-22 19:25:23 +0000780 } else {
781 z->neg = 0;
Damien Georgebb4a43f2014-03-12 15:36:06 +0000782 uval = val;
Damien George438c88d2014-02-22 19:25:23 +0000783 }
784
785 z->len = 0;
Damien Georgebb4a43f2014-03-12 15:36:06 +0000786 while (uval > 0) {
787 z->dig[z->len++] = uval & DIG_MASK;
788 uval >>= DIG_SIZE;
789 }
790}
791
Damien George95307432014-09-10 22:10:33 +0100792void mpz_set_from_ll(mpz_t *z, long long val, bool is_signed) {
Damien Georgebb4a43f2014-03-12 15:36:06 +0000793 mpz_need_dig(z, MPZ_NUM_DIG_FOR_LL);
794
795 unsigned long long uval;
Damien George95307432014-09-10 22:10:33 +0100796 if (is_signed && val < 0) {
Damien Georgebb4a43f2014-03-12 15:36:06 +0000797 z->neg = 1;
798 uval = -val;
799 } else {
800 z->neg = 0;
801 uval = val;
802 }
803
804 z->len = 0;
805 while (uval > 0) {
806 z->dig[z->len++] = uval & DIG_MASK;
807 uval >>= DIG_SIZE;
Damien George438c88d2014-02-22 19:25:23 +0000808 }
809}
810
David Steinberg6e0b6d02015-01-02 12:39:22 +0000811#if MICROPY_PY_BUILTINS_FLOAT
812void mpz_set_from_float(mpz_t *z, mp_float_t src) {
813#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE
David Steinberg6e0b6d02015-01-02 12:39:22 +0000814typedef uint64_t mp_float_int_t;
David Steinbergc585ad12015-01-13 15:19:37 +0000815#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
David Steinberg6e0b6d02015-01-02 12:39:22 +0000816typedef uint32_t mp_float_int_t;
817#endif
818 union {
819 mp_float_t f;
Damien George2adf7ec2016-01-08 17:56:58 +0000820 #if MP_ENDIANNESS_LITTLE
David Steinbergc585ad12015-01-13 15:19:37 +0000821 struct { mp_float_int_t frc:MP_FLOAT_FRAC_BITS, exp:MP_FLOAT_EXP_BITS, sgn:1; } p;
Damien George2adf7ec2016-01-08 17:56:58 +0000822 #else
823 struct { mp_float_int_t sgn:1, exp:MP_FLOAT_EXP_BITS, frc:MP_FLOAT_FRAC_BITS; } p;
824 #endif
David Steinberg6e0b6d02015-01-02 12:39:22 +0000825 } u = {src};
826
827 z->neg = u.p.sgn;
828 if (u.p.exp == 0) {
829 // value == 0 || value < 1
Damien George58056b02015-01-09 20:58:58 +0000830 mpz_set_from_int(z, 0);
David Steinbergc585ad12015-01-13 15:19:37 +0000831 } else if (u.p.exp == ((1 << MP_FLOAT_EXP_BITS) - 1)) {
Damien George6fd4b362015-01-02 23:04:09 +0000832 // u.p.frc == 0 indicates inf, else NaN
833 // should be handled by caller
Damien George58056b02015-01-09 20:58:58 +0000834 mpz_set_from_int(z, 0);
David Steinberg6e0b6d02015-01-02 12:39:22 +0000835 } else {
David Steinbergc585ad12015-01-13 15:19:37 +0000836 const int adj_exp = (int)u.p.exp - MP_FLOAT_EXP_BIAS;
David Steinberg6e0b6d02015-01-02 12:39:22 +0000837 if (adj_exp < 0) {
838 // value < 1 , truncates to 0
Damien George58056b02015-01-09 20:58:58 +0000839 mpz_set_from_int(z, 0);
David Steinberg6e0b6d02015-01-02 12:39:22 +0000840 } else if (adj_exp == 0) {
841 // 1 <= value < 2 , so truncates to 1
Damien George58056b02015-01-09 20:58:58 +0000842 mpz_set_from_int(z, 1);
David Steinberg6e0b6d02015-01-02 12:39:22 +0000843 } else {
844 // 2 <= value
845 const int dig_cnt = (adj_exp + 1 + (DIG_SIZE - 1)) / DIG_SIZE;
846 const unsigned int rem = adj_exp % DIG_SIZE;
847 int dig_ind, shft;
David Steinbergc585ad12015-01-13 15:19:37 +0000848 mp_float_int_t frc = u.p.frc | ((mp_float_int_t)1 << MP_FLOAT_FRAC_BITS);
David Steinberg6e0b6d02015-01-02 12:39:22 +0000849
David Steinbergc585ad12015-01-13 15:19:37 +0000850 if (adj_exp < MP_FLOAT_FRAC_BITS) {
David Steinberg6e0b6d02015-01-02 12:39:22 +0000851 shft = 0;
852 dig_ind = 0;
David Steinbergc585ad12015-01-13 15:19:37 +0000853 frc >>= MP_FLOAT_FRAC_BITS - adj_exp;
David Steinberg6e0b6d02015-01-02 12:39:22 +0000854 } else {
David Steinbergc585ad12015-01-13 15:19:37 +0000855 shft = (rem - MP_FLOAT_FRAC_BITS) % DIG_SIZE;
856 dig_ind = (adj_exp - MP_FLOAT_FRAC_BITS) / DIG_SIZE;
David Steinberg6e0b6d02015-01-02 12:39:22 +0000857 }
858 mpz_need_dig(z, dig_cnt);
859 z->len = dig_cnt;
860 if (dig_ind != 0) {
861 memset(z->dig, 0, dig_ind * sizeof(mpz_dig_t));
862 }
863 if (shft != 0) {
864 z->dig[dig_ind++] = (frc << shft) & DIG_MASK;
865 frc >>= DIG_SIZE - shft;
866 }
David Steinberg8d427b72015-01-13 15:20:32 +0000867#if DIG_SIZE < (MP_FLOAT_FRAC_BITS + 1)
David Steinberg6e0b6d02015-01-02 12:39:22 +0000868 while (dig_ind != dig_cnt) {
869 z->dig[dig_ind++] = frc & DIG_MASK;
870 frc >>= DIG_SIZE;
871 }
David Steinberg8d427b72015-01-13 15:20:32 +0000872#else
873 if (dig_ind != dig_cnt) {
874 z->dig[dig_ind] = frc;
875 }
876#endif
David Steinberg6e0b6d02015-01-02 12:39:22 +0000877 }
878 }
879}
David Steinberg6e0b6d02015-01-02 12:39:22 +0000880#endif
881
Damien George438c88d2014-02-22 19:25:23 +0000882// returns number of bytes from str that were processed
Damien Georgeafb1cf72014-09-05 20:37:06 +0100883mp_uint_t mpz_set_from_str(mpz_t *z, const char *str, mp_uint_t len, bool neg, mp_uint_t base) {
Damien George438c88d2014-02-22 19:25:23 +0000884 assert(base < 36);
885
886 const char *cur = str;
887 const char *top = str + len;
888
889 mpz_need_dig(z, len * 8 / DIG_SIZE + 1);
890
891 if (neg) {
892 z->neg = 1;
893 } else {
894 z->neg = 0;
895 }
896
897 z->len = 0;
898 for (; cur < top; ++cur) { // XXX UTF8 next char
Damien Georgeafb1cf72014-09-05 20:37:06 +0100899 //mp_uint_t v = char_to_numeric(cur#); // XXX UTF8 get char
900 mp_uint_t v = *cur;
Damien George438c88d2014-02-22 19:25:23 +0000901 if ('0' <= v && v <= '9') {
902 v -= '0';
903 } else if ('A' <= v && v <= 'Z') {
904 v -= 'A' - 10;
905 } else if ('a' <= v && v <= 'z') {
906 v -= 'a' - 10;
907 } else {
908 break;
909 }
910 if (v >= base) {
911 break;
912 }
913 z->len = mpn_mul_dig_add_dig(z->dig, z->len, base, v);
914 }
915
916 return cur - str;
917}
918
919bool mpz_is_zero(const mpz_t *z) {
920 return z->len == 0;
921}
922
Damien Georgea2e38382015-03-02 12:58:06 +0000923#if 0
924these functions are unused
925
Damien George438c88d2014-02-22 19:25:23 +0000926bool mpz_is_pos(const mpz_t *z) {
927 return z->len > 0 && z->neg == 0;
928}
929
930bool mpz_is_neg(const mpz_t *z) {
931 return z->len > 0 && z->neg != 0;
932}
933
934bool mpz_is_odd(const mpz_t *z) {
935 return z->len > 0 && (z->dig[0] & 1) != 0;
936}
937
938bool mpz_is_even(const mpz_t *z) {
939 return z->len == 0 || (z->dig[0] & 1) == 0;
940}
Damien Georgea2e38382015-03-02 12:58:06 +0000941#endif
Damien George438c88d2014-02-22 19:25:23 +0000942
Damien George42f3de92014-10-03 17:44:14 +0000943int mpz_cmp(const mpz_t *z1, const mpz_t *z2) {
Damien Georgea9dc9b82015-01-27 17:47:38 +0000944 // to catch comparison of -0 with +0
945 if (z1->len == 0 && z2->len == 0) {
946 return 0;
947 }
Damien George42f3de92014-10-03 17:44:14 +0000948 int cmp = (int)z2->neg - (int)z1->neg;
Damien George438c88d2014-02-22 19:25:23 +0000949 if (cmp != 0) {
950 return cmp;
951 }
952 cmp = mpn_cmp(z1->dig, z1->len, z2->dig, z2->len);
953 if (z1->neg != 0) {
954 cmp = -cmp;
955 }
956 return cmp;
957}
958
Damien George06201ff2014-03-01 19:50:50 +0000959#if 0
960// obsolete
961// compares mpz with an integer that fits within DIG_SIZE bits
Damien Georgeafb1cf72014-09-05 20:37:06 +0100962mp_int_t mpz_cmp_sml_int(const mpz_t *z, mp_int_t sml_int) {
963 mp_int_t cmp;
Damien George438c88d2014-02-22 19:25:23 +0000964 if (z->neg == 0) {
965 if (sml_int < 0) return 1;
966 if (sml_int == 0) {
967 if (z->len == 0) return 0;
968 return 1;
969 }
970 if (z->len == 0) return -1;
971 assert(sml_int < (1 << DIG_SIZE));
972 if (z->len != 1) return 1;
973 cmp = z->dig[0] - sml_int;
974 } else {
975 if (sml_int > 0) return -1;
976 if (sml_int == 0) {
977 if (z->len == 0) return 0;
978 return -1;
979 }
980 if (z->len == 0) return 1;
981 assert(sml_int > -(1 << DIG_SIZE));
982 if (z->len != 1) return -1;
983 cmp = -z->dig[0] - sml_int;
984 }
985 if (cmp < 0) return -1;
986 if (cmp > 0) return 1;
987 return 0;
988}
Damien George06201ff2014-03-01 19:50:50 +0000989#endif
Damien George438c88d2014-02-22 19:25:23 +0000990
Damien George438c88d2014-02-22 19:25:23 +0000991#if 0
992these functions are unused
993
994/* returns abs(z)
995*/
996mpz_t *mpz_abs(const mpz_t *z) {
997 mpz_t *z2 = mpz_clone(z);
998 z2->neg = 0;
999 return z2;
1000}
1001
1002/* returns -z
1003*/
1004mpz_t *mpz_neg(const mpz_t *z) {
1005 mpz_t *z2 = mpz_clone(z);
1006 z2->neg = 1 - z2->neg;
1007 return z2;
1008}
1009
1010/* returns lhs + rhs
1011 can have lhs, rhs the same
1012*/
1013mpz_t *mpz_add(const mpz_t *lhs, const mpz_t *rhs) {
1014 mpz_t *z = mpz_zero();
1015 mpz_add_inpl(z, lhs, rhs);
1016 return z;
1017}
1018
1019/* returns lhs - rhs
1020 can have lhs, rhs the same
1021*/
1022mpz_t *mpz_sub(const mpz_t *lhs, const mpz_t *rhs) {
1023 mpz_t *z = mpz_zero();
1024 mpz_sub_inpl(z, lhs, rhs);
1025 return z;
1026}
1027
1028/* returns lhs * rhs
1029 can have lhs, rhs the same
1030*/
1031mpz_t *mpz_mul(const mpz_t *lhs, const mpz_t *rhs) {
1032 mpz_t *z = mpz_zero();
1033 mpz_mul_inpl(z, lhs, rhs);
1034 return z;
1035}
1036
1037/* returns lhs ** rhs
1038 can have lhs, rhs the same
1039*/
1040mpz_t *mpz_pow(const mpz_t *lhs, const mpz_t *rhs) {
1041 mpz_t *z = mpz_zero();
1042 mpz_pow_inpl(z, lhs, rhs);
1043 return z;
1044}
Damien Georgea2e38382015-03-02 12:58:06 +00001045
1046/* computes new integers in quo and rem such that:
1047 quo * rhs + rem = lhs
1048 0 <= rem < rhs
1049 can have lhs, rhs the same
1050*/
1051void mpz_divmod(const mpz_t *lhs, const mpz_t *rhs, mpz_t **quo, mpz_t **rem) {
1052 *quo = mpz_zero();
1053 *rem = mpz_zero();
1054 mpz_divmod_inpl(*quo, *rem, lhs, rhs);
1055}
Damien George438c88d2014-02-22 19:25:23 +00001056#endif
1057
1058/* computes dest = abs(z)
1059 can have dest, z the same
1060*/
1061void mpz_abs_inpl(mpz_t *dest, const mpz_t *z) {
1062 if (dest != z) {
1063 mpz_set(dest, z);
1064 }
1065 dest->neg = 0;
1066}
1067
1068/* computes dest = -z
1069 can have dest, z the same
1070*/
1071void mpz_neg_inpl(mpz_t *dest, const mpz_t *z) {
1072 if (dest != z) {
1073 mpz_set(dest, z);
1074 }
1075 dest->neg = 1 - dest->neg;
1076}
1077
Damien George06201ff2014-03-01 19:50:50 +00001078/* computes dest = ~z (= -z - 1)
1079 can have dest, z the same
1080*/
1081void mpz_not_inpl(mpz_t *dest, const mpz_t *z) {
1082 if (dest != z) {
1083 mpz_set(dest, z);
1084 }
Damien Georgee0ac1942014-12-31 19:35:01 +00001085 if (dest->len == 0) {
1086 mpz_need_dig(dest, 1);
1087 dest->dig[0] = 1;
1088 dest->len = 1;
1089 dest->neg = 1;
1090 } else if (dest->neg) {
Damien George06201ff2014-03-01 19:50:50 +00001091 dest->neg = 0;
1092 mpz_dig_t k = 1;
1093 dest->len = mpn_sub(dest->dig, dest->dig, dest->len, &k, 1);
1094 } else {
Damien Georgee0ac1942014-12-31 19:35:01 +00001095 mpz_need_dig(dest, dest->len + 1);
Damien George06201ff2014-03-01 19:50:50 +00001096 mpz_dig_t k = 1;
1097 dest->len = mpn_add(dest->dig, dest->dig, dest->len, &k, 1);
1098 dest->neg = 1;
1099 }
1100}
1101
Damien Georgec5ac2ac2014-02-26 16:56:30 +00001102/* computes dest = lhs << rhs
1103 can have dest, lhs the same
1104*/
Damien George2f4e8512015-10-01 18:01:37 +01001105void mpz_shl_inpl(mpz_t *dest, const mpz_t *lhs, mp_uint_t rhs) {
Damien George06201ff2014-03-01 19:50:50 +00001106 if (lhs->len == 0 || rhs == 0) {
Damien Georgec5ac2ac2014-02-26 16:56:30 +00001107 mpz_set(dest, lhs);
Damien Georgec5ac2ac2014-02-26 16:56:30 +00001108 } else {
Damien George06201ff2014-03-01 19:50:50 +00001109 mpz_need_dig(dest, lhs->len + (rhs + DIG_SIZE - 1) / DIG_SIZE);
1110 dest->len = mpn_shl(dest->dig, lhs->dig, lhs->len, rhs);
1111 dest->neg = lhs->neg;
Damien Georgec5ac2ac2014-02-26 16:56:30 +00001112 }
Damien Georgec5ac2ac2014-02-26 16:56:30 +00001113}
1114
1115/* computes dest = lhs >> rhs
1116 can have dest, lhs the same
1117*/
Damien George2f4e8512015-10-01 18:01:37 +01001118void mpz_shr_inpl(mpz_t *dest, const mpz_t *lhs, mp_uint_t rhs) {
Damien George06201ff2014-03-01 19:50:50 +00001119 if (lhs->len == 0 || rhs == 0) {
Damien Georgec5ac2ac2014-02-26 16:56:30 +00001120 mpz_set(dest, lhs);
Damien Georgec5ac2ac2014-02-26 16:56:30 +00001121 } else {
Damien George06201ff2014-03-01 19:50:50 +00001122 mpz_need_dig(dest, lhs->len);
1123 dest->len = mpn_shr(dest->dig, lhs->dig, lhs->len, rhs);
1124 dest->neg = lhs->neg;
1125 if (dest->neg) {
1126 // arithmetic shift right, rounding to negative infinity
Damien Georgeafb1cf72014-09-05 20:37:06 +01001127 mp_uint_t n_whole = rhs / DIG_SIZE;
1128 mp_uint_t n_part = rhs % DIG_SIZE;
Damien George06201ff2014-03-01 19:50:50 +00001129 mpz_dig_t round_up = 0;
Damien Georgeafb1cf72014-09-05 20:37:06 +01001130 for (mp_uint_t i = 0; i < lhs->len && i < n_whole; i++) {
Damien George06201ff2014-03-01 19:50:50 +00001131 if (lhs->dig[i] != 0) {
1132 round_up = 1;
1133 break;
1134 }
1135 }
1136 if (n_whole < lhs->len && (lhs->dig[n_whole] & ((1 << n_part) - 1)) != 0) {
1137 round_up = 1;
1138 }
1139 if (round_up) {
Damien Georgee0ac1942014-12-31 19:35:01 +00001140 if (dest->len == 0) {
1141 // dest == 0, so need to add 1 by hand (answer will be -1)
1142 dest->dig[0] = 1;
1143 dest->len = 1;
1144 } else {
1145 // dest > 0, so can use mpn_add to add 1
1146 dest->len = mpn_add(dest->dig, dest->dig, dest->len, &round_up, 1);
1147 }
Damien George06201ff2014-03-01 19:50:50 +00001148 }
1149 }
Damien Georgec5ac2ac2014-02-26 16:56:30 +00001150 }
Damien Georgec5ac2ac2014-02-26 16:56:30 +00001151}
Damien Georgec5ac2ac2014-02-26 16:56:30 +00001152
Damien George438c88d2014-02-22 19:25:23 +00001153/* computes dest = lhs + rhs
1154 can have dest, lhs, rhs the same
1155*/
1156void mpz_add_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
1157 if (mpn_cmp(lhs->dig, lhs->len, rhs->dig, rhs->len) < 0) {
1158 const mpz_t *temp = lhs;
1159 lhs = rhs;
1160 rhs = temp;
1161 }
1162
1163 if (lhs->neg == rhs->neg) {
1164 mpz_need_dig(dest, lhs->len + 1);
1165 dest->len = mpn_add(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
1166 } else {
1167 mpz_need_dig(dest, lhs->len);
1168 dest->len = mpn_sub(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
1169 }
1170
1171 dest->neg = lhs->neg;
1172}
1173
1174/* computes dest = lhs - rhs
1175 can have dest, lhs, rhs the same
1176*/
1177void mpz_sub_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
1178 bool neg = false;
1179
1180 if (mpn_cmp(lhs->dig, lhs->len, rhs->dig, rhs->len) < 0) {
1181 const mpz_t *temp = lhs;
1182 lhs = rhs;
1183 rhs = temp;
1184 neg = true;
1185 }
1186
1187 if (lhs->neg != rhs->neg) {
1188 mpz_need_dig(dest, lhs->len + 1);
1189 dest->len = mpn_add(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
1190 } else {
1191 mpz_need_dig(dest, lhs->len);
1192 dest->len = mpn_sub(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
1193 }
1194
1195 if (neg) {
1196 dest->neg = 1 - lhs->neg;
1197 } else {
1198 dest->neg = lhs->neg;
1199 }
1200}
1201
Paul Sokolovsky57207b82014-03-23 01:52:36 +02001202/* computes dest = lhs & rhs
1203 can have dest, lhs, rhs the same
1204*/
1205void mpz_and_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
Doug Currie2e2e15c2016-01-30 22:35:58 -05001206 // make sure lhs has the most digits
1207 if (lhs->len < rhs->len) {
1208 const mpz_t *temp = lhs;
1209 lhs = rhs;
1210 rhs = temp;
Paul Sokolovsky57207b82014-03-23 01:52:36 +02001211 }
Doug Currie2e2e15c2016-01-30 22:35:58 -05001212
1213 #if MICROPY_OPT_MPZ_BITWISE
1214
1215 if ((0 == lhs->neg) && (0 == rhs->neg)) {
1216 mpz_need_dig(dest, lhs->len);
1217 dest->len = mpn_and(dest->dig, lhs->dig, rhs->dig, rhs->len);
1218 dest->neg = 0;
1219 } else {
1220 mpz_need_dig(dest, lhs->len + 1);
1221 dest->len = mpn_and_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len,
1222 lhs->neg == rhs->neg, 0 != lhs->neg, 0 != rhs->neg);
1223 dest->neg = lhs->neg & rhs->neg;
1224 }
1225
1226 #else
1227
1228 mpz_need_dig(dest, lhs->len + (lhs->neg || rhs->neg));
1229 dest->len = mpn_and_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len,
1230 (lhs->neg == rhs->neg) ? lhs->neg : 0, lhs->neg, rhs->neg);
1231 dest->neg = lhs->neg & rhs->neg;
1232
1233 #endif
Paul Sokolovsky57207b82014-03-23 01:52:36 +02001234}
1235
1236/* computes dest = lhs | rhs
1237 can have dest, lhs, rhs the same
1238*/
1239void mpz_or_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
Doug Currie2e2e15c2016-01-30 22:35:58 -05001240 // make sure lhs has the most digits
1241 if (lhs->len < rhs->len) {
Paul Sokolovsky57207b82014-03-23 01:52:36 +02001242 const mpz_t *temp = lhs;
1243 lhs = rhs;
1244 rhs = temp;
1245 }
1246
Doug Currie2e2e15c2016-01-30 22:35:58 -05001247 #if MICROPY_OPT_MPZ_BITWISE
1248
1249 if ((0 == lhs->neg) && (0 == rhs->neg)) {
Paul Sokolovsky57207b82014-03-23 01:52:36 +02001250 mpz_need_dig(dest, lhs->len);
1251 dest->len = mpn_or(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
Doug Currie2e2e15c2016-01-30 22:35:58 -05001252 dest->neg = 0;
Paul Sokolovsky57207b82014-03-23 01:52:36 +02001253 } else {
Doug Currie2e2e15c2016-01-30 22:35:58 -05001254 mpz_need_dig(dest, lhs->len + 1);
1255 dest->len = mpn_or_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len,
1256 0 != lhs->neg, 0 != rhs->neg);
1257 dest->neg = 1;
Paul Sokolovsky57207b82014-03-23 01:52:36 +02001258 }
1259
Doug Currie2e2e15c2016-01-30 22:35:58 -05001260 #else
1261
1262 mpz_need_dig(dest, lhs->len + (lhs->neg || rhs->neg));
1263 dest->len = mpn_or_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len,
1264 (lhs->neg || rhs->neg), lhs->neg, rhs->neg);
1265 dest->neg = lhs->neg | rhs->neg;
1266
1267 #endif
Paul Sokolovsky57207b82014-03-23 01:52:36 +02001268}
1269
1270/* computes dest = lhs ^ rhs
1271 can have dest, lhs, rhs the same
1272*/
1273void mpz_xor_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
Doug Currie2e2e15c2016-01-30 22:35:58 -05001274 // make sure lhs has the most digits
1275 if (lhs->len < rhs->len) {
Paul Sokolovsky57207b82014-03-23 01:52:36 +02001276 const mpz_t *temp = lhs;
1277 lhs = rhs;
1278 rhs = temp;
1279 }
1280
Doug Currie2e2e15c2016-01-30 22:35:58 -05001281 #if MICROPY_OPT_MPZ_BITWISE
1282
Paul Sokolovsky57207b82014-03-23 01:52:36 +02001283 if (lhs->neg == rhs->neg) {
1284 mpz_need_dig(dest, lhs->len);
Doug Currie2e2e15c2016-01-30 22:35:58 -05001285 if (lhs->neg == 0) {
1286 dest->len = mpn_xor(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
1287 } else {
1288 dest->len = mpn_xor_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len, 0, 0, 0);
1289 }
1290 dest->neg = 0;
Paul Sokolovsky57207b82014-03-23 01:52:36 +02001291 } else {
Doug Currie2e2e15c2016-01-30 22:35:58 -05001292 mpz_need_dig(dest, lhs->len + 1);
1293 dest->len = mpn_xor_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len, 1,
1294 0 == lhs->neg, 0 == rhs->neg);
1295 dest->neg = 1;
Paul Sokolovsky57207b82014-03-23 01:52:36 +02001296 }
1297
Doug Currie2e2e15c2016-01-30 22:35:58 -05001298 #else
1299
1300 mpz_need_dig(dest, lhs->len + (lhs->neg || rhs->neg));
1301 dest->len = mpn_xor_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len,
1302 (lhs->neg != rhs->neg), 0 == lhs->neg, 0 == rhs->neg);
1303 dest->neg = lhs->neg ^ rhs->neg;
1304
1305 #endif
Paul Sokolovsky57207b82014-03-23 01:52:36 +02001306}
1307
Damien George438c88d2014-02-22 19:25:23 +00001308/* computes dest = lhs * rhs
1309 can have dest, lhs, rhs the same
1310*/
Damien George4dea9222015-04-09 15:29:54 +00001311void mpz_mul_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
Damien George438c88d2014-02-22 19:25:23 +00001312 if (lhs->len == 0 || rhs->len == 0) {
Damien Georgec5ac2ac2014-02-26 16:56:30 +00001313 mpz_set_from_int(dest, 0);
1314 return;
Damien George438c88d2014-02-22 19:25:23 +00001315 }
1316
1317 mpz_t *temp = NULL;
1318 if (lhs == dest) {
1319 lhs = temp = mpz_clone(lhs);
1320 if (rhs == dest) {
1321 rhs = lhs;
1322 }
1323 } else if (rhs == dest) {
1324 rhs = temp = mpz_clone(rhs);
1325 }
1326
1327 mpz_need_dig(dest, lhs->len + rhs->len); // min mem l+r-1, max mem l+r
1328 memset(dest->dig, 0, dest->alloc * sizeof(mpz_dig_t));
1329 dest->len = mpn_mul(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
1330
1331 if (lhs->neg == rhs->neg) {
1332 dest->neg = 0;
1333 } else {
1334 dest->neg = 1;
1335 }
1336
1337 mpz_free(temp);
1338}
1339
1340/* computes dest = lhs ** rhs
1341 can have dest, lhs, rhs the same
1342*/
1343void mpz_pow_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
1344 if (lhs->len == 0 || rhs->neg != 0) {
Damien Georgec5ac2ac2014-02-26 16:56:30 +00001345 mpz_set_from_int(dest, 0);
1346 return;
Damien George438c88d2014-02-22 19:25:23 +00001347 }
1348
1349 if (rhs->len == 0) {
Damien Georgec5ac2ac2014-02-26 16:56:30 +00001350 mpz_set_from_int(dest, 1);
1351 return;
Damien George438c88d2014-02-22 19:25:23 +00001352 }
1353
1354 mpz_t *x = mpz_clone(lhs);
1355 mpz_t *n = mpz_clone(rhs);
1356
1357 mpz_set_from_int(dest, 1);
1358
1359 while (n->len > 0) {
Damien Georgea2e38382015-03-02 12:58:06 +00001360 if ((n->dig[0] & 1) != 0) {
Damien George438c88d2014-02-22 19:25:23 +00001361 mpz_mul_inpl(dest, dest, x);
1362 }
Damien George438c88d2014-02-22 19:25:23 +00001363 n->len = mpn_shr(n->dig, n->dig, n->len, 1);
Damien George5bf565e2014-04-04 00:16:32 +01001364 if (n->len == 0) {
1365 break;
1366 }
1367 mpz_mul_inpl(x, x, x);
Damien George438c88d2014-02-22 19:25:23 +00001368 }
1369
1370 mpz_free(x);
1371 mpz_free(n);
1372}
1373
Damien Georgea2e38382015-03-02 12:58:06 +00001374#if 0
1375these functions are unused
1376
Damien Georgeff1a96c2016-02-03 22:30:49 +00001377/* computes dest = (lhs ** rhs) % mod
1378 can have dest, lhs, rhs the same; mod can't be the same as dest
1379*/
1380void mpz_pow3_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs, const mpz_t *mod) {
1381 if (lhs->len == 0 || rhs->neg != 0) {
1382 mpz_set_from_int(dest, 0);
1383 return;
1384 }
1385
1386 if (rhs->len == 0) {
1387 mpz_set_from_int(dest, 1);
1388 return;
1389 }
1390
1391 mpz_t *x = mpz_clone(lhs);
1392 mpz_t *n = mpz_clone(rhs);
1393 mpz_t quo; mpz_init_zero(&quo);
1394
1395 mpz_set_from_int(dest, 1);
1396
1397 while (n->len > 0) {
1398 if ((n->dig[0] & 1) != 0) {
1399 mpz_mul_inpl(dest, dest, x);
1400 mpz_divmod_inpl(&quo, dest, dest, mod);
1401 }
1402 n->len = mpn_shr(n->dig, n->dig, n->len, 1);
1403 if (n->len == 0) {
1404 break;
1405 }
1406 mpz_mul_inpl(x, x, x);
1407 mpz_divmod_inpl(&quo, x, x, mod);
1408 }
1409
1410 mpz_deinit(&quo);
1411 mpz_free(x);
1412 mpz_free(n);
1413}
1414
Damien George438c88d2014-02-22 19:25:23 +00001415/* computes gcd(z1, z2)
1416 based on Knuth's modified gcd algorithm (I think?)
1417 gcd(z1, z2) >= 0
1418 gcd(0, 0) = 0
1419 gcd(z, 0) = abs(z)
1420*/
1421mpz_t *mpz_gcd(const mpz_t *z1, const mpz_t *z2) {
1422 if (z1->len == 0) {
1423 mpz_t *a = mpz_clone(z2);
1424 a->neg = 0;
1425 return a;
1426 } else if (z2->len == 0) {
1427 mpz_t *a = mpz_clone(z1);
1428 a->neg = 0;
1429 return a;
1430 }
1431
1432 mpz_t *a = mpz_clone(z1);
1433 mpz_t *b = mpz_clone(z2);
1434 mpz_t c; mpz_init_zero(&c);
1435 a->neg = 0;
1436 b->neg = 0;
1437
1438 for (;;) {
1439 if (mpz_cmp(a, b) < 0) {
1440 if (a->len == 0) {
1441 mpz_free(a);
1442 mpz_deinit(&c);
1443 return b;
1444 }
1445 mpz_t *t = a; a = b; b = t;
1446 }
1447 if (!(b->len >= 2 || (b->len == 1 && b->dig[0] > 1))) { // compute b > 0; could be mpz_cmp_small_int(b, 1) > 0
1448 break;
1449 }
1450 mpz_set(&c, b);
1451 do {
1452 mpz_add_inpl(&c, &c, &c);
1453 } while (mpz_cmp(&c, a) <= 0);
1454 c.len = mpn_shr(c.dig, c.dig, c.len, 1);
1455 mpz_sub_inpl(a, a, &c);
1456 }
1457
1458 mpz_deinit(&c);
1459
1460 if (b->len == 1 && b->dig[0] == 1) { // compute b == 1; could be mpz_cmp_small_int(b, 1) == 0
1461 mpz_free(a);
1462 return b;
1463 } else {
1464 mpz_free(b);
1465 return a;
1466 }
1467}
1468
1469/* computes lcm(z1, z2)
1470 = abs(z1) / gcd(z1, z2) * abs(z2)
1471 lcm(z1, z1) >= 0
1472 lcm(0, 0) = 0
1473 lcm(z, 0) = 0
1474*/
Damien George5d9b8162014-08-07 14:27:48 +00001475mpz_t *mpz_lcm(const mpz_t *z1, const mpz_t *z2) {
1476 if (z1->len == 0 || z2->len == 0) {
1477 return mpz_zero();
stijn01d6be42014-05-05 12:18:27 +02001478 }
Damien George438c88d2014-02-22 19:25:23 +00001479
1480 mpz_t *gcd = mpz_gcd(z1, z2);
1481 mpz_t *quo = mpz_zero();
1482 mpz_t *rem = mpz_zero();
1483 mpz_divmod_inpl(quo, rem, z1, gcd);
1484 mpz_mul_inpl(rem, quo, z2);
1485 mpz_free(gcd);
1486 mpz_free(quo);
1487 rem->neg = 0;
1488 return rem;
1489}
Damien Georgea2e38382015-03-02 12:58:06 +00001490#endif
Damien George438c88d2014-02-22 19:25:23 +00001491
1492/* computes new integers in quo and rem such that:
1493 quo * rhs + rem = lhs
1494 0 <= rem < rhs
1495 can have lhs, rhs the same
1496*/
1497void mpz_divmod_inpl(mpz_t *dest_quo, mpz_t *dest_rem, const mpz_t *lhs, const mpz_t *rhs) {
1498 if (rhs->len == 0) {
1499 mpz_set_from_int(dest_quo, 0);
1500 mpz_set_from_int(dest_rem, 0);
1501 return;
1502 }
1503
1504 mpz_need_dig(dest_quo, lhs->len + 1); // +1 necessary?
1505 memset(dest_quo->dig, 0, (lhs->len + 1) * sizeof(mpz_dig_t));
1506 dest_quo->len = 0;
1507 mpz_need_dig(dest_rem, lhs->len + 1); // +1 necessary?
1508 mpz_set(dest_rem, lhs);
1509 //rhs->dig[rhs->len] = 0;
1510 mpn_div(dest_rem->dig, &dest_rem->len, rhs->dig, rhs->len, dest_quo->dig, &dest_quo->len);
1511
Damien George65402ab2016-05-08 22:21:21 +01001512 // check signs and do Python style modulo
Damien George438c88d2014-02-22 19:25:23 +00001513 if (lhs->neg != rhs->neg) {
1514 dest_quo->neg = 1;
Damien George65402ab2016-05-08 22:21:21 +01001515 if (!mpz_is_zero(dest_rem)) {
1516 mpz_t mpzone; mpz_init_from_int(&mpzone, -1);
1517 mpz_add_inpl(dest_quo, dest_quo, &mpzone);
1518 mpz_add_inpl(dest_rem, dest_rem, rhs);
1519 }
Damien George438c88d2014-02-22 19:25:23 +00001520 }
1521}
1522
1523#if 0
1524these functions are unused
1525
1526/* computes floor(lhs / rhs)
1527 can have lhs, rhs the same
1528*/
1529mpz_t *mpz_div(const mpz_t *lhs, const mpz_t *rhs) {
1530 mpz_t *quo = mpz_zero();
1531 mpz_t rem; mpz_init_zero(&rem);
1532 mpz_divmod_inpl(quo, &rem, lhs, rhs);
1533 mpz_deinit(&rem);
1534 return quo;
1535}
1536
1537/* computes lhs % rhs ( >= 0)
1538 can have lhs, rhs the same
1539*/
1540mpz_t *mpz_mod(const mpz_t *lhs, const mpz_t *rhs) {
1541 mpz_t quo; mpz_init_zero(&quo);
1542 mpz_t *rem = mpz_zero();
1543 mpz_divmod_inpl(&quo, rem, lhs, rhs);
1544 mpz_deinit(&quo);
1545 return rem;
1546}
1547#endif
1548
Damien Georgeffe911d2014-07-24 14:21:37 +01001549// must return actual int value if it fits in mp_int_t
1550mp_int_t mpz_hash(const mpz_t *z) {
1551 mp_int_t val = 0;
1552 mpz_dig_t *d = z->dig + z->len;
1553
Damien George58056b02015-01-09 20:58:58 +00001554 while (d-- > z->dig) {
Damien Georgeffe911d2014-07-24 14:21:37 +01001555 val = (val << DIG_SIZE) | *d;
1556 }
1557
1558 if (z->neg != 0) {
1559 val = -val;
1560 }
1561
1562 return val;
1563}
1564
Damien George40f3c022014-07-03 13:25:24 +01001565bool mpz_as_int_checked(const mpz_t *i, mp_int_t *value) {
Damien George963a5a32015-01-16 17:47:07 +00001566 mp_uint_t val = 0;
Damien George8270e382014-04-03 11:00:54 +00001567 mpz_dig_t *d = i->dig + i->len;
1568
Damien George58056b02015-01-09 20:58:58 +00001569 while (d-- > i->dig) {
Damien Georgec9aa58e2014-07-31 13:41:43 +00001570 if (val > (~(WORD_MSBIT_HIGH) >> DIG_SIZE)) {
1571 // will overflow
Damien George8270e382014-04-03 11:00:54 +00001572 return false;
1573 }
Damien Georgec9aa58e2014-07-31 13:41:43 +00001574 val = (val << DIG_SIZE) | *d;
Damien George8270e382014-04-03 11:00:54 +00001575 }
1576
1577 if (i->neg != 0) {
1578 val = -val;
1579 }
1580
1581 *value = val;
1582 return true;
1583}
1584
Damien Georgec9aa58e2014-07-31 13:41:43 +00001585bool mpz_as_uint_checked(const mpz_t *i, mp_uint_t *value) {
1586 if (i->neg != 0) {
1587 // can't represent signed values
1588 return false;
1589 }
1590
1591 mp_uint_t val = 0;
1592 mpz_dig_t *d = i->dig + i->len;
1593
Damien George58056b02015-01-09 20:58:58 +00001594 while (d-- > i->dig) {
Damien George9a21d2e2014-09-06 17:15:34 +01001595 if (val > (~(WORD_MSBIT_HIGH) >> (DIG_SIZE - 1))) {
Damien Georgec9aa58e2014-07-31 13:41:43 +00001596 // will overflow
1597 return false;
1598 }
1599 val = (val << DIG_SIZE) | *d;
1600 }
1601
1602 *value = val;
1603 return true;
1604}
1605
Damien George271d18e2015-04-25 23:16:39 +01001606// writes at most len bytes to buf (so buf should be zeroed before calling)
1607void mpz_as_bytes(const mpz_t *z, bool big_endian, mp_uint_t len, byte *buf) {
1608 byte *b = buf;
1609 if (big_endian) {
1610 b += len;
1611 }
1612 mpz_dig_t *zdig = z->dig;
1613 int bits = 0;
1614 mpz_dbl_dig_t d = 0;
1615 mpz_dbl_dig_t carry = 1;
1616 for (mp_uint_t zlen = z->len; zlen > 0; --zlen) {
1617 bits += DIG_SIZE;
1618 d = (d << DIG_SIZE) | *zdig++;
1619 for (; bits >= 8; bits -= 8, d >>= 8) {
1620 mpz_dig_t val = d;
1621 if (z->neg) {
Damien George94729072015-04-25 23:51:14 +01001622 val = (~val & 0xff) + carry;
1623 carry = val >> 8;
Damien George271d18e2015-04-25 23:16:39 +01001624 }
1625 if (big_endian) {
1626 *--b = val;
1627 if (b == buf) {
1628 return;
1629 }
1630 } else {
1631 *b++ = val;
1632 if (b == buf + len) {
1633 return;
1634 }
1635 }
1636 }
1637 }
1638}
1639
Damien Georgefb510b32014-06-01 13:32:54 +01001640#if MICROPY_PY_BUILTINS_FLOAT
Damien George52608102014-03-08 15:04:54 +00001641mp_float_t mpz_as_float(const mpz_t *i) {
1642 mp_float_t val = 0;
Damien George438c88d2014-02-22 19:25:23 +00001643 mpz_dig_t *d = i->dig + i->len;
1644
Damien George58056b02015-01-09 20:58:58 +00001645 while (d-- > i->dig) {
Damien George9a21d2e2014-09-06 17:15:34 +01001646 val = val * DIG_BASE + *d;
Damien George438c88d2014-02-22 19:25:23 +00001647 }
1648
1649 if (i->neg != 0) {
1650 val = -val;
1651 }
1652
1653 return val;
1654}
Damien George52608102014-03-08 15:04:54 +00001655#endif
Damien George438c88d2014-02-22 19:25:23 +00001656
Damien Georgeafb1cf72014-09-05 20:37:06 +01001657mp_uint_t mpz_as_str_size(const mpz_t *i, mp_uint_t base, const char *prefix, char comma) {
Damien George438c88d2014-02-22 19:25:23 +00001658 if (base < 2 || base > 32) {
1659 return 0;
1660 }
1661
Damien Georgeafb1cf72014-09-05 20:37:06 +01001662 mp_uint_t num_digits = i->len * DIG_SIZE / log_base2_floor[base] + 1;
1663 mp_uint_t num_commas = comma ? num_digits / 3: 0;
1664 mp_uint_t prefix_len = prefix ? strlen(prefix) : 0;
Dave Hylandsc4029e52014-04-07 11:19:51 -07001665
1666 return num_digits + num_commas + prefix_len + 2; // +1 for sign, +1 for null byte
1667}
1668
Damien Georgeafb1cf72014-09-05 20:37:06 +01001669#if 0
1670this function is unused
1671char *mpz_as_str(const mpz_t *i, mp_uint_t base) {
1672 char *s = m_new(char, mpz_as_str_size(i, base, NULL, '\0'));
1673 mpz_as_str_inpl(i, base, NULL, 'a', '\0', s);
Damien George438c88d2014-02-22 19:25:23 +00001674 return s;
1675}
Damien Georgeafb1cf72014-09-05 20:37:06 +01001676#endif
Damien George438c88d2014-02-22 19:25:23 +00001677
1678// assumes enough space as calculated by mpz_as_str_size
1679// returns length of string, not including null byte
Damien Georgeafb1cf72014-09-05 20:37:06 +01001680mp_uint_t mpz_as_str_inpl(const mpz_t *i, mp_uint_t base, const char *prefix, char base_char, char comma, char *str) {
Damien George438c88d2014-02-22 19:25:23 +00001681 if (str == NULL || base < 2 || base > 32) {
1682 str[0] = 0;
1683 return 0;
1684 }
1685
Damien Georgeafb1cf72014-09-05 20:37:06 +01001686 mp_uint_t ilen = i->len;
Damien George438c88d2014-02-22 19:25:23 +00001687
Dave Hylandsc4029e52014-04-07 11:19:51 -07001688 char *s = str;
Damien George438c88d2014-02-22 19:25:23 +00001689 if (ilen == 0) {
Dave Hylandsc4029e52014-04-07 11:19:51 -07001690 if (prefix) {
1691 while (*prefix)
1692 *s++ = *prefix++;
1693 }
1694 *s++ = '0';
1695 *s = '\0';
1696 return s - str;
Damien George438c88d2014-02-22 19:25:23 +00001697 }
1698
Damien Georgeeec91052014-04-08 23:11:00 +01001699 // make a copy of mpz digits, so we can do the div/mod calculation
Damien George438c88d2014-02-22 19:25:23 +00001700 mpz_dig_t *dig = m_new(mpz_dig_t, ilen);
1701 memcpy(dig, i->dig, ilen * sizeof(mpz_dig_t));
1702
1703 // convert
Dave Hylandsc4029e52014-04-07 11:19:51 -07001704 char *last_comma = str;
Damien George438c88d2014-02-22 19:25:23 +00001705 bool done;
1706 do {
1707 mpz_dig_t *d = dig + ilen;
1708 mpz_dbl_dig_t a = 0;
1709
1710 // compute next remainder
1711 while (--d >= dig) {
1712 a = (a << DIG_SIZE) | *d;
1713 *d = a / base;
1714 a %= base;
1715 }
1716
1717 // convert to character
1718 a += '0';
1719 if (a > '9') {
Dave Hylandsc4029e52014-04-07 11:19:51 -07001720 a += base_char - '9' - 1;
Damien George438c88d2014-02-22 19:25:23 +00001721 }
1722 *s++ = a;
1723
1724 // check if number is zero
1725 done = true;
1726 for (d = dig; d < dig + ilen; ++d) {
1727 if (*d != 0) {
1728 done = false;
1729 break;
1730 }
1731 }
Dave Hylandsc4029e52014-04-07 11:19:51 -07001732 if (comma && (s - last_comma) == 3) {
1733 *s++ = comma;
1734 last_comma = s;
1735 }
1736 }
1737 while (!done);
Damien George438c88d2014-02-22 19:25:23 +00001738
Damien Georgeeec91052014-04-08 23:11:00 +01001739 // free the copy of the digits array
1740 m_del(mpz_dig_t, dig, ilen);
1741
Dave Hylandsc4029e52014-04-07 11:19:51 -07001742 if (prefix) {
1743 const char *p = &prefix[strlen(prefix)];
1744 while (p > prefix) {
1745 *s++ = *--p;
1746 }
1747 }
Damien George438c88d2014-02-22 19:25:23 +00001748 if (i->neg != 0) {
1749 *s++ = '-';
1750 }
1751
1752 // reverse string
1753 for (char *u = str, *v = s - 1; u < v; ++u, --v) {
1754 char temp = *u;
1755 *u = *v;
1756 *v = temp;
1757 }
1758
Dave Hylandsc4029e52014-04-07 11:19:51 -07001759 *s = '\0'; // null termination
Damien George438c88d2014-02-22 19:25:23 +00001760
1761 return s - str;
1762}
1763
1764#endif // MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_MPZ