blob: f02b75c2be83e9b7227ae62e50e6dccd18bc66f9 [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;
494 carry = d >> (DIG_SIZE - norm_shift);
495 }
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;
504 carry = n >> (DIG_SIZE - norm_shift);
505 }
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;
621 carry = d << (DIG_SIZE - norm_shift);
622 }
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;
628 carry = n << (DIG_SIZE - norm_shift);
629 }
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 George438c88d2014-02-22 19:25:23 +00001377/* computes gcd(z1, z2)
1378 based on Knuth's modified gcd algorithm (I think?)
1379 gcd(z1, z2) >= 0
1380 gcd(0, 0) = 0
1381 gcd(z, 0) = abs(z)
1382*/
1383mpz_t *mpz_gcd(const mpz_t *z1, const mpz_t *z2) {
1384 if (z1->len == 0) {
1385 mpz_t *a = mpz_clone(z2);
1386 a->neg = 0;
1387 return a;
1388 } else if (z2->len == 0) {
1389 mpz_t *a = mpz_clone(z1);
1390 a->neg = 0;
1391 return a;
1392 }
1393
1394 mpz_t *a = mpz_clone(z1);
1395 mpz_t *b = mpz_clone(z2);
1396 mpz_t c; mpz_init_zero(&c);
1397 a->neg = 0;
1398 b->neg = 0;
1399
1400 for (;;) {
1401 if (mpz_cmp(a, b) < 0) {
1402 if (a->len == 0) {
1403 mpz_free(a);
1404 mpz_deinit(&c);
1405 return b;
1406 }
1407 mpz_t *t = a; a = b; b = t;
1408 }
1409 if (!(b->len >= 2 || (b->len == 1 && b->dig[0] > 1))) { // compute b > 0; could be mpz_cmp_small_int(b, 1) > 0
1410 break;
1411 }
1412 mpz_set(&c, b);
1413 do {
1414 mpz_add_inpl(&c, &c, &c);
1415 } while (mpz_cmp(&c, a) <= 0);
1416 c.len = mpn_shr(c.dig, c.dig, c.len, 1);
1417 mpz_sub_inpl(a, a, &c);
1418 }
1419
1420 mpz_deinit(&c);
1421
1422 if (b->len == 1 && b->dig[0] == 1) { // compute b == 1; could be mpz_cmp_small_int(b, 1) == 0
1423 mpz_free(a);
1424 return b;
1425 } else {
1426 mpz_free(b);
1427 return a;
1428 }
1429}
1430
1431/* computes lcm(z1, z2)
1432 = abs(z1) / gcd(z1, z2) * abs(z2)
1433 lcm(z1, z1) >= 0
1434 lcm(0, 0) = 0
1435 lcm(z, 0) = 0
1436*/
Damien George5d9b8162014-08-07 14:27:48 +00001437mpz_t *mpz_lcm(const mpz_t *z1, const mpz_t *z2) {
1438 if (z1->len == 0 || z2->len == 0) {
1439 return mpz_zero();
stijn01d6be42014-05-05 12:18:27 +02001440 }
Damien George438c88d2014-02-22 19:25:23 +00001441
1442 mpz_t *gcd = mpz_gcd(z1, z2);
1443 mpz_t *quo = mpz_zero();
1444 mpz_t *rem = mpz_zero();
1445 mpz_divmod_inpl(quo, rem, z1, gcd);
1446 mpz_mul_inpl(rem, quo, z2);
1447 mpz_free(gcd);
1448 mpz_free(quo);
1449 rem->neg = 0;
1450 return rem;
1451}
Damien Georgea2e38382015-03-02 12:58:06 +00001452#endif
Damien George438c88d2014-02-22 19:25:23 +00001453
1454/* computes new integers in quo and rem such that:
1455 quo * rhs + rem = lhs
1456 0 <= rem < rhs
1457 can have lhs, rhs the same
1458*/
1459void mpz_divmod_inpl(mpz_t *dest_quo, mpz_t *dest_rem, const mpz_t *lhs, const mpz_t *rhs) {
1460 if (rhs->len == 0) {
1461 mpz_set_from_int(dest_quo, 0);
1462 mpz_set_from_int(dest_rem, 0);
1463 return;
1464 }
1465
1466 mpz_need_dig(dest_quo, lhs->len + 1); // +1 necessary?
1467 memset(dest_quo->dig, 0, (lhs->len + 1) * sizeof(mpz_dig_t));
1468 dest_quo->len = 0;
1469 mpz_need_dig(dest_rem, lhs->len + 1); // +1 necessary?
1470 mpz_set(dest_rem, lhs);
1471 //rhs->dig[rhs->len] = 0;
1472 mpn_div(dest_rem->dig, &dest_rem->len, rhs->dig, rhs->len, dest_quo->dig, &dest_quo->len);
1473
1474 if (lhs->neg != rhs->neg) {
1475 dest_quo->neg = 1;
1476 }
1477}
1478
1479#if 0
1480these functions are unused
1481
1482/* computes floor(lhs / rhs)
1483 can have lhs, rhs the same
1484*/
1485mpz_t *mpz_div(const mpz_t *lhs, const mpz_t *rhs) {
1486 mpz_t *quo = mpz_zero();
1487 mpz_t rem; mpz_init_zero(&rem);
1488 mpz_divmod_inpl(quo, &rem, lhs, rhs);
1489 mpz_deinit(&rem);
1490 return quo;
1491}
1492
1493/* computes lhs % rhs ( >= 0)
1494 can have lhs, rhs the same
1495*/
1496mpz_t *mpz_mod(const mpz_t *lhs, const mpz_t *rhs) {
1497 mpz_t quo; mpz_init_zero(&quo);
1498 mpz_t *rem = mpz_zero();
1499 mpz_divmod_inpl(&quo, rem, lhs, rhs);
1500 mpz_deinit(&quo);
1501 return rem;
1502}
1503#endif
1504
Damien Georgeffe911d2014-07-24 14:21:37 +01001505// must return actual int value if it fits in mp_int_t
1506mp_int_t mpz_hash(const mpz_t *z) {
1507 mp_int_t val = 0;
1508 mpz_dig_t *d = z->dig + z->len;
1509
Damien George58056b02015-01-09 20:58:58 +00001510 while (d-- > z->dig) {
Damien Georgeffe911d2014-07-24 14:21:37 +01001511 val = (val << DIG_SIZE) | *d;
1512 }
1513
1514 if (z->neg != 0) {
1515 val = -val;
1516 }
1517
1518 return val;
1519}
1520
Damien George40f3c022014-07-03 13:25:24 +01001521bool mpz_as_int_checked(const mpz_t *i, mp_int_t *value) {
Damien George963a5a32015-01-16 17:47:07 +00001522 mp_uint_t val = 0;
Damien George8270e382014-04-03 11:00:54 +00001523 mpz_dig_t *d = i->dig + i->len;
1524
Damien George58056b02015-01-09 20:58:58 +00001525 while (d-- > i->dig) {
Damien Georgec9aa58e2014-07-31 13:41:43 +00001526 if (val > (~(WORD_MSBIT_HIGH) >> DIG_SIZE)) {
1527 // will overflow
Damien George8270e382014-04-03 11:00:54 +00001528 return false;
1529 }
Damien Georgec9aa58e2014-07-31 13:41:43 +00001530 val = (val << DIG_SIZE) | *d;
Damien George8270e382014-04-03 11:00:54 +00001531 }
1532
1533 if (i->neg != 0) {
1534 val = -val;
1535 }
1536
1537 *value = val;
1538 return true;
1539}
1540
Damien Georgec9aa58e2014-07-31 13:41:43 +00001541bool mpz_as_uint_checked(const mpz_t *i, mp_uint_t *value) {
1542 if (i->neg != 0) {
1543 // can't represent signed values
1544 return false;
1545 }
1546
1547 mp_uint_t val = 0;
1548 mpz_dig_t *d = i->dig + i->len;
1549
Damien George58056b02015-01-09 20:58:58 +00001550 while (d-- > i->dig) {
Damien George9a21d2e2014-09-06 17:15:34 +01001551 if (val > (~(WORD_MSBIT_HIGH) >> (DIG_SIZE - 1))) {
Damien Georgec9aa58e2014-07-31 13:41:43 +00001552 // will overflow
1553 return false;
1554 }
1555 val = (val << DIG_SIZE) | *d;
1556 }
1557
1558 *value = val;
1559 return true;
1560}
1561
Damien George271d18e2015-04-25 23:16:39 +01001562// writes at most len bytes to buf (so buf should be zeroed before calling)
1563void mpz_as_bytes(const mpz_t *z, bool big_endian, mp_uint_t len, byte *buf) {
1564 byte *b = buf;
1565 if (big_endian) {
1566 b += len;
1567 }
1568 mpz_dig_t *zdig = z->dig;
1569 int bits = 0;
1570 mpz_dbl_dig_t d = 0;
1571 mpz_dbl_dig_t carry = 1;
1572 for (mp_uint_t zlen = z->len; zlen > 0; --zlen) {
1573 bits += DIG_SIZE;
1574 d = (d << DIG_SIZE) | *zdig++;
1575 for (; bits >= 8; bits -= 8, d >>= 8) {
1576 mpz_dig_t val = d;
1577 if (z->neg) {
Damien George94729072015-04-25 23:51:14 +01001578 val = (~val & 0xff) + carry;
1579 carry = val >> 8;
Damien George271d18e2015-04-25 23:16:39 +01001580 }
1581 if (big_endian) {
1582 *--b = val;
1583 if (b == buf) {
1584 return;
1585 }
1586 } else {
1587 *b++ = val;
1588 if (b == buf + len) {
1589 return;
1590 }
1591 }
1592 }
1593 }
1594}
1595
Damien Georgefb510b32014-06-01 13:32:54 +01001596#if MICROPY_PY_BUILTINS_FLOAT
Damien George52608102014-03-08 15:04:54 +00001597mp_float_t mpz_as_float(const mpz_t *i) {
1598 mp_float_t val = 0;
Damien George438c88d2014-02-22 19:25:23 +00001599 mpz_dig_t *d = i->dig + i->len;
1600
Damien George58056b02015-01-09 20:58:58 +00001601 while (d-- > i->dig) {
Damien George9a21d2e2014-09-06 17:15:34 +01001602 val = val * DIG_BASE + *d;
Damien George438c88d2014-02-22 19:25:23 +00001603 }
1604
1605 if (i->neg != 0) {
1606 val = -val;
1607 }
1608
1609 return val;
1610}
Damien George52608102014-03-08 15:04:54 +00001611#endif
Damien George438c88d2014-02-22 19:25:23 +00001612
Damien Georgeafb1cf72014-09-05 20:37:06 +01001613mp_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 +00001614 if (base < 2 || base > 32) {
1615 return 0;
1616 }
1617
Damien Georgeafb1cf72014-09-05 20:37:06 +01001618 mp_uint_t num_digits = i->len * DIG_SIZE / log_base2_floor[base] + 1;
1619 mp_uint_t num_commas = comma ? num_digits / 3: 0;
1620 mp_uint_t prefix_len = prefix ? strlen(prefix) : 0;
Dave Hylandsc4029e52014-04-07 11:19:51 -07001621
1622 return num_digits + num_commas + prefix_len + 2; // +1 for sign, +1 for null byte
1623}
1624
Damien Georgeafb1cf72014-09-05 20:37:06 +01001625#if 0
1626this function is unused
1627char *mpz_as_str(const mpz_t *i, mp_uint_t base) {
1628 char *s = m_new(char, mpz_as_str_size(i, base, NULL, '\0'));
1629 mpz_as_str_inpl(i, base, NULL, 'a', '\0', s);
Damien George438c88d2014-02-22 19:25:23 +00001630 return s;
1631}
Damien Georgeafb1cf72014-09-05 20:37:06 +01001632#endif
Damien George438c88d2014-02-22 19:25:23 +00001633
1634// assumes enough space as calculated by mpz_as_str_size
1635// returns length of string, not including null byte
Damien Georgeafb1cf72014-09-05 20:37:06 +01001636mp_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 +00001637 if (str == NULL || base < 2 || base > 32) {
1638 str[0] = 0;
1639 return 0;
1640 }
1641
Damien Georgeafb1cf72014-09-05 20:37:06 +01001642 mp_uint_t ilen = i->len;
Damien George438c88d2014-02-22 19:25:23 +00001643
Dave Hylandsc4029e52014-04-07 11:19:51 -07001644 char *s = str;
Damien George438c88d2014-02-22 19:25:23 +00001645 if (ilen == 0) {
Dave Hylandsc4029e52014-04-07 11:19:51 -07001646 if (prefix) {
1647 while (*prefix)
1648 *s++ = *prefix++;
1649 }
1650 *s++ = '0';
1651 *s = '\0';
1652 return s - str;
Damien George438c88d2014-02-22 19:25:23 +00001653 }
1654
Damien Georgeeec91052014-04-08 23:11:00 +01001655 // make a copy of mpz digits, so we can do the div/mod calculation
Damien George438c88d2014-02-22 19:25:23 +00001656 mpz_dig_t *dig = m_new(mpz_dig_t, ilen);
1657 memcpy(dig, i->dig, ilen * sizeof(mpz_dig_t));
1658
1659 // convert
Dave Hylandsc4029e52014-04-07 11:19:51 -07001660 char *last_comma = str;
Damien George438c88d2014-02-22 19:25:23 +00001661 bool done;
1662 do {
1663 mpz_dig_t *d = dig + ilen;
1664 mpz_dbl_dig_t a = 0;
1665
1666 // compute next remainder
1667 while (--d >= dig) {
1668 a = (a << DIG_SIZE) | *d;
1669 *d = a / base;
1670 a %= base;
1671 }
1672
1673 // convert to character
1674 a += '0';
1675 if (a > '9') {
Dave Hylandsc4029e52014-04-07 11:19:51 -07001676 a += base_char - '9' - 1;
Damien George438c88d2014-02-22 19:25:23 +00001677 }
1678 *s++ = a;
1679
1680 // check if number is zero
1681 done = true;
1682 for (d = dig; d < dig + ilen; ++d) {
1683 if (*d != 0) {
1684 done = false;
1685 break;
1686 }
1687 }
Dave Hylandsc4029e52014-04-07 11:19:51 -07001688 if (comma && (s - last_comma) == 3) {
1689 *s++ = comma;
1690 last_comma = s;
1691 }
1692 }
1693 while (!done);
Damien George438c88d2014-02-22 19:25:23 +00001694
Damien Georgeeec91052014-04-08 23:11:00 +01001695 // free the copy of the digits array
1696 m_del(mpz_dig_t, dig, ilen);
1697
Dave Hylandsc4029e52014-04-07 11:19:51 -07001698 if (prefix) {
1699 const char *p = &prefix[strlen(prefix)];
1700 while (p > prefix) {
1701 *s++ = *--p;
1702 }
1703 }
Damien George438c88d2014-02-22 19:25:23 +00001704 if (i->neg != 0) {
1705 *s++ = '-';
1706 }
1707
1708 // reverse string
1709 for (char *u = str, *v = s - 1; u < v; ++u, --v) {
1710 char temp = *u;
1711 *u = *v;
1712 *v = temp;
1713 }
1714
Dave Hylandsc4029e52014-04-07 11:19:51 -07001715 *s = '\0'; // null termination
Damien George438c88d2014-02-22 19:25:23 +00001716
1717 return s - str;
1718}
1719
1720#endif // MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_MPZ