blob: 72d226cb3f5b870ff56389ef38980611b1cf6d4f [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 Georgedcdcc432017-02-16 15:50:28 +110056STATIC int mpn_cmp(const mpz_dig_t *idig, size_t ilen, const mpz_dig_t *jdig, size_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 Georgedcdcc432017-02-16 15:50:28 +110074STATIC size_t mpn_shl(mpz_dig_t *idig, mpz_dig_t *jdig, size_t jlen, mp_uint_t n) {
Damien Georgeafb1cf72014-09-05 20:37:06 +010075 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 Georgedcdcc432017-02-16 15:50:28 +110087 for (size_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 Georgedcdcc432017-02-16 15:50:28 +1100113STATIC size_t mpn_shr(mpz_dig_t *idig, mpz_dig_t *jdig, size_t jlen, mp_uint_t n) {
Damien Georgeafb1cf72014-09-05 20:37:06 +0100114 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 Georgedcdcc432017-02-16 15:50:28 +1100124 for (size_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 Georgedcdcc432017-02-16 15:50:28 +1100145STATIC size_t mpn_add(mpz_dig_t *idig, const mpz_dig_t *jdig, size_t jlen, const mpz_dig_t *kdig, size_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 Georgedcdcc432017-02-16 15:50:28 +1100175STATIC size_t mpn_sub(mpz_dig_t *idig, const mpz_dig_t *jdig, size_t jlen, const mpz_dig_t *kdig, size_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
Damien Georgedcdcc432017-02-16 15:50:28 +1100199STATIC size_t mpn_remove_trailing_zeros(mpz_dig_t *oidig, mpz_dig_t *idig) {
Doug Currie2e2e15c2016-01-30 22:35:58 -0500200 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 Georgedcdcc432017-02-16 15:50:28 +1100212STATIC size_t mpn_and(mpz_dig_t *idig, const mpz_dig_t *jdig, const mpz_dig_t *kdig, size_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*/
Damien Georgedcdcc432017-02-16 15:50:28 +1100233STATIC size_t mpn_and_neg(mpz_dig_t *idig, const mpz_dig_t *jdig, size_t jlen, const mpz_dig_t *kdig, size_t klen,
Doug Currie2e2e15c2016-01-30 22:35:58 -0500234 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 Georgedcdcc432017-02-16 15:50:28 +1100264STATIC size_t mpn_or(mpz_dig_t *idig, const mpz_dig_t *jdig, size_t jlen, const mpz_dig_t *kdig, size_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
Damien Georgedcdcc432017-02-16 15:50:28 +1100294STATIC size_t mpn_or_neg(mpz_dig_t *idig, const mpz_dig_t *jdig, size_t jlen, const mpz_dig_t *kdig, size_t klen,
Doug Currie2e2e15c2016-01-30 22:35:58 -0500295 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
Damien Georgee83f1402016-12-14 10:39:41 +1100311 // At least one of j,k must be negative so the above for-loop runs at least
312 // once. For carryi to be non-zero here it must be equal to 1 at the end of
313 // each iteration of the loop. So the accumulation of carryi must overflow
314 // each time, ie carryi += 0xff..ff. So carryj|carryk must be 0 in the
315 // DIG_MASK bits on each iteration. But considering all cases of signs of
316 // j,k one sees that this is not possible.
317 assert(carryi == 0);
Doug Currie2e2e15c2016-01-30 22:35:58 -0500318
319 return mpn_remove_trailing_zeros(oidig, idig);
320}
321
322#else
323
Damien Georgedcdcc432017-02-16 15:50:28 +1100324STATIC size_t mpn_or_neg(mpz_dig_t *idig, const mpz_dig_t *jdig, size_t jlen, const mpz_dig_t *kdig, size_t klen,
Doug Currie2e2e15c2016-01-30 22:35:58 -0500325 mpz_dbl_dig_t carryi, mpz_dbl_dig_t carryj, mpz_dbl_dig_t carryk) {
326 mpz_dig_t *oidig = idig;
327 mpz_dig_t imask = (0 == carryi) ? 0 : DIG_MASK;
328 mpz_dig_t jmask = (0 == carryj) ? 0 : DIG_MASK;
329 mpz_dig_t kmask = (0 == carryk) ? 0 : DIG_MASK;
330
331 for (; jlen > 0; ++idig, ++jdig) {
332 carryj += *jdig ^ jmask;
333 carryk += (--klen <= --jlen) ? (*kdig++ ^ kmask) : kmask;
334 carryi += ((carryj | carryk) ^ imask) & DIG_MASK;
335 *idig = carryi & DIG_MASK;
336 carryk >>= DIG_SIZE;
337 carryj >>= DIG_SIZE;
338 carryi >>= DIG_SIZE;
339 }
340
Damien Georgee83f1402016-12-14 10:39:41 +1100341 // See comment in above mpn_or_neg for why carryi must be 0.
342 assert(carryi == 0);
Doug Currie2e2e15c2016-01-30 22:35:58 -0500343
344 return mpn_remove_trailing_zeros(oidig, idig);
345}
346
347#endif
348
349#if MICROPY_OPT_MPZ_BITWISE
350
Paul Sokolovsky57207b82014-03-23 01:52:36 +0200351/* computes i = j ^ k
352 returns number of digits in i
353 assumes enough memory in i; assumes normalised j, k; assumes jlen >= klen
354 can have i, j, k pointing to same memory
355*/
Damien Georgedcdcc432017-02-16 15:50:28 +1100356STATIC size_t mpn_xor(mpz_dig_t *idig, const mpz_dig_t *jdig, size_t jlen, const mpz_dig_t *kdig, size_t klen) {
Paul Sokolovsky57207b82014-03-23 01:52:36 +0200357 mpz_dig_t *oidig = idig;
358
359 jlen -= klen;
360
361 for (; klen > 0; --klen, ++idig, ++jdig, ++kdig) {
362 *idig = *jdig ^ *kdig;
363 }
364
365 for (; jlen > 0; --jlen, ++idig, ++jdig) {
366 *idig = *jdig;
367 }
368
Doug Currie2e2e15c2016-01-30 22:35:58 -0500369 return mpn_remove_trailing_zeros(oidig, idig);
370}
371
372#endif
373
374/* i = (-j) ^ (-k) = ~(j - 1) ^ ~(k - 1) = (j - 1) ^ (k - 1)
375 i = -(j ^ (-k)) = -(j ^ ~(k - 1)) = ~(j ^ ~(k - 1)) + 1 = (j ^ (k - 1)) + 1
376 i = -((-j) ^ k) = -(~(j - 1) ^ k) = ~(~(j - 1) ^ k) + 1 = ((j - 1) ^ k) + 1
377 computes general form:
378 i = ((j - 1 + jc) ^ (k - 1 + kc)) + ic
379 returns number of digits in i
380 assumes enough memory in i; assumes normalised j, k; assumes length j >= length k
381 can have i, j, k pointing to same memory
382*/
Damien Georgedcdcc432017-02-16 15:50:28 +1100383STATIC size_t mpn_xor_neg(mpz_dig_t *idig, const mpz_dig_t *jdig, size_t jlen, const mpz_dig_t *kdig, size_t klen,
Doug Currie2e2e15c2016-01-30 22:35:58 -0500384 mpz_dbl_dig_t carryi, mpz_dbl_dig_t carryj, mpz_dbl_dig_t carryk) {
385 mpz_dig_t *oidig = idig;
386
387 for (; jlen > 0; ++idig, ++jdig) {
388 carryj += *jdig + DIG_MASK;
389 carryk += (--klen <= --jlen) ? (*kdig++ + DIG_MASK) : DIG_MASK;
390 carryi += (carryj ^ carryk) & DIG_MASK;
391 *idig = carryi & DIG_MASK;
392 carryk >>= DIG_SIZE;
393 carryj >>= DIG_SIZE;
394 carryi >>= DIG_SIZE;
Paul Sokolovskyb3be4712015-11-22 22:03:18 +0200395 }
396
Doug Currie2e2e15c2016-01-30 22:35:58 -0500397 if (0 != carryi) {
398 *idig++ = carryi;
399 }
400
401 return mpn_remove_trailing_zeros(oidig, idig);
Paul Sokolovsky57207b82014-03-23 01:52:36 +0200402}
403
Damien George438c88d2014-02-22 19:25:23 +0000404/* computes i = i * d1 + d2
405 returns number of digits in i
406 assumes enough memory in i; assumes normalised i; assumes dmul != 0
407*/
Damien Georgedcdcc432017-02-16 15:50:28 +1100408STATIC size_t mpn_mul_dig_add_dig(mpz_dig_t *idig, size_t ilen, mpz_dig_t dmul, mpz_dig_t dadd) {
Damien George438c88d2014-02-22 19:25:23 +0000409 mpz_dig_t *oidig = idig;
410 mpz_dbl_dig_t carry = dadd;
411
412 for (; ilen > 0; --ilen, ++idig) {
Damien George9a21d2e2014-09-06 17:15:34 +0100413 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 +0000414 *idig = carry & DIG_MASK;
415 carry >>= DIG_SIZE;
416 }
417
418 if (carry != 0) {
419 *idig++ = carry;
420 }
421
422 return idig - oidig;
423}
424
425/* computes i = j * k
426 returns number of digits in i
427 assumes enough memory in i; assumes i is zeroed; assumes normalised j, k
428 can have j, k point to same memory
429*/
Damien Georgedcdcc432017-02-16 15:50:28 +1100430STATIC size_t mpn_mul(mpz_dig_t *idig, mpz_dig_t *jdig, size_t jlen, mpz_dig_t *kdig, size_t klen) {
Damien George438c88d2014-02-22 19:25:23 +0000431 mpz_dig_t *oidig = idig;
Damien Georgedcdcc432017-02-16 15:50:28 +1100432 size_t ilen = 0;
Damien George438c88d2014-02-22 19:25:23 +0000433
434 for (; klen > 0; --klen, ++idig, ++kdig) {
435 mpz_dig_t *id = idig;
436 mpz_dbl_dig_t carry = 0;
437
Damien Georgedcdcc432017-02-16 15:50:28 +1100438 size_t jl = jlen;
Damien George438c88d2014-02-22 19:25:23 +0000439 for (mpz_dig_t *jd = jdig; jl > 0; --jl, ++jd, ++id) {
Damien George9a21d2e2014-09-06 17:15:34 +0100440 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 +0000441 *id = carry & DIG_MASK;
442 carry >>= DIG_SIZE;
443 }
444
445 if (carry != 0) {
446 *id++ = carry;
447 }
448
449 ilen = id - oidig;
450 }
451
452 return ilen;
453}
454
455/* natural_div - quo * den + new_num = old_num (ie num is replaced with rem)
456 assumes den != 0
457 assumes num_dig has enough memory to be extended by 1 digit
458 assumes quo_dig has enough memory (as many digits as num)
459 assumes quo_dig is filled with zeros
Damien George438c88d2014-02-22 19:25:23 +0000460*/
Damien Georgedcdcc432017-02-16 15:50:28 +1100461STATIC void mpn_div(mpz_dig_t *num_dig, size_t *num_len, const mpz_dig_t *den_dig, size_t den_len, mpz_dig_t *quo_dig, size_t *quo_len) {
Damien George438c88d2014-02-22 19:25:23 +0000462 mpz_dig_t *orig_num_dig = num_dig;
463 mpz_dig_t *orig_quo_dig = quo_dig;
464 mpz_dig_t norm_shift = 0;
465 mpz_dbl_dig_t lead_den_digit;
466
467 // handle simple cases
468 {
Damien George42f3de92014-10-03 17:44:14 +0000469 int cmp = mpn_cmp(num_dig, *num_len, den_dig, den_len);
Damien George438c88d2014-02-22 19:25:23 +0000470 if (cmp == 0) {
471 *num_len = 0;
472 quo_dig[0] = 1;
473 *quo_len = 1;
474 return;
475 } else if (cmp < 0) {
476 // numerator remains the same
477 *quo_len = 0;
478 return;
479 }
480 }
481
Damien George460b0862016-05-09 17:21:42 +0100482 // We need to normalise the denominator (leading bit of leading digit is 1)
483 // so that the division routine works. Since the denominator memory is
484 // read-only we do the normalisation on the fly, each time a digit of the
485 // denominator is needed. We need to know is how many bits to shift by.
486
Damien George438c88d2014-02-22 19:25:23 +0000487 // count number of leading zeros in leading digit of denominator
488 {
489 mpz_dig_t d = den_dig[den_len - 1];
Damien George9a21d2e2014-09-06 17:15:34 +0100490 while ((d & DIG_MSB) == 0) {
Damien George438c88d2014-02-22 19:25:23 +0000491 d <<= 1;
492 ++norm_shift;
493 }
494 }
495
Damien George438c88d2014-02-22 19:25:23 +0000496 // now need to shift numerator by same amount as denominator
497 // first, increase length of numerator in case we need more room to shift
498 num_dig[*num_len] = 0;
499 ++(*num_len);
500 for (mpz_dig_t *num = num_dig, carry = 0; num < num_dig + *num_len; ++num) {
501 mpz_dig_t n = *num;
502 *num = ((n << norm_shift) | carry) & DIG_MASK;
Damien Georgedc3faea2016-05-08 21:38:43 +0100503 carry = (mpz_dbl_dig_t)n >> (DIG_SIZE - norm_shift);
Damien George438c88d2014-02-22 19:25:23 +0000504 }
505
506 // cache the leading digit of the denominator
Damien George460b0862016-05-09 17:21:42 +0100507 lead_den_digit = (mpz_dbl_dig_t)den_dig[den_len - 1] << norm_shift;
508 if (den_len >= 2) {
509 lead_den_digit |= (mpz_dbl_dig_t)den_dig[den_len - 2] >> (DIG_SIZE - norm_shift);
510 }
Damien George438c88d2014-02-22 19:25:23 +0000511
512 // point num_dig to last digit in numerator
513 num_dig += *num_len - 1;
514
515 // calculate number of digits in quotient
516 *quo_len = *num_len - den_len;
517
518 // point to last digit to store for quotient
519 quo_dig += *quo_len - 1;
520
521 // keep going while we have enough digits to divide
522 while (*num_len > den_len) {
Damien George9a21d2e2014-09-06 17:15:34 +0100523 mpz_dbl_dig_t quo = ((mpz_dbl_dig_t)*num_dig << DIG_SIZE) | num_dig[-1];
Damien George438c88d2014-02-22 19:25:23 +0000524
525 // get approximate quotient
526 quo /= lead_den_digit;
527
Damien George9a21d2e2014-09-06 17:15:34 +0100528 // Multiply quo by den and subtract from num to get remainder.
529 // We have different code here to handle different compile-time
530 // configurations of mpz:
531 //
532 // 1. DIG_SIZE is stricly less than half the number of bits
533 // available in mpz_dbl_dig_t. In this case we can use a
534 // slightly more optimal (in time and space) routine that
535 // uses the extra bits in mpz_dbl_dig_signed_t to store a
536 // sign bit.
537 //
538 // 2. DIG_SIZE is exactly half the number of bits available in
539 // mpz_dbl_dig_t. In this (common) case we need to be careful
540 // not to overflow the borrow variable. And the shifting of
541 // borrow needs some special logic (it's a shift right with
542 // round up).
543
544 if (DIG_SIZE < 8 * sizeof(mpz_dbl_dig_t) / 2) {
Damien George460b0862016-05-09 17:21:42 +0100545 const mpz_dig_t *d = den_dig;
546 mpz_dbl_dig_t d_norm = 0;
Damien George438c88d2014-02-22 19:25:23 +0000547 mpz_dbl_dig_signed_t borrow = 0;
548
Damien George460b0862016-05-09 17:21:42 +0100549 for (mpz_dig_t *n = num_dig - den_len; n < num_dig; ++n, ++d) {
550 d_norm = ((mpz_dbl_dig_t)*d << norm_shift) | (d_norm >> DIG_SIZE);
551 borrow += (mpz_dbl_dig_t)*n - (mpz_dbl_dig_t)quo * (d_norm & DIG_MASK); // will overflow if DIG_SIZE >= 8*sizeof(mpz_dbl_dig_t)/2
Damien George438c88d2014-02-22 19:25:23 +0000552 *n = borrow & DIG_MASK;
553 borrow >>= DIG_SIZE;
554 }
Damien George9a21d2e2014-09-06 17:15:34 +0100555 borrow += *num_dig; // will overflow if DIG_SIZE >= 8*sizeof(mpz_dbl_dig_t)/2
Damien George438c88d2014-02-22 19:25:23 +0000556 *num_dig = borrow & DIG_MASK;
557 borrow >>= DIG_SIZE;
558
559 // adjust quotient if it is too big
560 for (; borrow != 0; --quo) {
Damien George460b0862016-05-09 17:21:42 +0100561 d = den_dig;
562 d_norm = 0;
Damien George438c88d2014-02-22 19:25:23 +0000563 mpz_dbl_dig_t carry = 0;
Damien George460b0862016-05-09 17:21:42 +0100564 for (mpz_dig_t *n = num_dig - den_len; n < num_dig; ++n, ++d) {
565 d_norm = ((mpz_dbl_dig_t)*d << norm_shift) | (d_norm >> DIG_SIZE);
566 carry += (mpz_dbl_dig_t)*n + (d_norm & DIG_MASK);
Damien George438c88d2014-02-22 19:25:23 +0000567 *n = carry & DIG_MASK;
568 carry >>= DIG_SIZE;
569 }
570 carry += *num_dig;
571 *num_dig = carry & DIG_MASK;
572 carry >>= DIG_SIZE;
573
574 borrow += carry;
575 }
Damien George9a21d2e2014-09-06 17:15:34 +0100576 } else { // DIG_SIZE == 8 * sizeof(mpz_dbl_dig_t) / 2
Damien George460b0862016-05-09 17:21:42 +0100577 const mpz_dig_t *d = den_dig;
578 mpz_dbl_dig_t d_norm = 0;
Damien George9a21d2e2014-09-06 17:15:34 +0100579 mpz_dbl_dig_t borrow = 0;
580
Damien George460b0862016-05-09 17:21:42 +0100581 for (mpz_dig_t *n = num_dig - den_len; n < num_dig; ++n, ++d) {
582 d_norm = ((mpz_dbl_dig_t)*d << norm_shift) | (d_norm >> DIG_SIZE);
583 mpz_dbl_dig_t x = (mpz_dbl_dig_t)quo * (d_norm & DIG_MASK);
Damien George9a21d2e2014-09-06 17:15:34 +0100584 if (x >= *n || *n - x <= borrow) {
585 borrow += (mpz_dbl_dig_t)x - (mpz_dbl_dig_t)*n;
586 *n = (-borrow) & DIG_MASK;
587 borrow = (borrow >> DIG_SIZE) + ((borrow & DIG_MASK) == 0 ? 0 : 1); // shift-right with round-up
588 } else {
589 *n = ((mpz_dbl_dig_t)*n - (mpz_dbl_dig_t)x - (mpz_dbl_dig_t)borrow) & DIG_MASK;
590 borrow = 0;
591 }
592 }
593 if (borrow >= *num_dig) {
594 borrow -= (mpz_dbl_dig_t)*num_dig;
595 *num_dig = (-borrow) & DIG_MASK;
596 borrow = (borrow >> DIG_SIZE) + ((borrow & DIG_MASK) == 0 ? 0 : 1); // shift-right with round-up
597 } else {
598 *num_dig = (*num_dig - borrow) & DIG_MASK;
599 borrow = 0;
600 }
601
602 // adjust quotient if it is too big
603 for (; borrow != 0; --quo) {
Damien George460b0862016-05-09 17:21:42 +0100604 d = den_dig;
605 d_norm = 0;
Damien George9a21d2e2014-09-06 17:15:34 +0100606 mpz_dbl_dig_t carry = 0;
Damien George460b0862016-05-09 17:21:42 +0100607 for (mpz_dig_t *n = num_dig - den_len; n < num_dig; ++n, ++d) {
608 d_norm = ((mpz_dbl_dig_t)*d << norm_shift) | (d_norm >> DIG_SIZE);
609 carry += (mpz_dbl_dig_t)*n + (d_norm & DIG_MASK);
Damien George9a21d2e2014-09-06 17:15:34 +0100610 *n = carry & DIG_MASK;
611 carry >>= DIG_SIZE;
612 }
613 carry += (mpz_dbl_dig_t)*num_dig;
614 *num_dig = carry & DIG_MASK;
615 carry >>= DIG_SIZE;
616
617 //assert(borrow >= carry); // enable this to check the logic
618 borrow -= carry;
619 }
Damien George438c88d2014-02-22 19:25:23 +0000620 }
621
622 // store this digit of the quotient
623 *quo_dig = quo & DIG_MASK;
624 --quo_dig;
625
626 // move down to next digit of numerator
627 --num_dig;
628 --(*num_len);
629 }
630
Damien George438c88d2014-02-22 19:25:23 +0000631 // unnormalise numerator (remainder now)
632 for (mpz_dig_t *num = orig_num_dig + *num_len - 1, carry = 0; num >= orig_num_dig; --num) {
633 mpz_dig_t n = *num;
634 *num = ((n >> norm_shift) | carry) & DIG_MASK;
Damien Georgedc3faea2016-05-08 21:38:43 +0100635 carry = (mpz_dbl_dig_t)n << (DIG_SIZE - norm_shift);
Damien George438c88d2014-02-22 19:25:23 +0000636 }
637
638 // strip trailing zeros
639
640 while (*quo_len > 0 && orig_quo_dig[*quo_len - 1] == 0) {
641 --(*quo_len);
642 }
643
644 while (*num_len > 0 && orig_num_dig[*num_len - 1] == 0) {
645 --(*num_len);
646 }
647}
648
Damien George06201ff2014-03-01 19:50:50 +0000649#define MIN_ALLOC (2)
Damien George438c88d2014-02-22 19:25:23 +0000650
Damien George438c88d2014-02-22 19:25:23 +0000651void mpz_init_zero(mpz_t *z) {
Damien George438c88d2014-02-22 19:25:23 +0000652 z->neg = 0;
Damien George06201ff2014-03-01 19:50:50 +0000653 z->fixed_dig = 0;
654 z->alloc = 0;
Damien George438c88d2014-02-22 19:25:23 +0000655 z->len = 0;
656 z->dig = NULL;
657}
658
Damien George40f3c022014-07-03 13:25:24 +0100659void mpz_init_from_int(mpz_t *z, mp_int_t val) {
Damien George438c88d2014-02-22 19:25:23 +0000660 mpz_init_zero(z);
661 mpz_set_from_int(z, val);
662}
663
Damien Georgedcdcc432017-02-16 15:50:28 +1100664void mpz_init_fixed_from_int(mpz_t *z, mpz_dig_t *dig, size_t alloc, mp_int_t val) {
Damien George06201ff2014-03-01 19:50:50 +0000665 z->neg = 0;
666 z->fixed_dig = 1;
667 z->alloc = alloc;
668 z->len = 0;
669 z->dig = dig;
670 mpz_set_from_int(z, val);
671}
672
Damien George438c88d2014-02-22 19:25:23 +0000673void mpz_deinit(mpz_t *z) {
Damien George06201ff2014-03-01 19:50:50 +0000674 if (z != NULL && !z->fixed_dig) {
Damien George438c88d2014-02-22 19:25:23 +0000675 m_del(mpz_dig_t, z->dig, z->alloc);
676 }
677}
678
Damien George848dd0e2015-03-12 15:59:40 +0000679#if 0
680these functions are unused
681
Damien George438c88d2014-02-22 19:25:23 +0000682mpz_t *mpz_zero(void) {
683 mpz_t *z = m_new_obj(mpz_t);
684 mpz_init_zero(z);
685 return z;
686}
687
Damien George40f3c022014-07-03 13:25:24 +0100688mpz_t *mpz_from_int(mp_int_t val) {
Damien George438c88d2014-02-22 19:25:23 +0000689 mpz_t *z = mpz_zero();
690 mpz_set_from_int(z, val);
691 return z;
692}
693
Damien George95307432014-09-10 22:10:33 +0100694mpz_t *mpz_from_ll(long long val, bool is_signed) {
Damien Georgebb4a43f2014-03-12 15:36:06 +0000695 mpz_t *z = mpz_zero();
Damien George95307432014-09-10 22:10:33 +0100696 mpz_set_from_ll(z, val, is_signed);
Damien Georgebb4a43f2014-03-12 15:36:06 +0000697 return z;
698}
699
David Steinberg6e0b6d02015-01-02 12:39:22 +0000700#if MICROPY_PY_BUILTINS_FLOAT
701mpz_t *mpz_from_float(mp_float_t val) {
702 mpz_t *z = mpz_zero();
703 mpz_set_from_float(z, val);
704 return z;
705}
706#endif
707
Damien George6ed77be2017-02-16 15:59:51 +1100708mpz_t *mpz_from_str(const char *str, size_t len, bool neg, unsigned int base) {
Damien George438c88d2014-02-22 19:25:23 +0000709 mpz_t *z = mpz_zero();
710 mpz_set_from_str(z, str, len, neg, base);
711 return z;
712}
Damien George848dd0e2015-03-12 15:59:40 +0000713#endif
Damien George438c88d2014-02-22 19:25:23 +0000714
Damien George848dd0e2015-03-12 15:59:40 +0000715STATIC void mpz_free(mpz_t *z) {
Damien George438c88d2014-02-22 19:25:23 +0000716 if (z != NULL) {
717 m_del(mpz_dig_t, z->dig, z->alloc);
718 m_del_obj(mpz_t, z);
719 }
720}
721
Damien Georgedcdcc432017-02-16 15:50:28 +1100722STATIC void mpz_need_dig(mpz_t *z, size_t need) {
Damien George438c88d2014-02-22 19:25:23 +0000723 if (need < MIN_ALLOC) {
Damien George06201ff2014-03-01 19:50:50 +0000724 need = MIN_ALLOC;
Damien George438c88d2014-02-22 19:25:23 +0000725 }
726
Damien George06201ff2014-03-01 19:50:50 +0000727 if (z->dig == NULL || z->alloc < need) {
Damien Georgedf3e5d22016-10-11 13:00:56 +1100728 // if z has fixed digit buffer there's not much we can do as the caller will
729 // be expecting a buffer with at least "need" bytes (but it shouldn't happen)
730 assert(!z->fixed_dig);
Damien George06201ff2014-03-01 19:50:50 +0000731 z->dig = m_renew(mpz_dig_t, z->dig, z->alloc, need);
732 z->alloc = need;
Damien George438c88d2014-02-22 19:25:23 +0000733 }
734}
735
Damien George848dd0e2015-03-12 15:59:40 +0000736STATIC mpz_t *mpz_clone(const mpz_t *src) {
Damien George438c88d2014-02-22 19:25:23 +0000737 mpz_t *z = m_new_obj(mpz_t);
Damien George438c88d2014-02-22 19:25:23 +0000738 z->neg = src->neg;
Damien George06201ff2014-03-01 19:50:50 +0000739 z->fixed_dig = 0;
740 z->alloc = src->alloc;
Damien George438c88d2014-02-22 19:25:23 +0000741 z->len = src->len;
742 if (src->dig == NULL) {
743 z->dig = NULL;
744 } else {
745 z->dig = m_new(mpz_dig_t, z->alloc);
746 memcpy(z->dig, src->dig, src->alloc * sizeof(mpz_dig_t));
747 }
748 return z;
749}
750
Damien George06201ff2014-03-01 19:50:50 +0000751/* sets dest = src
752 can have dest, src the same
753*/
Damien George438c88d2014-02-22 19:25:23 +0000754void mpz_set(mpz_t *dest, const mpz_t *src) {
755 mpz_need_dig(dest, src->len);
756 dest->neg = src->neg;
757 dest->len = src->len;
758 memcpy(dest->dig, src->dig, src->len * sizeof(mpz_dig_t));
759}
760
Damien George40f3c022014-07-03 13:25:24 +0100761void mpz_set_from_int(mpz_t *z, mp_int_t val) {
Damien George58056b02015-01-09 20:58:58 +0000762 if (val == 0) {
763 z->len = 0;
764 return;
765 }
766
Damien George06201ff2014-03-01 19:50:50 +0000767 mpz_need_dig(z, MPZ_NUM_DIG_FOR_INT);
Damien George438c88d2014-02-22 19:25:23 +0000768
Damien George40f3c022014-07-03 13:25:24 +0100769 mp_uint_t uval;
Damien George438c88d2014-02-22 19:25:23 +0000770 if (val < 0) {
771 z->neg = 1;
Damien Georgebb4a43f2014-03-12 15:36:06 +0000772 uval = -val;
Damien George438c88d2014-02-22 19:25:23 +0000773 } else {
774 z->neg = 0;
Damien Georgebb4a43f2014-03-12 15:36:06 +0000775 uval = val;
Damien George438c88d2014-02-22 19:25:23 +0000776 }
777
778 z->len = 0;
Damien Georgebb4a43f2014-03-12 15:36:06 +0000779 while (uval > 0) {
780 z->dig[z->len++] = uval & DIG_MASK;
781 uval >>= DIG_SIZE;
782 }
783}
784
Damien George95307432014-09-10 22:10:33 +0100785void mpz_set_from_ll(mpz_t *z, long long val, bool is_signed) {
Damien Georgebb4a43f2014-03-12 15:36:06 +0000786 mpz_need_dig(z, MPZ_NUM_DIG_FOR_LL);
787
788 unsigned long long uval;
Damien George95307432014-09-10 22:10:33 +0100789 if (is_signed && val < 0) {
Damien Georgebb4a43f2014-03-12 15:36:06 +0000790 z->neg = 1;
791 uval = -val;
792 } else {
793 z->neg = 0;
794 uval = val;
795 }
796
797 z->len = 0;
798 while (uval > 0) {
799 z->dig[z->len++] = uval & DIG_MASK;
800 uval >>= DIG_SIZE;
Damien George438c88d2014-02-22 19:25:23 +0000801 }
802}
803
David Steinberg6e0b6d02015-01-02 12:39:22 +0000804#if MICROPY_PY_BUILTINS_FLOAT
805void mpz_set_from_float(mpz_t *z, mp_float_t src) {
806#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE
David Steinberg6e0b6d02015-01-02 12:39:22 +0000807typedef uint64_t mp_float_int_t;
David Steinbergc585ad12015-01-13 15:19:37 +0000808#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
David Steinberg6e0b6d02015-01-02 12:39:22 +0000809typedef uint32_t mp_float_int_t;
810#endif
811 union {
812 mp_float_t f;
Damien George2adf7ec2016-01-08 17:56:58 +0000813 #if MP_ENDIANNESS_LITTLE
David Steinbergc585ad12015-01-13 15:19:37 +0000814 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 +0000815 #else
816 struct { mp_float_int_t sgn:1, exp:MP_FLOAT_EXP_BITS, frc:MP_FLOAT_FRAC_BITS; } p;
817 #endif
David Steinberg6e0b6d02015-01-02 12:39:22 +0000818 } u = {src};
819
820 z->neg = u.p.sgn;
821 if (u.p.exp == 0) {
822 // value == 0 || value < 1
Damien George58056b02015-01-09 20:58:58 +0000823 mpz_set_from_int(z, 0);
David Steinbergc585ad12015-01-13 15:19:37 +0000824 } else if (u.p.exp == ((1 << MP_FLOAT_EXP_BITS) - 1)) {
Damien George6fd4b362015-01-02 23:04:09 +0000825 // u.p.frc == 0 indicates inf, else NaN
826 // should be handled by caller
Damien George58056b02015-01-09 20:58:58 +0000827 mpz_set_from_int(z, 0);
David Steinberg6e0b6d02015-01-02 12:39:22 +0000828 } else {
David Steinbergc585ad12015-01-13 15:19:37 +0000829 const int adj_exp = (int)u.p.exp - MP_FLOAT_EXP_BIAS;
David Steinberg6e0b6d02015-01-02 12:39:22 +0000830 if (adj_exp < 0) {
831 // value < 1 , truncates to 0
Damien George58056b02015-01-09 20:58:58 +0000832 mpz_set_from_int(z, 0);
David Steinberg6e0b6d02015-01-02 12:39:22 +0000833 } else if (adj_exp == 0) {
834 // 1 <= value < 2 , so truncates to 1
Damien George58056b02015-01-09 20:58:58 +0000835 mpz_set_from_int(z, 1);
David Steinberg6e0b6d02015-01-02 12:39:22 +0000836 } else {
837 // 2 <= value
838 const int dig_cnt = (adj_exp + 1 + (DIG_SIZE - 1)) / DIG_SIZE;
839 const unsigned int rem = adj_exp % DIG_SIZE;
840 int dig_ind, shft;
David Steinbergc585ad12015-01-13 15:19:37 +0000841 mp_float_int_t frc = u.p.frc | ((mp_float_int_t)1 << MP_FLOAT_FRAC_BITS);
David Steinberg6e0b6d02015-01-02 12:39:22 +0000842
David Steinbergc585ad12015-01-13 15:19:37 +0000843 if (adj_exp < MP_FLOAT_FRAC_BITS) {
David Steinberg6e0b6d02015-01-02 12:39:22 +0000844 shft = 0;
845 dig_ind = 0;
David Steinbergc585ad12015-01-13 15:19:37 +0000846 frc >>= MP_FLOAT_FRAC_BITS - adj_exp;
David Steinberg6e0b6d02015-01-02 12:39:22 +0000847 } else {
David Steinbergc585ad12015-01-13 15:19:37 +0000848 shft = (rem - MP_FLOAT_FRAC_BITS) % DIG_SIZE;
849 dig_ind = (adj_exp - MP_FLOAT_FRAC_BITS) / DIG_SIZE;
David Steinberg6e0b6d02015-01-02 12:39:22 +0000850 }
851 mpz_need_dig(z, dig_cnt);
852 z->len = dig_cnt;
853 if (dig_ind != 0) {
854 memset(z->dig, 0, dig_ind * sizeof(mpz_dig_t));
855 }
856 if (shft != 0) {
857 z->dig[dig_ind++] = (frc << shft) & DIG_MASK;
858 frc >>= DIG_SIZE - shft;
859 }
David Steinberg8d427b72015-01-13 15:20:32 +0000860#if DIG_SIZE < (MP_FLOAT_FRAC_BITS + 1)
David Steinberg6e0b6d02015-01-02 12:39:22 +0000861 while (dig_ind != dig_cnt) {
862 z->dig[dig_ind++] = frc & DIG_MASK;
863 frc >>= DIG_SIZE;
864 }
David Steinberg8d427b72015-01-13 15:20:32 +0000865#else
866 if (dig_ind != dig_cnt) {
867 z->dig[dig_ind] = frc;
868 }
869#endif
David Steinberg6e0b6d02015-01-02 12:39:22 +0000870 }
871 }
872}
David Steinberg6e0b6d02015-01-02 12:39:22 +0000873#endif
874
Damien George438c88d2014-02-22 19:25:23 +0000875// returns number of bytes from str that were processed
Damien George6ed77be2017-02-16 15:59:51 +1100876size_t mpz_set_from_str(mpz_t *z, const char *str, size_t len, bool neg, unsigned int base) {
Damien George2d9440e2016-12-28 12:04:19 +1100877 assert(base <= 36);
Damien George438c88d2014-02-22 19:25:23 +0000878
879 const char *cur = str;
880 const char *top = str + len;
881
882 mpz_need_dig(z, len * 8 / DIG_SIZE + 1);
883
884 if (neg) {
885 z->neg = 1;
886 } else {
887 z->neg = 0;
888 }
889
890 z->len = 0;
891 for (; cur < top; ++cur) { // XXX UTF8 next char
Damien Georgeafb1cf72014-09-05 20:37:06 +0100892 //mp_uint_t v = char_to_numeric(cur#); // XXX UTF8 get char
893 mp_uint_t v = *cur;
Damien George438c88d2014-02-22 19:25:23 +0000894 if ('0' <= v && v <= '9') {
895 v -= '0';
896 } else if ('A' <= v && v <= 'Z') {
897 v -= 'A' - 10;
898 } else if ('a' <= v && v <= 'z') {
899 v -= 'a' - 10;
900 } else {
901 break;
902 }
903 if (v >= base) {
904 break;
905 }
906 z->len = mpn_mul_dig_add_dig(z->dig, z->len, base, v);
907 }
908
909 return cur - str;
910}
911
Damien Georgedcdcc432017-02-16 15:50:28 +1100912void mpz_set_from_bytes(mpz_t *z, bool big_endian, size_t len, const byte *buf) {
Paul Sokolovsky1b42f522017-01-21 20:07:50 +0300913 int delta = 1;
914 if (big_endian) {
915 buf += len - 1;
916 delta = -1;
917 }
918
919 mpz_need_dig(z, (len * 8 + DIG_SIZE - 1) / DIG_SIZE);
920
921 mpz_dig_t d = 0;
922 int num_bits = 0;
923 z->neg = 0;
924 z->len = 0;
925 while (len) {
926 while (len && num_bits < DIG_SIZE) {
927 d |= *buf << num_bits;
928 num_bits += 8;
929 buf += delta;
930 len--;
931 }
932 z->dig[z->len++] = d & DIG_MASK;
933 // Need this #if because it's C undefined behavior to do: uint32_t >> 32
934 #if DIG_SIZE != 8 && DIG_SIZE != 16 && DIG_SIZE != 32
935 d >>= DIG_SIZE;
936 #else
937 d = 0;
938 #endif
939 num_bits -= DIG_SIZE;
940 }
941}
942
Damien George438c88d2014-02-22 19:25:23 +0000943bool mpz_is_zero(const mpz_t *z) {
944 return z->len == 0;
945}
946
Damien Georgea2e38382015-03-02 12:58:06 +0000947#if 0
948these functions are unused
949
Damien George438c88d2014-02-22 19:25:23 +0000950bool mpz_is_pos(const mpz_t *z) {
951 return z->len > 0 && z->neg == 0;
952}
953
954bool mpz_is_neg(const mpz_t *z) {
955 return z->len > 0 && z->neg != 0;
956}
957
958bool mpz_is_odd(const mpz_t *z) {
959 return z->len > 0 && (z->dig[0] & 1) != 0;
960}
961
962bool mpz_is_even(const mpz_t *z) {
963 return z->len == 0 || (z->dig[0] & 1) == 0;
964}
Damien Georgea2e38382015-03-02 12:58:06 +0000965#endif
Damien George438c88d2014-02-22 19:25:23 +0000966
Damien George42f3de92014-10-03 17:44:14 +0000967int mpz_cmp(const mpz_t *z1, const mpz_t *z2) {
Damien Georgea9dc9b82015-01-27 17:47:38 +0000968 // to catch comparison of -0 with +0
969 if (z1->len == 0 && z2->len == 0) {
970 return 0;
971 }
Damien George42f3de92014-10-03 17:44:14 +0000972 int cmp = (int)z2->neg - (int)z1->neg;
Damien George438c88d2014-02-22 19:25:23 +0000973 if (cmp != 0) {
974 return cmp;
975 }
976 cmp = mpn_cmp(z1->dig, z1->len, z2->dig, z2->len);
977 if (z1->neg != 0) {
978 cmp = -cmp;
979 }
980 return cmp;
981}
982
Damien George06201ff2014-03-01 19:50:50 +0000983#if 0
984// obsolete
985// compares mpz with an integer that fits within DIG_SIZE bits
Damien Georgeafb1cf72014-09-05 20:37:06 +0100986mp_int_t mpz_cmp_sml_int(const mpz_t *z, mp_int_t sml_int) {
987 mp_int_t cmp;
Damien George438c88d2014-02-22 19:25:23 +0000988 if (z->neg == 0) {
989 if (sml_int < 0) return 1;
990 if (sml_int == 0) {
991 if (z->len == 0) return 0;
992 return 1;
993 }
994 if (z->len == 0) return -1;
995 assert(sml_int < (1 << DIG_SIZE));
996 if (z->len != 1) return 1;
997 cmp = z->dig[0] - sml_int;
998 } else {
999 if (sml_int > 0) return -1;
1000 if (sml_int == 0) {
1001 if (z->len == 0) return 0;
1002 return -1;
1003 }
1004 if (z->len == 0) return 1;
1005 assert(sml_int > -(1 << DIG_SIZE));
1006 if (z->len != 1) return -1;
1007 cmp = -z->dig[0] - sml_int;
1008 }
1009 if (cmp < 0) return -1;
1010 if (cmp > 0) return 1;
1011 return 0;
1012}
Damien George06201ff2014-03-01 19:50:50 +00001013#endif
Damien George438c88d2014-02-22 19:25:23 +00001014
Damien George438c88d2014-02-22 19:25:23 +00001015#if 0
1016these functions are unused
1017
1018/* returns abs(z)
1019*/
1020mpz_t *mpz_abs(const mpz_t *z) {
1021 mpz_t *z2 = mpz_clone(z);
1022 z2->neg = 0;
1023 return z2;
1024}
1025
1026/* returns -z
1027*/
1028mpz_t *mpz_neg(const mpz_t *z) {
1029 mpz_t *z2 = mpz_clone(z);
1030 z2->neg = 1 - z2->neg;
1031 return z2;
1032}
1033
1034/* returns lhs + rhs
1035 can have lhs, rhs the same
1036*/
1037mpz_t *mpz_add(const mpz_t *lhs, const mpz_t *rhs) {
1038 mpz_t *z = mpz_zero();
1039 mpz_add_inpl(z, lhs, rhs);
1040 return z;
1041}
1042
1043/* returns lhs - rhs
1044 can have lhs, rhs the same
1045*/
1046mpz_t *mpz_sub(const mpz_t *lhs, const mpz_t *rhs) {
1047 mpz_t *z = mpz_zero();
1048 mpz_sub_inpl(z, lhs, rhs);
1049 return z;
1050}
1051
1052/* returns lhs * rhs
1053 can have lhs, rhs the same
1054*/
1055mpz_t *mpz_mul(const mpz_t *lhs, const mpz_t *rhs) {
1056 mpz_t *z = mpz_zero();
1057 mpz_mul_inpl(z, lhs, rhs);
1058 return z;
1059}
1060
1061/* returns lhs ** rhs
1062 can have lhs, rhs the same
1063*/
1064mpz_t *mpz_pow(const mpz_t *lhs, const mpz_t *rhs) {
1065 mpz_t *z = mpz_zero();
1066 mpz_pow_inpl(z, lhs, rhs);
1067 return z;
1068}
Damien Georgea2e38382015-03-02 12:58:06 +00001069
1070/* computes new integers in quo and rem such that:
1071 quo * rhs + rem = lhs
1072 0 <= rem < rhs
1073 can have lhs, rhs the same
1074*/
1075void mpz_divmod(const mpz_t *lhs, const mpz_t *rhs, mpz_t **quo, mpz_t **rem) {
1076 *quo = mpz_zero();
1077 *rem = mpz_zero();
1078 mpz_divmod_inpl(*quo, *rem, lhs, rhs);
1079}
Damien George438c88d2014-02-22 19:25:23 +00001080#endif
1081
1082/* computes dest = abs(z)
1083 can have dest, z the same
1084*/
1085void mpz_abs_inpl(mpz_t *dest, const mpz_t *z) {
1086 if (dest != z) {
1087 mpz_set(dest, z);
1088 }
1089 dest->neg = 0;
1090}
1091
1092/* computes dest = -z
1093 can have dest, z the same
1094*/
1095void mpz_neg_inpl(mpz_t *dest, const mpz_t *z) {
1096 if (dest != z) {
1097 mpz_set(dest, z);
1098 }
1099 dest->neg = 1 - dest->neg;
1100}
1101
Damien George06201ff2014-03-01 19:50:50 +00001102/* computes dest = ~z (= -z - 1)
1103 can have dest, z the same
1104*/
1105void mpz_not_inpl(mpz_t *dest, const mpz_t *z) {
1106 if (dest != z) {
1107 mpz_set(dest, z);
1108 }
Damien Georgee0ac1942014-12-31 19:35:01 +00001109 if (dest->len == 0) {
1110 mpz_need_dig(dest, 1);
1111 dest->dig[0] = 1;
1112 dest->len = 1;
1113 dest->neg = 1;
1114 } else if (dest->neg) {
Damien George06201ff2014-03-01 19:50:50 +00001115 dest->neg = 0;
1116 mpz_dig_t k = 1;
1117 dest->len = mpn_sub(dest->dig, dest->dig, dest->len, &k, 1);
1118 } else {
Damien Georgee0ac1942014-12-31 19:35:01 +00001119 mpz_need_dig(dest, dest->len + 1);
Damien George06201ff2014-03-01 19:50:50 +00001120 mpz_dig_t k = 1;
1121 dest->len = mpn_add(dest->dig, dest->dig, dest->len, &k, 1);
1122 dest->neg = 1;
1123 }
1124}
1125
Damien Georgec5ac2ac2014-02-26 16:56:30 +00001126/* computes dest = lhs << rhs
1127 can have dest, lhs the same
1128*/
Damien George2f4e8512015-10-01 18:01:37 +01001129void mpz_shl_inpl(mpz_t *dest, const mpz_t *lhs, mp_uint_t rhs) {
Damien George06201ff2014-03-01 19:50:50 +00001130 if (lhs->len == 0 || rhs == 0) {
Damien Georgec5ac2ac2014-02-26 16:56:30 +00001131 mpz_set(dest, lhs);
Damien Georgec5ac2ac2014-02-26 16:56:30 +00001132 } else {
Damien George06201ff2014-03-01 19:50:50 +00001133 mpz_need_dig(dest, lhs->len + (rhs + DIG_SIZE - 1) / DIG_SIZE);
1134 dest->len = mpn_shl(dest->dig, lhs->dig, lhs->len, rhs);
1135 dest->neg = lhs->neg;
Damien Georgec5ac2ac2014-02-26 16:56:30 +00001136 }
Damien Georgec5ac2ac2014-02-26 16:56:30 +00001137}
1138
1139/* computes dest = lhs >> rhs
1140 can have dest, lhs the same
1141*/
Damien George2f4e8512015-10-01 18:01:37 +01001142void mpz_shr_inpl(mpz_t *dest, const mpz_t *lhs, mp_uint_t rhs) {
Damien George06201ff2014-03-01 19:50:50 +00001143 if (lhs->len == 0 || rhs == 0) {
Damien Georgec5ac2ac2014-02-26 16:56:30 +00001144 mpz_set(dest, lhs);
Damien Georgec5ac2ac2014-02-26 16:56:30 +00001145 } else {
Damien George06201ff2014-03-01 19:50:50 +00001146 mpz_need_dig(dest, lhs->len);
1147 dest->len = mpn_shr(dest->dig, lhs->dig, lhs->len, rhs);
1148 dest->neg = lhs->neg;
1149 if (dest->neg) {
1150 // arithmetic shift right, rounding to negative infinity
Damien Georgeafb1cf72014-09-05 20:37:06 +01001151 mp_uint_t n_whole = rhs / DIG_SIZE;
1152 mp_uint_t n_part = rhs % DIG_SIZE;
Damien George06201ff2014-03-01 19:50:50 +00001153 mpz_dig_t round_up = 0;
Damien Georgedcdcc432017-02-16 15:50:28 +11001154 for (size_t i = 0; i < lhs->len && i < n_whole; i++) {
Damien George06201ff2014-03-01 19:50:50 +00001155 if (lhs->dig[i] != 0) {
1156 round_up = 1;
1157 break;
1158 }
1159 }
1160 if (n_whole < lhs->len && (lhs->dig[n_whole] & ((1 << n_part) - 1)) != 0) {
1161 round_up = 1;
1162 }
1163 if (round_up) {
Damien Georgee0ac1942014-12-31 19:35:01 +00001164 if (dest->len == 0) {
1165 // dest == 0, so need to add 1 by hand (answer will be -1)
1166 dest->dig[0] = 1;
1167 dest->len = 1;
1168 } else {
1169 // dest > 0, so can use mpn_add to add 1
1170 dest->len = mpn_add(dest->dig, dest->dig, dest->len, &round_up, 1);
1171 }
Damien George06201ff2014-03-01 19:50:50 +00001172 }
1173 }
Damien Georgec5ac2ac2014-02-26 16:56:30 +00001174 }
Damien Georgec5ac2ac2014-02-26 16:56:30 +00001175}
Damien Georgec5ac2ac2014-02-26 16:56:30 +00001176
Damien George438c88d2014-02-22 19:25:23 +00001177/* computes dest = lhs + rhs
1178 can have dest, lhs, rhs the same
1179*/
1180void mpz_add_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
1181 if (mpn_cmp(lhs->dig, lhs->len, rhs->dig, rhs->len) < 0) {
1182 const mpz_t *temp = lhs;
1183 lhs = rhs;
1184 rhs = temp;
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 dest->neg = lhs->neg;
1196}
1197
1198/* computes dest = lhs - rhs
1199 can have dest, lhs, rhs the same
1200*/
1201void mpz_sub_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
1202 bool neg = false;
1203
1204 if (mpn_cmp(lhs->dig, lhs->len, rhs->dig, rhs->len) < 0) {
1205 const mpz_t *temp = lhs;
1206 lhs = rhs;
1207 rhs = temp;
1208 neg = true;
1209 }
1210
1211 if (lhs->neg != rhs->neg) {
1212 mpz_need_dig(dest, lhs->len + 1);
1213 dest->len = mpn_add(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
1214 } else {
1215 mpz_need_dig(dest, lhs->len);
1216 dest->len = mpn_sub(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
1217 }
1218
1219 if (neg) {
1220 dest->neg = 1 - lhs->neg;
1221 } else {
1222 dest->neg = lhs->neg;
1223 }
1224}
1225
Paul Sokolovsky57207b82014-03-23 01:52:36 +02001226/* computes dest = lhs & rhs
1227 can have dest, lhs, rhs the same
1228*/
1229void mpz_and_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
Doug Currie2e2e15c2016-01-30 22:35:58 -05001230 // make sure lhs has the most digits
1231 if (lhs->len < rhs->len) {
1232 const mpz_t *temp = lhs;
1233 lhs = rhs;
1234 rhs = temp;
Paul Sokolovsky57207b82014-03-23 01:52:36 +02001235 }
Doug Currie2e2e15c2016-01-30 22:35:58 -05001236
1237 #if MICROPY_OPT_MPZ_BITWISE
1238
1239 if ((0 == lhs->neg) && (0 == rhs->neg)) {
1240 mpz_need_dig(dest, lhs->len);
1241 dest->len = mpn_and(dest->dig, lhs->dig, rhs->dig, rhs->len);
1242 dest->neg = 0;
1243 } else {
1244 mpz_need_dig(dest, lhs->len + 1);
1245 dest->len = mpn_and_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len,
1246 lhs->neg == rhs->neg, 0 != lhs->neg, 0 != rhs->neg);
1247 dest->neg = lhs->neg & rhs->neg;
1248 }
1249
1250 #else
1251
1252 mpz_need_dig(dest, lhs->len + (lhs->neg || rhs->neg));
1253 dest->len = mpn_and_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len,
1254 (lhs->neg == rhs->neg) ? lhs->neg : 0, lhs->neg, rhs->neg);
1255 dest->neg = lhs->neg & rhs->neg;
1256
1257 #endif
Paul Sokolovsky57207b82014-03-23 01:52:36 +02001258}
1259
1260/* computes dest = lhs | rhs
1261 can have dest, lhs, rhs the same
1262*/
1263void mpz_or_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
Doug Currie2e2e15c2016-01-30 22:35:58 -05001264 // make sure lhs has the most digits
1265 if (lhs->len < rhs->len) {
Paul Sokolovsky57207b82014-03-23 01:52:36 +02001266 const mpz_t *temp = lhs;
1267 lhs = rhs;
1268 rhs = temp;
1269 }
1270
Doug Currie2e2e15c2016-01-30 22:35:58 -05001271 #if MICROPY_OPT_MPZ_BITWISE
1272
1273 if ((0 == lhs->neg) && (0 == rhs->neg)) {
Paul Sokolovsky57207b82014-03-23 01:52:36 +02001274 mpz_need_dig(dest, lhs->len);
1275 dest->len = mpn_or(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
Doug Currie2e2e15c2016-01-30 22:35:58 -05001276 dest->neg = 0;
Paul Sokolovsky57207b82014-03-23 01:52:36 +02001277 } else {
Doug Currie2e2e15c2016-01-30 22:35:58 -05001278 mpz_need_dig(dest, lhs->len + 1);
1279 dest->len = mpn_or_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len,
1280 0 != lhs->neg, 0 != rhs->neg);
1281 dest->neg = 1;
Paul Sokolovsky57207b82014-03-23 01:52:36 +02001282 }
1283
Doug Currie2e2e15c2016-01-30 22:35:58 -05001284 #else
1285
1286 mpz_need_dig(dest, lhs->len + (lhs->neg || rhs->neg));
1287 dest->len = mpn_or_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len,
1288 (lhs->neg || rhs->neg), lhs->neg, rhs->neg);
1289 dest->neg = lhs->neg | rhs->neg;
1290
1291 #endif
Paul Sokolovsky57207b82014-03-23 01:52:36 +02001292}
1293
1294/* computes dest = lhs ^ rhs
1295 can have dest, lhs, rhs the same
1296*/
1297void mpz_xor_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
Doug Currie2e2e15c2016-01-30 22:35:58 -05001298 // make sure lhs has the most digits
1299 if (lhs->len < rhs->len) {
Paul Sokolovsky57207b82014-03-23 01:52:36 +02001300 const mpz_t *temp = lhs;
1301 lhs = rhs;
1302 rhs = temp;
1303 }
1304
Doug Currie2e2e15c2016-01-30 22:35:58 -05001305 #if MICROPY_OPT_MPZ_BITWISE
1306
Paul Sokolovsky57207b82014-03-23 01:52:36 +02001307 if (lhs->neg == rhs->neg) {
1308 mpz_need_dig(dest, lhs->len);
Doug Currie2e2e15c2016-01-30 22:35:58 -05001309 if (lhs->neg == 0) {
1310 dest->len = mpn_xor(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
1311 } else {
1312 dest->len = mpn_xor_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len, 0, 0, 0);
1313 }
1314 dest->neg = 0;
Paul Sokolovsky57207b82014-03-23 01:52:36 +02001315 } else {
Doug Currie2e2e15c2016-01-30 22:35:58 -05001316 mpz_need_dig(dest, lhs->len + 1);
1317 dest->len = mpn_xor_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len, 1,
1318 0 == lhs->neg, 0 == rhs->neg);
1319 dest->neg = 1;
Paul Sokolovsky57207b82014-03-23 01:52:36 +02001320 }
1321
Doug Currie2e2e15c2016-01-30 22:35:58 -05001322 #else
1323
1324 mpz_need_dig(dest, lhs->len + (lhs->neg || rhs->neg));
1325 dest->len = mpn_xor_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len,
1326 (lhs->neg != rhs->neg), 0 == lhs->neg, 0 == rhs->neg);
1327 dest->neg = lhs->neg ^ rhs->neg;
1328
1329 #endif
Paul Sokolovsky57207b82014-03-23 01:52:36 +02001330}
1331
Damien George438c88d2014-02-22 19:25:23 +00001332/* computes dest = lhs * rhs
1333 can have dest, lhs, rhs the same
1334*/
Damien George4dea9222015-04-09 15:29:54 +00001335void mpz_mul_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
Damien George438c88d2014-02-22 19:25:23 +00001336 if (lhs->len == 0 || rhs->len == 0) {
Damien Georgec5ac2ac2014-02-26 16:56:30 +00001337 mpz_set_from_int(dest, 0);
1338 return;
Damien George438c88d2014-02-22 19:25:23 +00001339 }
1340
1341 mpz_t *temp = NULL;
1342 if (lhs == dest) {
1343 lhs = temp = mpz_clone(lhs);
1344 if (rhs == dest) {
1345 rhs = lhs;
1346 }
1347 } else if (rhs == dest) {
1348 rhs = temp = mpz_clone(rhs);
1349 }
1350
1351 mpz_need_dig(dest, lhs->len + rhs->len); // min mem l+r-1, max mem l+r
1352 memset(dest->dig, 0, dest->alloc * sizeof(mpz_dig_t));
1353 dest->len = mpn_mul(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
1354
1355 if (lhs->neg == rhs->neg) {
1356 dest->neg = 0;
1357 } else {
1358 dest->neg = 1;
1359 }
1360
1361 mpz_free(temp);
1362}
1363
1364/* computes dest = lhs ** rhs
1365 can have dest, lhs, rhs the same
1366*/
1367void mpz_pow_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
1368 if (lhs->len == 0 || rhs->neg != 0) {
Damien Georgec5ac2ac2014-02-26 16:56:30 +00001369 mpz_set_from_int(dest, 0);
1370 return;
Damien George438c88d2014-02-22 19:25:23 +00001371 }
1372
1373 if (rhs->len == 0) {
Damien Georgec5ac2ac2014-02-26 16:56:30 +00001374 mpz_set_from_int(dest, 1);
1375 return;
Damien George438c88d2014-02-22 19:25:23 +00001376 }
1377
1378 mpz_t *x = mpz_clone(lhs);
1379 mpz_t *n = mpz_clone(rhs);
1380
1381 mpz_set_from_int(dest, 1);
1382
1383 while (n->len > 0) {
Damien Georgea2e38382015-03-02 12:58:06 +00001384 if ((n->dig[0] & 1) != 0) {
Damien George438c88d2014-02-22 19:25:23 +00001385 mpz_mul_inpl(dest, dest, x);
1386 }
Damien George438c88d2014-02-22 19:25:23 +00001387 n->len = mpn_shr(n->dig, n->dig, n->len, 1);
Damien George5bf565e2014-04-04 00:16:32 +01001388 if (n->len == 0) {
1389 break;
1390 }
1391 mpz_mul_inpl(x, x, x);
Damien George438c88d2014-02-22 19:25:23 +00001392 }
1393
1394 mpz_free(x);
1395 mpz_free(n);
1396}
1397
Damien Georgeff1a96c2016-02-03 22:30:49 +00001398/* computes dest = (lhs ** rhs) % mod
1399 can have dest, lhs, rhs the same; mod can't be the same as dest
1400*/
1401void mpz_pow3_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs, const mpz_t *mod) {
1402 if (lhs->len == 0 || rhs->neg != 0) {
1403 mpz_set_from_int(dest, 0);
1404 return;
1405 }
1406
1407 if (rhs->len == 0) {
1408 mpz_set_from_int(dest, 1);
1409 return;
1410 }
1411
1412 mpz_t *x = mpz_clone(lhs);
1413 mpz_t *n = mpz_clone(rhs);
1414 mpz_t quo; mpz_init_zero(&quo);
1415
1416 mpz_set_from_int(dest, 1);
1417
1418 while (n->len > 0) {
1419 if ((n->dig[0] & 1) != 0) {
1420 mpz_mul_inpl(dest, dest, x);
1421 mpz_divmod_inpl(&quo, dest, dest, mod);
1422 }
1423 n->len = mpn_shr(n->dig, n->dig, n->len, 1);
1424 if (n->len == 0) {
1425 break;
1426 }
1427 mpz_mul_inpl(x, x, x);
1428 mpz_divmod_inpl(&quo, x, x, mod);
1429 }
1430
1431 mpz_deinit(&quo);
1432 mpz_free(x);
1433 mpz_free(n);
1434}
1435
Nicko van Somerendf0117c2017-02-01 16:41:22 -07001436#if 0
1437these functions are unused
1438
Damien George438c88d2014-02-22 19:25:23 +00001439/* computes gcd(z1, z2)
1440 based on Knuth's modified gcd algorithm (I think?)
1441 gcd(z1, z2) >= 0
1442 gcd(0, 0) = 0
1443 gcd(z, 0) = abs(z)
1444*/
1445mpz_t *mpz_gcd(const mpz_t *z1, const mpz_t *z2) {
1446 if (z1->len == 0) {
1447 mpz_t *a = mpz_clone(z2);
1448 a->neg = 0;
1449 return a;
1450 } else if (z2->len == 0) {
1451 mpz_t *a = mpz_clone(z1);
1452 a->neg = 0;
1453 return a;
1454 }
1455
1456 mpz_t *a = mpz_clone(z1);
1457 mpz_t *b = mpz_clone(z2);
1458 mpz_t c; mpz_init_zero(&c);
1459 a->neg = 0;
1460 b->neg = 0;
1461
1462 for (;;) {
1463 if (mpz_cmp(a, b) < 0) {
1464 if (a->len == 0) {
1465 mpz_free(a);
1466 mpz_deinit(&c);
1467 return b;
1468 }
1469 mpz_t *t = a; a = b; b = t;
1470 }
1471 if (!(b->len >= 2 || (b->len == 1 && b->dig[0] > 1))) { // compute b > 0; could be mpz_cmp_small_int(b, 1) > 0
1472 break;
1473 }
1474 mpz_set(&c, b);
1475 do {
1476 mpz_add_inpl(&c, &c, &c);
1477 } while (mpz_cmp(&c, a) <= 0);
1478 c.len = mpn_shr(c.dig, c.dig, c.len, 1);
1479 mpz_sub_inpl(a, a, &c);
1480 }
1481
1482 mpz_deinit(&c);
1483
1484 if (b->len == 1 && b->dig[0] == 1) { // compute b == 1; could be mpz_cmp_small_int(b, 1) == 0
1485 mpz_free(a);
1486 return b;
1487 } else {
1488 mpz_free(b);
1489 return a;
1490 }
1491}
1492
1493/* computes lcm(z1, z2)
1494 = abs(z1) / gcd(z1, z2) * abs(z2)
1495 lcm(z1, z1) >= 0
1496 lcm(0, 0) = 0
1497 lcm(z, 0) = 0
1498*/
Damien George5d9b8162014-08-07 14:27:48 +00001499mpz_t *mpz_lcm(const mpz_t *z1, const mpz_t *z2) {
1500 if (z1->len == 0 || z2->len == 0) {
1501 return mpz_zero();
stijn01d6be42014-05-05 12:18:27 +02001502 }
Damien George438c88d2014-02-22 19:25:23 +00001503
1504 mpz_t *gcd = mpz_gcd(z1, z2);
1505 mpz_t *quo = mpz_zero();
1506 mpz_t *rem = mpz_zero();
1507 mpz_divmod_inpl(quo, rem, z1, gcd);
1508 mpz_mul_inpl(rem, quo, z2);
1509 mpz_free(gcd);
1510 mpz_free(quo);
1511 rem->neg = 0;
1512 return rem;
1513}
Damien Georgea2e38382015-03-02 12:58:06 +00001514#endif
Damien George438c88d2014-02-22 19:25:23 +00001515
1516/* computes new integers in quo and rem such that:
1517 quo * rhs + rem = lhs
1518 0 <= rem < rhs
1519 can have lhs, rhs the same
Damien George48874942016-10-11 13:00:01 +11001520 assumes rhs != 0 (undefined behaviour if it is)
Damien George438c88d2014-02-22 19:25:23 +00001521*/
1522void mpz_divmod_inpl(mpz_t *dest_quo, mpz_t *dest_rem, const mpz_t *lhs, const mpz_t *rhs) {
Damien George48874942016-10-11 13:00:01 +11001523 assert(!mpz_is_zero(rhs));
Damien George438c88d2014-02-22 19:25:23 +00001524
1525 mpz_need_dig(dest_quo, lhs->len + 1); // +1 necessary?
1526 memset(dest_quo->dig, 0, (lhs->len + 1) * sizeof(mpz_dig_t));
1527 dest_quo->len = 0;
1528 mpz_need_dig(dest_rem, lhs->len + 1); // +1 necessary?
1529 mpz_set(dest_rem, lhs);
Damien George438c88d2014-02-22 19:25:23 +00001530 mpn_div(dest_rem->dig, &dest_rem->len, rhs->dig, rhs->len, dest_quo->dig, &dest_quo->len);
1531
Damien George65402ab2016-05-08 22:21:21 +01001532 // check signs and do Python style modulo
Damien George438c88d2014-02-22 19:25:23 +00001533 if (lhs->neg != rhs->neg) {
1534 dest_quo->neg = 1;
Damien George65402ab2016-05-08 22:21:21 +01001535 if (!mpz_is_zero(dest_rem)) {
1536 mpz_t mpzone; mpz_init_from_int(&mpzone, -1);
1537 mpz_add_inpl(dest_quo, dest_quo, &mpzone);
1538 mpz_add_inpl(dest_rem, dest_rem, rhs);
1539 }
Damien George438c88d2014-02-22 19:25:23 +00001540 }
1541}
1542
1543#if 0
1544these functions are unused
1545
1546/* computes floor(lhs / rhs)
1547 can have lhs, rhs the same
1548*/
1549mpz_t *mpz_div(const mpz_t *lhs, const mpz_t *rhs) {
1550 mpz_t *quo = mpz_zero();
1551 mpz_t rem; mpz_init_zero(&rem);
1552 mpz_divmod_inpl(quo, &rem, lhs, rhs);
1553 mpz_deinit(&rem);
1554 return quo;
1555}
1556
1557/* computes lhs % rhs ( >= 0)
1558 can have lhs, rhs the same
1559*/
1560mpz_t *mpz_mod(const mpz_t *lhs, const mpz_t *rhs) {
1561 mpz_t quo; mpz_init_zero(&quo);
1562 mpz_t *rem = mpz_zero();
1563 mpz_divmod_inpl(&quo, rem, lhs, rhs);
1564 mpz_deinit(&quo);
1565 return rem;
1566}
1567#endif
1568
Damien Georgeffe911d2014-07-24 14:21:37 +01001569// must return actual int value if it fits in mp_int_t
1570mp_int_t mpz_hash(const mpz_t *z) {
1571 mp_int_t val = 0;
1572 mpz_dig_t *d = z->dig + z->len;
1573
Damien George58056b02015-01-09 20:58:58 +00001574 while (d-- > z->dig) {
Damien Georgeffe911d2014-07-24 14:21:37 +01001575 val = (val << DIG_SIZE) | *d;
1576 }
1577
1578 if (z->neg != 0) {
1579 val = -val;
1580 }
1581
1582 return val;
1583}
1584
Damien George40f3c022014-07-03 13:25:24 +01001585bool mpz_as_int_checked(const mpz_t *i, mp_int_t *value) {
Damien George963a5a32015-01-16 17:47:07 +00001586 mp_uint_t val = 0;
Damien George8270e382014-04-03 11:00:54 +00001587 mpz_dig_t *d = i->dig + i->len;
1588
Damien George58056b02015-01-09 20:58:58 +00001589 while (d-- > i->dig) {
Damien Georgec9aa58e2014-07-31 13:41:43 +00001590 if (val > (~(WORD_MSBIT_HIGH) >> DIG_SIZE)) {
1591 // will overflow
Damien George8270e382014-04-03 11:00:54 +00001592 return false;
1593 }
Damien Georgec9aa58e2014-07-31 13:41:43 +00001594 val = (val << DIG_SIZE) | *d;
Damien George8270e382014-04-03 11:00:54 +00001595 }
1596
1597 if (i->neg != 0) {
1598 val = -val;
1599 }
1600
1601 *value = val;
1602 return true;
1603}
1604
Damien Georgec9aa58e2014-07-31 13:41:43 +00001605bool mpz_as_uint_checked(const mpz_t *i, mp_uint_t *value) {
1606 if (i->neg != 0) {
1607 // can't represent signed values
1608 return false;
1609 }
1610
1611 mp_uint_t val = 0;
1612 mpz_dig_t *d = i->dig + i->len;
1613
Damien George58056b02015-01-09 20:58:58 +00001614 while (d-- > i->dig) {
Damien George9a21d2e2014-09-06 17:15:34 +01001615 if (val > (~(WORD_MSBIT_HIGH) >> (DIG_SIZE - 1))) {
Damien Georgec9aa58e2014-07-31 13:41:43 +00001616 // will overflow
1617 return false;
1618 }
1619 val = (val << DIG_SIZE) | *d;
1620 }
1621
1622 *value = val;
1623 return true;
1624}
1625
Damien George271d18e2015-04-25 23:16:39 +01001626// writes at most len bytes to buf (so buf should be zeroed before calling)
Damien Georgedcdcc432017-02-16 15:50:28 +11001627void mpz_as_bytes(const mpz_t *z, bool big_endian, size_t len, byte *buf) {
Damien George271d18e2015-04-25 23:16:39 +01001628 byte *b = buf;
1629 if (big_endian) {
1630 b += len;
1631 }
1632 mpz_dig_t *zdig = z->dig;
1633 int bits = 0;
1634 mpz_dbl_dig_t d = 0;
1635 mpz_dbl_dig_t carry = 1;
Damien Georgedcdcc432017-02-16 15:50:28 +11001636 for (size_t zlen = z->len; zlen > 0; --zlen) {
Damien George271d18e2015-04-25 23:16:39 +01001637 bits += DIG_SIZE;
1638 d = (d << DIG_SIZE) | *zdig++;
1639 for (; bits >= 8; bits -= 8, d >>= 8) {
1640 mpz_dig_t val = d;
1641 if (z->neg) {
Damien George94729072015-04-25 23:51:14 +01001642 val = (~val & 0xff) + carry;
1643 carry = val >> 8;
Damien George271d18e2015-04-25 23:16:39 +01001644 }
1645 if (big_endian) {
1646 *--b = val;
1647 if (b == buf) {
1648 return;
1649 }
1650 } else {
1651 *b++ = val;
1652 if (b == buf + len) {
1653 return;
1654 }
1655 }
1656 }
1657 }
1658}
1659
Damien Georgefb510b32014-06-01 13:32:54 +01001660#if MICROPY_PY_BUILTINS_FLOAT
Damien George52608102014-03-08 15:04:54 +00001661mp_float_t mpz_as_float(const mpz_t *i) {
1662 mp_float_t val = 0;
Damien George438c88d2014-02-22 19:25:23 +00001663 mpz_dig_t *d = i->dig + i->len;
1664
Damien George58056b02015-01-09 20:58:58 +00001665 while (d-- > i->dig) {
Damien George9a21d2e2014-09-06 17:15:34 +01001666 val = val * DIG_BASE + *d;
Damien George438c88d2014-02-22 19:25:23 +00001667 }
1668
1669 if (i->neg != 0) {
1670 val = -val;
1671 }
1672
1673 return val;
1674}
Damien George52608102014-03-08 15:04:54 +00001675#endif
Damien George438c88d2014-02-22 19:25:23 +00001676
Damien Georgeafb1cf72014-09-05 20:37:06 +01001677#if 0
1678this function is unused
Damien George6ed77be2017-02-16 15:59:51 +11001679char *mpz_as_str(const mpz_t *i, unsigned int base) {
Damien Georgeeb90edb2017-02-16 15:55:36 +11001680 char *s = m_new(char, mp_int_format_size(mpz_max_num_bits(i), base, NULL, '\0'));
Damien Georgeafb1cf72014-09-05 20:37:06 +01001681 mpz_as_str_inpl(i, base, NULL, 'a', '\0', s);
Damien George438c88d2014-02-22 19:25:23 +00001682 return s;
1683}
Damien Georgeafb1cf72014-09-05 20:37:06 +01001684#endif
Damien George438c88d2014-02-22 19:25:23 +00001685
Damien George8bb7d952016-10-11 13:11:32 +11001686// assumes enough space as calculated by mp_int_format_size
Damien George438c88d2014-02-22 19:25:23 +00001687// returns length of string, not including null byte
Damien George6ed77be2017-02-16 15:59:51 +11001688size_t mpz_as_str_inpl(const mpz_t *i, unsigned int base, const char *prefix, char base_char, char comma, char *str) {
Pavol Rusnak3679ee92016-10-25 11:03:39 +02001689 if (str == NULL) {
1690 return 0;
1691 }
1692 if (base < 2 || base > 32) {
Damien George438c88d2014-02-22 19:25:23 +00001693 str[0] = 0;
1694 return 0;
1695 }
1696
Damien Georgedcdcc432017-02-16 15:50:28 +11001697 size_t ilen = i->len;
Damien George438c88d2014-02-22 19:25:23 +00001698
Dave Hylandsc4029e52014-04-07 11:19:51 -07001699 char *s = str;
Damien George438c88d2014-02-22 19:25:23 +00001700 if (ilen == 0) {
Dave Hylandsc4029e52014-04-07 11:19:51 -07001701 if (prefix) {
1702 while (*prefix)
1703 *s++ = *prefix++;
1704 }
1705 *s++ = '0';
1706 *s = '\0';
1707 return s - str;
Damien George438c88d2014-02-22 19:25:23 +00001708 }
1709
Damien Georgeeec91052014-04-08 23:11:00 +01001710 // make a copy of mpz digits, so we can do the div/mod calculation
Damien George438c88d2014-02-22 19:25:23 +00001711 mpz_dig_t *dig = m_new(mpz_dig_t, ilen);
1712 memcpy(dig, i->dig, ilen * sizeof(mpz_dig_t));
1713
1714 // convert
Dave Hylandsc4029e52014-04-07 11:19:51 -07001715 char *last_comma = str;
Damien George438c88d2014-02-22 19:25:23 +00001716 bool done;
1717 do {
1718 mpz_dig_t *d = dig + ilen;
1719 mpz_dbl_dig_t a = 0;
1720
1721 // compute next remainder
1722 while (--d >= dig) {
1723 a = (a << DIG_SIZE) | *d;
1724 *d = a / base;
1725 a %= base;
1726 }
1727
1728 // convert to character
1729 a += '0';
1730 if (a > '9') {
Dave Hylandsc4029e52014-04-07 11:19:51 -07001731 a += base_char - '9' - 1;
Damien George438c88d2014-02-22 19:25:23 +00001732 }
1733 *s++ = a;
1734
1735 // check if number is zero
1736 done = true;
1737 for (d = dig; d < dig + ilen; ++d) {
1738 if (*d != 0) {
1739 done = false;
1740 break;
1741 }
1742 }
Dave Hylandsc4029e52014-04-07 11:19:51 -07001743 if (comma && (s - last_comma) == 3) {
1744 *s++ = comma;
1745 last_comma = s;
1746 }
1747 }
1748 while (!done);
Damien George438c88d2014-02-22 19:25:23 +00001749
Damien Georgeeec91052014-04-08 23:11:00 +01001750 // free the copy of the digits array
1751 m_del(mpz_dig_t, dig, ilen);
1752
Dave Hylandsc4029e52014-04-07 11:19:51 -07001753 if (prefix) {
1754 const char *p = &prefix[strlen(prefix)];
1755 while (p > prefix) {
1756 *s++ = *--p;
1757 }
1758 }
Damien George438c88d2014-02-22 19:25:23 +00001759 if (i->neg != 0) {
1760 *s++ = '-';
1761 }
1762
1763 // reverse string
1764 for (char *u = str, *v = s - 1; u < v; ++u, --v) {
1765 char temp = *u;
1766 *u = *v;
1767 *v = temp;
1768 }
1769
Dave Hylandsc4029e52014-04-07 11:19:51 -07001770 *s = '\0'; // null termination
Damien George438c88d2014-02-22 19:25:23 +00001771
1772 return s - str;
1773}
1774
1775#endif // MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_MPZ