blob: cceb079cd3c375832a1d78f3f24e707412df49a1 [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
Damien George438c88d2014-02-22 19:25:23 +0000457*/
Damien George460b0862016-05-09 17:21:42 +0100458STATIC void mpn_div(mpz_dig_t *num_dig, mp_uint_t *num_len, const 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 +0000459 mpz_dig_t *orig_num_dig = num_dig;
460 mpz_dig_t *orig_quo_dig = quo_dig;
461 mpz_dig_t norm_shift = 0;
462 mpz_dbl_dig_t lead_den_digit;
463
464 // handle simple cases
465 {
Damien George42f3de92014-10-03 17:44:14 +0000466 int cmp = mpn_cmp(num_dig, *num_len, den_dig, den_len);
Damien George438c88d2014-02-22 19:25:23 +0000467 if (cmp == 0) {
468 *num_len = 0;
469 quo_dig[0] = 1;
470 *quo_len = 1;
471 return;
472 } else if (cmp < 0) {
473 // numerator remains the same
474 *quo_len = 0;
475 return;
476 }
477 }
478
Damien George460b0862016-05-09 17:21:42 +0100479 // We need to normalise the denominator (leading bit of leading digit is 1)
480 // so that the division routine works. Since the denominator memory is
481 // read-only we do the normalisation on the fly, each time a digit of the
482 // denominator is needed. We need to know is how many bits to shift by.
483
Damien George438c88d2014-02-22 19:25:23 +0000484 // count number of leading zeros in leading digit of denominator
485 {
486 mpz_dig_t d = den_dig[den_len - 1];
Damien George9a21d2e2014-09-06 17:15:34 +0100487 while ((d & DIG_MSB) == 0) {
Damien George438c88d2014-02-22 19:25:23 +0000488 d <<= 1;
489 ++norm_shift;
490 }
491 }
492
Damien George438c88d2014-02-22 19:25:23 +0000493 // now need to shift numerator by same amount as denominator
494 // first, increase length of numerator in case we need more room to shift
495 num_dig[*num_len] = 0;
496 ++(*num_len);
497 for (mpz_dig_t *num = num_dig, carry = 0; num < num_dig + *num_len; ++num) {
498 mpz_dig_t n = *num;
499 *num = ((n << norm_shift) | carry) & DIG_MASK;
Damien Georgedc3faea2016-05-08 21:38:43 +0100500 carry = (mpz_dbl_dig_t)n >> (DIG_SIZE - norm_shift);
Damien George438c88d2014-02-22 19:25:23 +0000501 }
502
503 // cache the leading digit of the denominator
Damien George460b0862016-05-09 17:21:42 +0100504 lead_den_digit = (mpz_dbl_dig_t)den_dig[den_len - 1] << norm_shift;
505 if (den_len >= 2) {
506 lead_den_digit |= (mpz_dbl_dig_t)den_dig[den_len - 2] >> (DIG_SIZE - norm_shift);
507 }
Damien George438c88d2014-02-22 19:25:23 +0000508
509 // point num_dig to last digit in numerator
510 num_dig += *num_len - 1;
511
512 // calculate number of digits in quotient
513 *quo_len = *num_len - den_len;
514
515 // point to last digit to store for quotient
516 quo_dig += *quo_len - 1;
517
518 // keep going while we have enough digits to divide
519 while (*num_len > den_len) {
Damien George9a21d2e2014-09-06 17:15:34 +0100520 mpz_dbl_dig_t quo = ((mpz_dbl_dig_t)*num_dig << DIG_SIZE) | num_dig[-1];
Damien George438c88d2014-02-22 19:25:23 +0000521
522 // get approximate quotient
523 quo /= lead_den_digit;
524
Damien George9a21d2e2014-09-06 17:15:34 +0100525 // Multiply quo by den and subtract from num to get remainder.
526 // We have different code here to handle different compile-time
527 // configurations of mpz:
528 //
529 // 1. DIG_SIZE is stricly less than half the number of bits
530 // available in mpz_dbl_dig_t. In this case we can use a
531 // slightly more optimal (in time and space) routine that
532 // uses the extra bits in mpz_dbl_dig_signed_t to store a
533 // sign bit.
534 //
535 // 2. DIG_SIZE is exactly half the number of bits available in
536 // mpz_dbl_dig_t. In this (common) case we need to be careful
537 // not to overflow the borrow variable. And the shifting of
538 // borrow needs some special logic (it's a shift right with
539 // round up).
540
541 if (DIG_SIZE < 8 * sizeof(mpz_dbl_dig_t) / 2) {
Damien George460b0862016-05-09 17:21:42 +0100542 const mpz_dig_t *d = den_dig;
543 mpz_dbl_dig_t d_norm = 0;
Damien George438c88d2014-02-22 19:25:23 +0000544 mpz_dbl_dig_signed_t borrow = 0;
545
Damien George460b0862016-05-09 17:21:42 +0100546 for (mpz_dig_t *n = num_dig - den_len; n < num_dig; ++n, ++d) {
547 d_norm = ((mpz_dbl_dig_t)*d << norm_shift) | (d_norm >> DIG_SIZE);
548 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 +0000549 *n = borrow & DIG_MASK;
550 borrow >>= DIG_SIZE;
551 }
Damien George9a21d2e2014-09-06 17:15:34 +0100552 borrow += *num_dig; // will overflow if DIG_SIZE >= 8*sizeof(mpz_dbl_dig_t)/2
Damien George438c88d2014-02-22 19:25:23 +0000553 *num_dig = borrow & DIG_MASK;
554 borrow >>= DIG_SIZE;
555
556 // adjust quotient if it is too big
557 for (; borrow != 0; --quo) {
Damien George460b0862016-05-09 17:21:42 +0100558 d = den_dig;
559 d_norm = 0;
Damien George438c88d2014-02-22 19:25:23 +0000560 mpz_dbl_dig_t carry = 0;
Damien George460b0862016-05-09 17:21:42 +0100561 for (mpz_dig_t *n = num_dig - den_len; n < num_dig; ++n, ++d) {
562 d_norm = ((mpz_dbl_dig_t)*d << norm_shift) | (d_norm >> DIG_SIZE);
563 carry += (mpz_dbl_dig_t)*n + (d_norm & DIG_MASK);
Damien George438c88d2014-02-22 19:25:23 +0000564 *n = carry & DIG_MASK;
565 carry >>= DIG_SIZE;
566 }
567 carry += *num_dig;
568 *num_dig = carry & DIG_MASK;
569 carry >>= DIG_SIZE;
570
571 borrow += carry;
572 }
Damien George9a21d2e2014-09-06 17:15:34 +0100573 } else { // DIG_SIZE == 8 * sizeof(mpz_dbl_dig_t) / 2
Damien George460b0862016-05-09 17:21:42 +0100574 const mpz_dig_t *d = den_dig;
575 mpz_dbl_dig_t d_norm = 0;
Damien George9a21d2e2014-09-06 17:15:34 +0100576 mpz_dbl_dig_t borrow = 0;
577
Damien George460b0862016-05-09 17:21:42 +0100578 for (mpz_dig_t *n = num_dig - den_len; n < num_dig; ++n, ++d) {
579 d_norm = ((mpz_dbl_dig_t)*d << norm_shift) | (d_norm >> DIG_SIZE);
580 mpz_dbl_dig_t x = (mpz_dbl_dig_t)quo * (d_norm & DIG_MASK);
Damien George9a21d2e2014-09-06 17:15:34 +0100581 if (x >= *n || *n - x <= borrow) {
582 borrow += (mpz_dbl_dig_t)x - (mpz_dbl_dig_t)*n;
583 *n = (-borrow) & DIG_MASK;
584 borrow = (borrow >> DIG_SIZE) + ((borrow & DIG_MASK) == 0 ? 0 : 1); // shift-right with round-up
585 } else {
586 *n = ((mpz_dbl_dig_t)*n - (mpz_dbl_dig_t)x - (mpz_dbl_dig_t)borrow) & DIG_MASK;
587 borrow = 0;
588 }
589 }
590 if (borrow >= *num_dig) {
591 borrow -= (mpz_dbl_dig_t)*num_dig;
592 *num_dig = (-borrow) & DIG_MASK;
593 borrow = (borrow >> DIG_SIZE) + ((borrow & DIG_MASK) == 0 ? 0 : 1); // shift-right with round-up
594 } else {
595 *num_dig = (*num_dig - borrow) & DIG_MASK;
596 borrow = 0;
597 }
598
599 // adjust quotient if it is too big
600 for (; borrow != 0; --quo) {
Damien George460b0862016-05-09 17:21:42 +0100601 d = den_dig;
602 d_norm = 0;
Damien George9a21d2e2014-09-06 17:15:34 +0100603 mpz_dbl_dig_t carry = 0;
Damien George460b0862016-05-09 17:21:42 +0100604 for (mpz_dig_t *n = num_dig - den_len; n < num_dig; ++n, ++d) {
605 d_norm = ((mpz_dbl_dig_t)*d << norm_shift) | (d_norm >> DIG_SIZE);
606 carry += (mpz_dbl_dig_t)*n + (d_norm & DIG_MASK);
Damien George9a21d2e2014-09-06 17:15:34 +0100607 *n = carry & DIG_MASK;
608 carry >>= DIG_SIZE;
609 }
610 carry += (mpz_dbl_dig_t)*num_dig;
611 *num_dig = carry & DIG_MASK;
612 carry >>= DIG_SIZE;
613
614 //assert(borrow >= carry); // enable this to check the logic
615 borrow -= carry;
616 }
Damien George438c88d2014-02-22 19:25:23 +0000617 }
618
619 // store this digit of the quotient
620 *quo_dig = quo & DIG_MASK;
621 --quo_dig;
622
623 // move down to next digit of numerator
624 --num_dig;
625 --(*num_len);
626 }
627
Damien George438c88d2014-02-22 19:25:23 +0000628 // unnormalise numerator (remainder now)
629 for (mpz_dig_t *num = orig_num_dig + *num_len - 1, carry = 0; num >= orig_num_dig; --num) {
630 mpz_dig_t n = *num;
631 *num = ((n >> norm_shift) | carry) & DIG_MASK;
Damien Georgedc3faea2016-05-08 21:38:43 +0100632 carry = (mpz_dbl_dig_t)n << (DIG_SIZE - norm_shift);
Damien George438c88d2014-02-22 19:25:23 +0000633 }
634
635 // strip trailing zeros
636
637 while (*quo_len > 0 && orig_quo_dig[*quo_len - 1] == 0) {
638 --(*quo_len);
639 }
640
641 while (*num_len > 0 && orig_num_dig[*num_len - 1] == 0) {
642 --(*num_len);
643 }
644}
645
Damien George06201ff2014-03-01 19:50:50 +0000646#define MIN_ALLOC (2)
Damien George438c88d2014-02-22 19:25:23 +0000647
Damien George438c88d2014-02-22 19:25:23 +0000648void mpz_init_zero(mpz_t *z) {
Damien George438c88d2014-02-22 19:25:23 +0000649 z->neg = 0;
Damien George06201ff2014-03-01 19:50:50 +0000650 z->fixed_dig = 0;
651 z->alloc = 0;
Damien George438c88d2014-02-22 19:25:23 +0000652 z->len = 0;
653 z->dig = NULL;
654}
655
Damien George40f3c022014-07-03 13:25:24 +0100656void mpz_init_from_int(mpz_t *z, mp_int_t val) {
Damien George438c88d2014-02-22 19:25:23 +0000657 mpz_init_zero(z);
658 mpz_set_from_int(z, val);
659}
660
Damien Georgeafb1cf72014-09-05 20:37:06 +0100661void 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 +0000662 z->neg = 0;
663 z->fixed_dig = 1;
664 z->alloc = alloc;
665 z->len = 0;
666 z->dig = dig;
667 mpz_set_from_int(z, val);
668}
669
Damien George438c88d2014-02-22 19:25:23 +0000670void mpz_deinit(mpz_t *z) {
Damien George06201ff2014-03-01 19:50:50 +0000671 if (z != NULL && !z->fixed_dig) {
Damien George438c88d2014-02-22 19:25:23 +0000672 m_del(mpz_dig_t, z->dig, z->alloc);
673 }
674}
675
Damien George848dd0e2015-03-12 15:59:40 +0000676#if 0
677these functions are unused
678
Damien George438c88d2014-02-22 19:25:23 +0000679mpz_t *mpz_zero(void) {
680 mpz_t *z = m_new_obj(mpz_t);
681 mpz_init_zero(z);
682 return z;
683}
684
Damien George40f3c022014-07-03 13:25:24 +0100685mpz_t *mpz_from_int(mp_int_t val) {
Damien George438c88d2014-02-22 19:25:23 +0000686 mpz_t *z = mpz_zero();
687 mpz_set_from_int(z, val);
688 return z;
689}
690
Damien George95307432014-09-10 22:10:33 +0100691mpz_t *mpz_from_ll(long long val, bool is_signed) {
Damien Georgebb4a43f2014-03-12 15:36:06 +0000692 mpz_t *z = mpz_zero();
Damien George95307432014-09-10 22:10:33 +0100693 mpz_set_from_ll(z, val, is_signed);
Damien Georgebb4a43f2014-03-12 15:36:06 +0000694 return z;
695}
696
David Steinberg6e0b6d02015-01-02 12:39:22 +0000697#if MICROPY_PY_BUILTINS_FLOAT
698mpz_t *mpz_from_float(mp_float_t val) {
699 mpz_t *z = mpz_zero();
700 mpz_set_from_float(z, val);
701 return z;
702}
703#endif
704
Damien Georgeafb1cf72014-09-05 20:37:06 +0100705mpz_t *mpz_from_str(const char *str, mp_uint_t len, bool neg, mp_uint_t base) {
Damien George438c88d2014-02-22 19:25:23 +0000706 mpz_t *z = mpz_zero();
707 mpz_set_from_str(z, str, len, neg, base);
708 return z;
709}
Damien George848dd0e2015-03-12 15:59:40 +0000710#endif
Damien George438c88d2014-02-22 19:25:23 +0000711
Damien George848dd0e2015-03-12 15:59:40 +0000712STATIC void mpz_free(mpz_t *z) {
Damien George438c88d2014-02-22 19:25:23 +0000713 if (z != NULL) {
714 m_del(mpz_dig_t, z->dig, z->alloc);
715 m_del_obj(mpz_t, z);
716 }
717}
718
Damien Georgeafb1cf72014-09-05 20:37:06 +0100719STATIC void mpz_need_dig(mpz_t *z, mp_uint_t need) {
Damien George438c88d2014-02-22 19:25:23 +0000720 if (need < MIN_ALLOC) {
Damien George06201ff2014-03-01 19:50:50 +0000721 need = MIN_ALLOC;
Damien George438c88d2014-02-22 19:25:23 +0000722 }
723
Damien George06201ff2014-03-01 19:50:50 +0000724 if (z->dig == NULL || z->alloc < need) {
Damien Georgedf3e5d22016-10-11 13:00:56 +1100725 // if z has fixed digit buffer there's not much we can do as the caller will
726 // be expecting a buffer with at least "need" bytes (but it shouldn't happen)
727 assert(!z->fixed_dig);
Damien George06201ff2014-03-01 19:50:50 +0000728 z->dig = m_renew(mpz_dig_t, z->dig, z->alloc, need);
729 z->alloc = need;
Damien George438c88d2014-02-22 19:25:23 +0000730 }
731}
732
Damien George848dd0e2015-03-12 15:59:40 +0000733STATIC mpz_t *mpz_clone(const mpz_t *src) {
Damien George438c88d2014-02-22 19:25:23 +0000734 mpz_t *z = m_new_obj(mpz_t);
Damien George438c88d2014-02-22 19:25:23 +0000735 z->neg = src->neg;
Damien George06201ff2014-03-01 19:50:50 +0000736 z->fixed_dig = 0;
737 z->alloc = src->alloc;
Damien George438c88d2014-02-22 19:25:23 +0000738 z->len = src->len;
739 if (src->dig == NULL) {
740 z->dig = NULL;
741 } else {
742 z->dig = m_new(mpz_dig_t, z->alloc);
743 memcpy(z->dig, src->dig, src->alloc * sizeof(mpz_dig_t));
744 }
745 return z;
746}
747
Damien George06201ff2014-03-01 19:50:50 +0000748/* sets dest = src
749 can have dest, src the same
750*/
Damien George438c88d2014-02-22 19:25:23 +0000751void mpz_set(mpz_t *dest, const mpz_t *src) {
752 mpz_need_dig(dest, src->len);
753 dest->neg = src->neg;
754 dest->len = src->len;
755 memcpy(dest->dig, src->dig, src->len * sizeof(mpz_dig_t));
756}
757
Damien George40f3c022014-07-03 13:25:24 +0100758void mpz_set_from_int(mpz_t *z, mp_int_t val) {
Damien George58056b02015-01-09 20:58:58 +0000759 if (val == 0) {
760 z->len = 0;
761 return;
762 }
763
Damien George06201ff2014-03-01 19:50:50 +0000764 mpz_need_dig(z, MPZ_NUM_DIG_FOR_INT);
Damien George438c88d2014-02-22 19:25:23 +0000765
Damien George40f3c022014-07-03 13:25:24 +0100766 mp_uint_t uval;
Damien George438c88d2014-02-22 19:25:23 +0000767 if (val < 0) {
768 z->neg = 1;
Damien Georgebb4a43f2014-03-12 15:36:06 +0000769 uval = -val;
Damien George438c88d2014-02-22 19:25:23 +0000770 } else {
771 z->neg = 0;
Damien Georgebb4a43f2014-03-12 15:36:06 +0000772 uval = val;
Damien George438c88d2014-02-22 19:25:23 +0000773 }
774
775 z->len = 0;
Damien Georgebb4a43f2014-03-12 15:36:06 +0000776 while (uval > 0) {
777 z->dig[z->len++] = uval & DIG_MASK;
778 uval >>= DIG_SIZE;
779 }
780}
781
Damien George95307432014-09-10 22:10:33 +0100782void mpz_set_from_ll(mpz_t *z, long long val, bool is_signed) {
Damien Georgebb4a43f2014-03-12 15:36:06 +0000783 mpz_need_dig(z, MPZ_NUM_DIG_FOR_LL);
784
785 unsigned long long uval;
Damien George95307432014-09-10 22:10:33 +0100786 if (is_signed && val < 0) {
Damien Georgebb4a43f2014-03-12 15:36:06 +0000787 z->neg = 1;
788 uval = -val;
789 } else {
790 z->neg = 0;
791 uval = val;
792 }
793
794 z->len = 0;
795 while (uval > 0) {
796 z->dig[z->len++] = uval & DIG_MASK;
797 uval >>= DIG_SIZE;
Damien George438c88d2014-02-22 19:25:23 +0000798 }
799}
800
David Steinberg6e0b6d02015-01-02 12:39:22 +0000801#if MICROPY_PY_BUILTINS_FLOAT
802void mpz_set_from_float(mpz_t *z, mp_float_t src) {
803#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE
David Steinberg6e0b6d02015-01-02 12:39:22 +0000804typedef uint64_t mp_float_int_t;
David Steinbergc585ad12015-01-13 15:19:37 +0000805#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
David Steinberg6e0b6d02015-01-02 12:39:22 +0000806typedef uint32_t mp_float_int_t;
807#endif
808 union {
809 mp_float_t f;
Damien George2adf7ec2016-01-08 17:56:58 +0000810 #if MP_ENDIANNESS_LITTLE
David Steinbergc585ad12015-01-13 15:19:37 +0000811 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 +0000812 #else
813 struct { mp_float_int_t sgn:1, exp:MP_FLOAT_EXP_BITS, frc:MP_FLOAT_FRAC_BITS; } p;
814 #endif
David Steinberg6e0b6d02015-01-02 12:39:22 +0000815 } u = {src};
816
817 z->neg = u.p.sgn;
818 if (u.p.exp == 0) {
819 // value == 0 || value < 1
Damien George58056b02015-01-09 20:58:58 +0000820 mpz_set_from_int(z, 0);
David Steinbergc585ad12015-01-13 15:19:37 +0000821 } else if (u.p.exp == ((1 << MP_FLOAT_EXP_BITS) - 1)) {
Damien George6fd4b362015-01-02 23:04:09 +0000822 // u.p.frc == 0 indicates inf, else NaN
823 // should be handled by caller
Damien George58056b02015-01-09 20:58:58 +0000824 mpz_set_from_int(z, 0);
David Steinberg6e0b6d02015-01-02 12:39:22 +0000825 } else {
David Steinbergc585ad12015-01-13 15:19:37 +0000826 const int adj_exp = (int)u.p.exp - MP_FLOAT_EXP_BIAS;
David Steinberg6e0b6d02015-01-02 12:39:22 +0000827 if (adj_exp < 0) {
828 // value < 1 , truncates to 0
Damien George58056b02015-01-09 20:58:58 +0000829 mpz_set_from_int(z, 0);
David Steinberg6e0b6d02015-01-02 12:39:22 +0000830 } else if (adj_exp == 0) {
831 // 1 <= value < 2 , so truncates to 1
Damien George58056b02015-01-09 20:58:58 +0000832 mpz_set_from_int(z, 1);
David Steinberg6e0b6d02015-01-02 12:39:22 +0000833 } else {
834 // 2 <= value
835 const int dig_cnt = (adj_exp + 1 + (DIG_SIZE - 1)) / DIG_SIZE;
836 const unsigned int rem = adj_exp % DIG_SIZE;
837 int dig_ind, shft;
David Steinbergc585ad12015-01-13 15:19:37 +0000838 mp_float_int_t frc = u.p.frc | ((mp_float_int_t)1 << MP_FLOAT_FRAC_BITS);
David Steinberg6e0b6d02015-01-02 12:39:22 +0000839
David Steinbergc585ad12015-01-13 15:19:37 +0000840 if (adj_exp < MP_FLOAT_FRAC_BITS) {
David Steinberg6e0b6d02015-01-02 12:39:22 +0000841 shft = 0;
842 dig_ind = 0;
David Steinbergc585ad12015-01-13 15:19:37 +0000843 frc >>= MP_FLOAT_FRAC_BITS - adj_exp;
David Steinberg6e0b6d02015-01-02 12:39:22 +0000844 } else {
David Steinbergc585ad12015-01-13 15:19:37 +0000845 shft = (rem - MP_FLOAT_FRAC_BITS) % DIG_SIZE;
846 dig_ind = (adj_exp - MP_FLOAT_FRAC_BITS) / DIG_SIZE;
David Steinberg6e0b6d02015-01-02 12:39:22 +0000847 }
848 mpz_need_dig(z, dig_cnt);
849 z->len = dig_cnt;
850 if (dig_ind != 0) {
851 memset(z->dig, 0, dig_ind * sizeof(mpz_dig_t));
852 }
853 if (shft != 0) {
854 z->dig[dig_ind++] = (frc << shft) & DIG_MASK;
855 frc >>= DIG_SIZE - shft;
856 }
David Steinberg8d427b72015-01-13 15:20:32 +0000857#if DIG_SIZE < (MP_FLOAT_FRAC_BITS + 1)
David Steinberg6e0b6d02015-01-02 12:39:22 +0000858 while (dig_ind != dig_cnt) {
859 z->dig[dig_ind++] = frc & DIG_MASK;
860 frc >>= DIG_SIZE;
861 }
David Steinberg8d427b72015-01-13 15:20:32 +0000862#else
863 if (dig_ind != dig_cnt) {
864 z->dig[dig_ind] = frc;
865 }
866#endif
David Steinberg6e0b6d02015-01-02 12:39:22 +0000867 }
868 }
869}
David Steinberg6e0b6d02015-01-02 12:39:22 +0000870#endif
871
Damien George438c88d2014-02-22 19:25:23 +0000872// returns number of bytes from str that were processed
Damien Georgeafb1cf72014-09-05 20:37:06 +0100873mp_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 +0000874 assert(base < 36);
875
876 const char *cur = str;
877 const char *top = str + len;
878
879 mpz_need_dig(z, len * 8 / DIG_SIZE + 1);
880
881 if (neg) {
882 z->neg = 1;
883 } else {
884 z->neg = 0;
885 }
886
887 z->len = 0;
888 for (; cur < top; ++cur) { // XXX UTF8 next char
Damien Georgeafb1cf72014-09-05 20:37:06 +0100889 //mp_uint_t v = char_to_numeric(cur#); // XXX UTF8 get char
890 mp_uint_t v = *cur;
Damien George438c88d2014-02-22 19:25:23 +0000891 if ('0' <= v && v <= '9') {
892 v -= '0';
893 } else if ('A' <= v && v <= 'Z') {
894 v -= 'A' - 10;
895 } else if ('a' <= v && v <= 'z') {
896 v -= 'a' - 10;
897 } else {
898 break;
899 }
900 if (v >= base) {
901 break;
902 }
903 z->len = mpn_mul_dig_add_dig(z->dig, z->len, base, v);
904 }
905
906 return cur - str;
907}
908
909bool mpz_is_zero(const mpz_t *z) {
910 return z->len == 0;
911}
912
Damien Georgea2e38382015-03-02 12:58:06 +0000913#if 0
914these functions are unused
915
Damien George438c88d2014-02-22 19:25:23 +0000916bool mpz_is_pos(const mpz_t *z) {
917 return z->len > 0 && z->neg == 0;
918}
919
920bool mpz_is_neg(const mpz_t *z) {
921 return z->len > 0 && z->neg != 0;
922}
923
924bool mpz_is_odd(const mpz_t *z) {
925 return z->len > 0 && (z->dig[0] & 1) != 0;
926}
927
928bool mpz_is_even(const mpz_t *z) {
929 return z->len == 0 || (z->dig[0] & 1) == 0;
930}
Damien Georgea2e38382015-03-02 12:58:06 +0000931#endif
Damien George438c88d2014-02-22 19:25:23 +0000932
Damien George42f3de92014-10-03 17:44:14 +0000933int mpz_cmp(const mpz_t *z1, const mpz_t *z2) {
Damien Georgea9dc9b82015-01-27 17:47:38 +0000934 // to catch comparison of -0 with +0
935 if (z1->len == 0 && z2->len == 0) {
936 return 0;
937 }
Damien George42f3de92014-10-03 17:44:14 +0000938 int cmp = (int)z2->neg - (int)z1->neg;
Damien George438c88d2014-02-22 19:25:23 +0000939 if (cmp != 0) {
940 return cmp;
941 }
942 cmp = mpn_cmp(z1->dig, z1->len, z2->dig, z2->len);
943 if (z1->neg != 0) {
944 cmp = -cmp;
945 }
946 return cmp;
947}
948
Damien George06201ff2014-03-01 19:50:50 +0000949#if 0
950// obsolete
951// compares mpz with an integer that fits within DIG_SIZE bits
Damien Georgeafb1cf72014-09-05 20:37:06 +0100952mp_int_t mpz_cmp_sml_int(const mpz_t *z, mp_int_t sml_int) {
953 mp_int_t cmp;
Damien George438c88d2014-02-22 19:25:23 +0000954 if (z->neg == 0) {
955 if (sml_int < 0) return 1;
956 if (sml_int == 0) {
957 if (z->len == 0) return 0;
958 return 1;
959 }
960 if (z->len == 0) return -1;
961 assert(sml_int < (1 << DIG_SIZE));
962 if (z->len != 1) return 1;
963 cmp = z->dig[0] - sml_int;
964 } else {
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 }
975 if (cmp < 0) return -1;
976 if (cmp > 0) return 1;
977 return 0;
978}
Damien George06201ff2014-03-01 19:50:50 +0000979#endif
Damien George438c88d2014-02-22 19:25:23 +0000980
Damien George438c88d2014-02-22 19:25:23 +0000981#if 0
982these functions are unused
983
984/* returns abs(z)
985*/
986mpz_t *mpz_abs(const mpz_t *z) {
987 mpz_t *z2 = mpz_clone(z);
988 z2->neg = 0;
989 return z2;
990}
991
992/* returns -z
993*/
994mpz_t *mpz_neg(const mpz_t *z) {
995 mpz_t *z2 = mpz_clone(z);
996 z2->neg = 1 - z2->neg;
997 return z2;
998}
999
1000/* returns lhs + rhs
1001 can have lhs, rhs the same
1002*/
1003mpz_t *mpz_add(const mpz_t *lhs, const mpz_t *rhs) {
1004 mpz_t *z = mpz_zero();
1005 mpz_add_inpl(z, lhs, rhs);
1006 return z;
1007}
1008
1009/* returns lhs - rhs
1010 can have lhs, rhs the same
1011*/
1012mpz_t *mpz_sub(const mpz_t *lhs, const mpz_t *rhs) {
1013 mpz_t *z = mpz_zero();
1014 mpz_sub_inpl(z, lhs, rhs);
1015 return z;
1016}
1017
1018/* returns lhs * rhs
1019 can have lhs, rhs the same
1020*/
1021mpz_t *mpz_mul(const mpz_t *lhs, const mpz_t *rhs) {
1022 mpz_t *z = mpz_zero();
1023 mpz_mul_inpl(z, lhs, rhs);
1024 return z;
1025}
1026
1027/* returns lhs ** rhs
1028 can have lhs, rhs the same
1029*/
1030mpz_t *mpz_pow(const mpz_t *lhs, const mpz_t *rhs) {
1031 mpz_t *z = mpz_zero();
1032 mpz_pow_inpl(z, lhs, rhs);
1033 return z;
1034}
Damien Georgea2e38382015-03-02 12:58:06 +00001035
1036/* computes new integers in quo and rem such that:
1037 quo * rhs + rem = lhs
1038 0 <= rem < rhs
1039 can have lhs, rhs the same
1040*/
1041void mpz_divmod(const mpz_t *lhs, const mpz_t *rhs, mpz_t **quo, mpz_t **rem) {
1042 *quo = mpz_zero();
1043 *rem = mpz_zero();
1044 mpz_divmod_inpl(*quo, *rem, lhs, rhs);
1045}
Damien George438c88d2014-02-22 19:25:23 +00001046#endif
1047
1048/* computes dest = abs(z)
1049 can have dest, z the same
1050*/
1051void mpz_abs_inpl(mpz_t *dest, const mpz_t *z) {
1052 if (dest != z) {
1053 mpz_set(dest, z);
1054 }
1055 dest->neg = 0;
1056}
1057
1058/* computes dest = -z
1059 can have dest, z the same
1060*/
1061void mpz_neg_inpl(mpz_t *dest, const mpz_t *z) {
1062 if (dest != z) {
1063 mpz_set(dest, z);
1064 }
1065 dest->neg = 1 - dest->neg;
1066}
1067
Damien George06201ff2014-03-01 19:50:50 +00001068/* computes dest = ~z (= -z - 1)
1069 can have dest, z the same
1070*/
1071void mpz_not_inpl(mpz_t *dest, const mpz_t *z) {
1072 if (dest != z) {
1073 mpz_set(dest, z);
1074 }
Damien Georgee0ac1942014-12-31 19:35:01 +00001075 if (dest->len == 0) {
1076 mpz_need_dig(dest, 1);
1077 dest->dig[0] = 1;
1078 dest->len = 1;
1079 dest->neg = 1;
1080 } else if (dest->neg) {
Damien George06201ff2014-03-01 19:50:50 +00001081 dest->neg = 0;
1082 mpz_dig_t k = 1;
1083 dest->len = mpn_sub(dest->dig, dest->dig, dest->len, &k, 1);
1084 } else {
Damien Georgee0ac1942014-12-31 19:35:01 +00001085 mpz_need_dig(dest, dest->len + 1);
Damien George06201ff2014-03-01 19:50:50 +00001086 mpz_dig_t k = 1;
1087 dest->len = mpn_add(dest->dig, dest->dig, dest->len, &k, 1);
1088 dest->neg = 1;
1089 }
1090}
1091
Damien Georgec5ac2ac2014-02-26 16:56:30 +00001092/* computes dest = lhs << rhs
1093 can have dest, lhs the same
1094*/
Damien George2f4e8512015-10-01 18:01:37 +01001095void mpz_shl_inpl(mpz_t *dest, const mpz_t *lhs, mp_uint_t rhs) {
Damien George06201ff2014-03-01 19:50:50 +00001096 if (lhs->len == 0 || rhs == 0) {
Damien Georgec5ac2ac2014-02-26 16:56:30 +00001097 mpz_set(dest, lhs);
Damien Georgec5ac2ac2014-02-26 16:56:30 +00001098 } else {
Damien George06201ff2014-03-01 19:50:50 +00001099 mpz_need_dig(dest, lhs->len + (rhs + DIG_SIZE - 1) / DIG_SIZE);
1100 dest->len = mpn_shl(dest->dig, lhs->dig, lhs->len, rhs);
1101 dest->neg = lhs->neg;
Damien Georgec5ac2ac2014-02-26 16:56:30 +00001102 }
Damien Georgec5ac2ac2014-02-26 16:56:30 +00001103}
1104
1105/* computes dest = lhs >> rhs
1106 can have dest, lhs the same
1107*/
Damien George2f4e8512015-10-01 18:01:37 +01001108void mpz_shr_inpl(mpz_t *dest, const mpz_t *lhs, mp_uint_t rhs) {
Damien George06201ff2014-03-01 19:50:50 +00001109 if (lhs->len == 0 || rhs == 0) {
Damien Georgec5ac2ac2014-02-26 16:56:30 +00001110 mpz_set(dest, lhs);
Damien Georgec5ac2ac2014-02-26 16:56:30 +00001111 } else {
Damien George06201ff2014-03-01 19:50:50 +00001112 mpz_need_dig(dest, lhs->len);
1113 dest->len = mpn_shr(dest->dig, lhs->dig, lhs->len, rhs);
1114 dest->neg = lhs->neg;
1115 if (dest->neg) {
1116 // arithmetic shift right, rounding to negative infinity
Damien Georgeafb1cf72014-09-05 20:37:06 +01001117 mp_uint_t n_whole = rhs / DIG_SIZE;
1118 mp_uint_t n_part = rhs % DIG_SIZE;
Damien George06201ff2014-03-01 19:50:50 +00001119 mpz_dig_t round_up = 0;
Damien Georgeafb1cf72014-09-05 20:37:06 +01001120 for (mp_uint_t i = 0; i < lhs->len && i < n_whole; i++) {
Damien George06201ff2014-03-01 19:50:50 +00001121 if (lhs->dig[i] != 0) {
1122 round_up = 1;
1123 break;
1124 }
1125 }
1126 if (n_whole < lhs->len && (lhs->dig[n_whole] & ((1 << n_part) - 1)) != 0) {
1127 round_up = 1;
1128 }
1129 if (round_up) {
Damien Georgee0ac1942014-12-31 19:35:01 +00001130 if (dest->len == 0) {
1131 // dest == 0, so need to add 1 by hand (answer will be -1)
1132 dest->dig[0] = 1;
1133 dest->len = 1;
1134 } else {
1135 // dest > 0, so can use mpn_add to add 1
1136 dest->len = mpn_add(dest->dig, dest->dig, dest->len, &round_up, 1);
1137 }
Damien George06201ff2014-03-01 19:50:50 +00001138 }
1139 }
Damien Georgec5ac2ac2014-02-26 16:56:30 +00001140 }
Damien Georgec5ac2ac2014-02-26 16:56:30 +00001141}
Damien Georgec5ac2ac2014-02-26 16:56:30 +00001142
Damien George438c88d2014-02-22 19:25:23 +00001143/* computes dest = lhs + rhs
1144 can have dest, lhs, rhs the same
1145*/
1146void mpz_add_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
1147 if (mpn_cmp(lhs->dig, lhs->len, rhs->dig, rhs->len) < 0) {
1148 const mpz_t *temp = lhs;
1149 lhs = rhs;
1150 rhs = temp;
1151 }
1152
1153 if (lhs->neg == rhs->neg) {
1154 mpz_need_dig(dest, lhs->len + 1);
1155 dest->len = mpn_add(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
1156 } else {
1157 mpz_need_dig(dest, lhs->len);
1158 dest->len = mpn_sub(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
1159 }
1160
1161 dest->neg = lhs->neg;
1162}
1163
1164/* computes dest = lhs - rhs
1165 can have dest, lhs, rhs the same
1166*/
1167void mpz_sub_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
1168 bool neg = false;
1169
1170 if (mpn_cmp(lhs->dig, lhs->len, rhs->dig, rhs->len) < 0) {
1171 const mpz_t *temp = lhs;
1172 lhs = rhs;
1173 rhs = temp;
1174 neg = true;
1175 }
1176
1177 if (lhs->neg != rhs->neg) {
1178 mpz_need_dig(dest, lhs->len + 1);
1179 dest->len = mpn_add(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
1180 } else {
1181 mpz_need_dig(dest, lhs->len);
1182 dest->len = mpn_sub(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
1183 }
1184
1185 if (neg) {
1186 dest->neg = 1 - lhs->neg;
1187 } else {
1188 dest->neg = lhs->neg;
1189 }
1190}
1191
Paul Sokolovsky57207b82014-03-23 01:52:36 +02001192/* computes dest = lhs & rhs
1193 can have dest, lhs, rhs the same
1194*/
1195void mpz_and_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
Doug Currie2e2e15c2016-01-30 22:35:58 -05001196 // make sure lhs has the most digits
1197 if (lhs->len < rhs->len) {
1198 const mpz_t *temp = lhs;
1199 lhs = rhs;
1200 rhs = temp;
Paul Sokolovsky57207b82014-03-23 01:52:36 +02001201 }
Doug Currie2e2e15c2016-01-30 22:35:58 -05001202
1203 #if MICROPY_OPT_MPZ_BITWISE
1204
1205 if ((0 == lhs->neg) && (0 == rhs->neg)) {
1206 mpz_need_dig(dest, lhs->len);
1207 dest->len = mpn_and(dest->dig, lhs->dig, rhs->dig, rhs->len);
1208 dest->neg = 0;
1209 } else {
1210 mpz_need_dig(dest, lhs->len + 1);
1211 dest->len = mpn_and_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len,
1212 lhs->neg == rhs->neg, 0 != lhs->neg, 0 != rhs->neg);
1213 dest->neg = lhs->neg & rhs->neg;
1214 }
1215
1216 #else
1217
1218 mpz_need_dig(dest, lhs->len + (lhs->neg || rhs->neg));
1219 dest->len = mpn_and_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len,
1220 (lhs->neg == rhs->neg) ? lhs->neg : 0, lhs->neg, rhs->neg);
1221 dest->neg = lhs->neg & rhs->neg;
1222
1223 #endif
Paul Sokolovsky57207b82014-03-23 01:52:36 +02001224}
1225
1226/* computes dest = lhs | rhs
1227 can have dest, lhs, rhs the same
1228*/
1229void mpz_or_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) {
Paul Sokolovsky57207b82014-03-23 01:52:36 +02001232 const mpz_t *temp = lhs;
1233 lhs = rhs;
1234 rhs = temp;
1235 }
1236
Doug Currie2e2e15c2016-01-30 22:35:58 -05001237 #if MICROPY_OPT_MPZ_BITWISE
1238
1239 if ((0 == lhs->neg) && (0 == rhs->neg)) {
Paul Sokolovsky57207b82014-03-23 01:52:36 +02001240 mpz_need_dig(dest, lhs->len);
1241 dest->len = mpn_or(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
Doug Currie2e2e15c2016-01-30 22:35:58 -05001242 dest->neg = 0;
Paul Sokolovsky57207b82014-03-23 01:52:36 +02001243 } else {
Doug Currie2e2e15c2016-01-30 22:35:58 -05001244 mpz_need_dig(dest, lhs->len + 1);
1245 dest->len = mpn_or_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len,
1246 0 != lhs->neg, 0 != rhs->neg);
1247 dest->neg = 1;
Paul Sokolovsky57207b82014-03-23 01:52:36 +02001248 }
1249
Doug Currie2e2e15c2016-01-30 22:35:58 -05001250 #else
1251
1252 mpz_need_dig(dest, lhs->len + (lhs->neg || rhs->neg));
1253 dest->len = mpn_or_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len,
1254 (lhs->neg || rhs->neg), 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_xor_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
Paul Sokolovsky57207b82014-03-23 01:52:36 +02001273 if (lhs->neg == rhs->neg) {
1274 mpz_need_dig(dest, lhs->len);
Doug Currie2e2e15c2016-01-30 22:35:58 -05001275 if (lhs->neg == 0) {
1276 dest->len = mpn_xor(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
1277 } else {
1278 dest->len = mpn_xor_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len, 0, 0, 0);
1279 }
1280 dest->neg = 0;
Paul Sokolovsky57207b82014-03-23 01:52:36 +02001281 } else {
Doug Currie2e2e15c2016-01-30 22:35:58 -05001282 mpz_need_dig(dest, lhs->len + 1);
1283 dest->len = mpn_xor_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len, 1,
1284 0 == lhs->neg, 0 == rhs->neg);
1285 dest->neg = 1;
Paul Sokolovsky57207b82014-03-23 01:52:36 +02001286 }
1287
Doug Currie2e2e15c2016-01-30 22:35:58 -05001288 #else
1289
1290 mpz_need_dig(dest, lhs->len + (lhs->neg || rhs->neg));
1291 dest->len = mpn_xor_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len,
1292 (lhs->neg != rhs->neg), 0 == lhs->neg, 0 == rhs->neg);
1293 dest->neg = lhs->neg ^ rhs->neg;
1294
1295 #endif
Paul Sokolovsky57207b82014-03-23 01:52:36 +02001296}
1297
Damien George438c88d2014-02-22 19:25:23 +00001298/* computes dest = lhs * rhs
1299 can have dest, lhs, rhs the same
1300*/
Damien George4dea9222015-04-09 15:29:54 +00001301void mpz_mul_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
Damien George438c88d2014-02-22 19:25:23 +00001302 if (lhs->len == 0 || rhs->len == 0) {
Damien Georgec5ac2ac2014-02-26 16:56:30 +00001303 mpz_set_from_int(dest, 0);
1304 return;
Damien George438c88d2014-02-22 19:25:23 +00001305 }
1306
1307 mpz_t *temp = NULL;
1308 if (lhs == dest) {
1309 lhs = temp = mpz_clone(lhs);
1310 if (rhs == dest) {
1311 rhs = lhs;
1312 }
1313 } else if (rhs == dest) {
1314 rhs = temp = mpz_clone(rhs);
1315 }
1316
1317 mpz_need_dig(dest, lhs->len + rhs->len); // min mem l+r-1, max mem l+r
1318 memset(dest->dig, 0, dest->alloc * sizeof(mpz_dig_t));
1319 dest->len = mpn_mul(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
1320
1321 if (lhs->neg == rhs->neg) {
1322 dest->neg = 0;
1323 } else {
1324 dest->neg = 1;
1325 }
1326
1327 mpz_free(temp);
1328}
1329
1330/* computes dest = lhs ** rhs
1331 can have dest, lhs, rhs the same
1332*/
1333void mpz_pow_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
1334 if (lhs->len == 0 || rhs->neg != 0) {
Damien Georgec5ac2ac2014-02-26 16:56:30 +00001335 mpz_set_from_int(dest, 0);
1336 return;
Damien George438c88d2014-02-22 19:25:23 +00001337 }
1338
1339 if (rhs->len == 0) {
Damien Georgec5ac2ac2014-02-26 16:56:30 +00001340 mpz_set_from_int(dest, 1);
1341 return;
Damien George438c88d2014-02-22 19:25:23 +00001342 }
1343
1344 mpz_t *x = mpz_clone(lhs);
1345 mpz_t *n = mpz_clone(rhs);
1346
1347 mpz_set_from_int(dest, 1);
1348
1349 while (n->len > 0) {
Damien Georgea2e38382015-03-02 12:58:06 +00001350 if ((n->dig[0] & 1) != 0) {
Damien George438c88d2014-02-22 19:25:23 +00001351 mpz_mul_inpl(dest, dest, x);
1352 }
Damien George438c88d2014-02-22 19:25:23 +00001353 n->len = mpn_shr(n->dig, n->dig, n->len, 1);
Damien George5bf565e2014-04-04 00:16:32 +01001354 if (n->len == 0) {
1355 break;
1356 }
1357 mpz_mul_inpl(x, x, x);
Damien George438c88d2014-02-22 19:25:23 +00001358 }
1359
1360 mpz_free(x);
1361 mpz_free(n);
1362}
1363
Damien Georgea2e38382015-03-02 12:58:06 +00001364#if 0
1365these functions are unused
1366
Damien Georgeff1a96c2016-02-03 22:30:49 +00001367/* computes dest = (lhs ** rhs) % mod
1368 can have dest, lhs, rhs the same; mod can't be the same as dest
1369*/
1370void mpz_pow3_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs, const mpz_t *mod) {
1371 if (lhs->len == 0 || rhs->neg != 0) {
1372 mpz_set_from_int(dest, 0);
1373 return;
1374 }
1375
1376 if (rhs->len == 0) {
1377 mpz_set_from_int(dest, 1);
1378 return;
1379 }
1380
1381 mpz_t *x = mpz_clone(lhs);
1382 mpz_t *n = mpz_clone(rhs);
1383 mpz_t quo; mpz_init_zero(&quo);
1384
1385 mpz_set_from_int(dest, 1);
1386
1387 while (n->len > 0) {
1388 if ((n->dig[0] & 1) != 0) {
1389 mpz_mul_inpl(dest, dest, x);
1390 mpz_divmod_inpl(&quo, dest, dest, mod);
1391 }
1392 n->len = mpn_shr(n->dig, n->dig, n->len, 1);
1393 if (n->len == 0) {
1394 break;
1395 }
1396 mpz_mul_inpl(x, x, x);
1397 mpz_divmod_inpl(&quo, x, x, mod);
1398 }
1399
1400 mpz_deinit(&quo);
1401 mpz_free(x);
1402 mpz_free(n);
1403}
1404
Damien George438c88d2014-02-22 19:25:23 +00001405/* computes gcd(z1, z2)
1406 based on Knuth's modified gcd algorithm (I think?)
1407 gcd(z1, z2) >= 0
1408 gcd(0, 0) = 0
1409 gcd(z, 0) = abs(z)
1410*/
1411mpz_t *mpz_gcd(const mpz_t *z1, const mpz_t *z2) {
1412 if (z1->len == 0) {
1413 mpz_t *a = mpz_clone(z2);
1414 a->neg = 0;
1415 return a;
1416 } else if (z2->len == 0) {
1417 mpz_t *a = mpz_clone(z1);
1418 a->neg = 0;
1419 return a;
1420 }
1421
1422 mpz_t *a = mpz_clone(z1);
1423 mpz_t *b = mpz_clone(z2);
1424 mpz_t c; mpz_init_zero(&c);
1425 a->neg = 0;
1426 b->neg = 0;
1427
1428 for (;;) {
1429 if (mpz_cmp(a, b) < 0) {
1430 if (a->len == 0) {
1431 mpz_free(a);
1432 mpz_deinit(&c);
1433 return b;
1434 }
1435 mpz_t *t = a; a = b; b = t;
1436 }
1437 if (!(b->len >= 2 || (b->len == 1 && b->dig[0] > 1))) { // compute b > 0; could be mpz_cmp_small_int(b, 1) > 0
1438 break;
1439 }
1440 mpz_set(&c, b);
1441 do {
1442 mpz_add_inpl(&c, &c, &c);
1443 } while (mpz_cmp(&c, a) <= 0);
1444 c.len = mpn_shr(c.dig, c.dig, c.len, 1);
1445 mpz_sub_inpl(a, a, &c);
1446 }
1447
1448 mpz_deinit(&c);
1449
1450 if (b->len == 1 && b->dig[0] == 1) { // compute b == 1; could be mpz_cmp_small_int(b, 1) == 0
1451 mpz_free(a);
1452 return b;
1453 } else {
1454 mpz_free(b);
1455 return a;
1456 }
1457}
1458
1459/* computes lcm(z1, z2)
1460 = abs(z1) / gcd(z1, z2) * abs(z2)
1461 lcm(z1, z1) >= 0
1462 lcm(0, 0) = 0
1463 lcm(z, 0) = 0
1464*/
Damien George5d9b8162014-08-07 14:27:48 +00001465mpz_t *mpz_lcm(const mpz_t *z1, const mpz_t *z2) {
1466 if (z1->len == 0 || z2->len == 0) {
1467 return mpz_zero();
stijn01d6be42014-05-05 12:18:27 +02001468 }
Damien George438c88d2014-02-22 19:25:23 +00001469
1470 mpz_t *gcd = mpz_gcd(z1, z2);
1471 mpz_t *quo = mpz_zero();
1472 mpz_t *rem = mpz_zero();
1473 mpz_divmod_inpl(quo, rem, z1, gcd);
1474 mpz_mul_inpl(rem, quo, z2);
1475 mpz_free(gcd);
1476 mpz_free(quo);
1477 rem->neg = 0;
1478 return rem;
1479}
Damien Georgea2e38382015-03-02 12:58:06 +00001480#endif
Damien George438c88d2014-02-22 19:25:23 +00001481
1482/* computes new integers in quo and rem such that:
1483 quo * rhs + rem = lhs
1484 0 <= rem < rhs
1485 can have lhs, rhs the same
Damien George48874942016-10-11 13:00:01 +11001486 assumes rhs != 0 (undefined behaviour if it is)
Damien George438c88d2014-02-22 19:25:23 +00001487*/
1488void 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 +11001489 assert(!mpz_is_zero(rhs));
Damien George438c88d2014-02-22 19:25:23 +00001490
1491 mpz_need_dig(dest_quo, lhs->len + 1); // +1 necessary?
1492 memset(dest_quo->dig, 0, (lhs->len + 1) * sizeof(mpz_dig_t));
1493 dest_quo->len = 0;
1494 mpz_need_dig(dest_rem, lhs->len + 1); // +1 necessary?
1495 mpz_set(dest_rem, lhs);
Damien George438c88d2014-02-22 19:25:23 +00001496 mpn_div(dest_rem->dig, &dest_rem->len, rhs->dig, rhs->len, dest_quo->dig, &dest_quo->len);
1497
Damien George65402ab2016-05-08 22:21:21 +01001498 // check signs and do Python style modulo
Damien George438c88d2014-02-22 19:25:23 +00001499 if (lhs->neg != rhs->neg) {
1500 dest_quo->neg = 1;
Damien George65402ab2016-05-08 22:21:21 +01001501 if (!mpz_is_zero(dest_rem)) {
1502 mpz_t mpzone; mpz_init_from_int(&mpzone, -1);
1503 mpz_add_inpl(dest_quo, dest_quo, &mpzone);
1504 mpz_add_inpl(dest_rem, dest_rem, rhs);
1505 }
Damien George438c88d2014-02-22 19:25:23 +00001506 }
1507}
1508
1509#if 0
1510these functions are unused
1511
1512/* computes floor(lhs / rhs)
1513 can have lhs, rhs the same
1514*/
1515mpz_t *mpz_div(const mpz_t *lhs, const mpz_t *rhs) {
1516 mpz_t *quo = mpz_zero();
1517 mpz_t rem; mpz_init_zero(&rem);
1518 mpz_divmod_inpl(quo, &rem, lhs, rhs);
1519 mpz_deinit(&rem);
1520 return quo;
1521}
1522
1523/* computes lhs % rhs ( >= 0)
1524 can have lhs, rhs the same
1525*/
1526mpz_t *mpz_mod(const mpz_t *lhs, const mpz_t *rhs) {
1527 mpz_t quo; mpz_init_zero(&quo);
1528 mpz_t *rem = mpz_zero();
1529 mpz_divmod_inpl(&quo, rem, lhs, rhs);
1530 mpz_deinit(&quo);
1531 return rem;
1532}
1533#endif
1534
Damien Georgeffe911d2014-07-24 14:21:37 +01001535// must return actual int value if it fits in mp_int_t
1536mp_int_t mpz_hash(const mpz_t *z) {
1537 mp_int_t val = 0;
1538 mpz_dig_t *d = z->dig + z->len;
1539
Damien George58056b02015-01-09 20:58:58 +00001540 while (d-- > z->dig) {
Damien Georgeffe911d2014-07-24 14:21:37 +01001541 val = (val << DIG_SIZE) | *d;
1542 }
1543
1544 if (z->neg != 0) {
1545 val = -val;
1546 }
1547
1548 return val;
1549}
1550
Damien George40f3c022014-07-03 13:25:24 +01001551bool mpz_as_int_checked(const mpz_t *i, mp_int_t *value) {
Damien George963a5a32015-01-16 17:47:07 +00001552 mp_uint_t val = 0;
Damien George8270e382014-04-03 11:00:54 +00001553 mpz_dig_t *d = i->dig + i->len;
1554
Damien George58056b02015-01-09 20:58:58 +00001555 while (d-- > i->dig) {
Damien Georgec9aa58e2014-07-31 13:41:43 +00001556 if (val > (~(WORD_MSBIT_HIGH) >> DIG_SIZE)) {
1557 // will overflow
Damien George8270e382014-04-03 11:00:54 +00001558 return false;
1559 }
Damien Georgec9aa58e2014-07-31 13:41:43 +00001560 val = (val << DIG_SIZE) | *d;
Damien George8270e382014-04-03 11:00:54 +00001561 }
1562
1563 if (i->neg != 0) {
1564 val = -val;
1565 }
1566
1567 *value = val;
1568 return true;
1569}
1570
Damien Georgec9aa58e2014-07-31 13:41:43 +00001571bool mpz_as_uint_checked(const mpz_t *i, mp_uint_t *value) {
1572 if (i->neg != 0) {
1573 // can't represent signed values
1574 return false;
1575 }
1576
1577 mp_uint_t val = 0;
1578 mpz_dig_t *d = i->dig + i->len;
1579
Damien George58056b02015-01-09 20:58:58 +00001580 while (d-- > i->dig) {
Damien George9a21d2e2014-09-06 17:15:34 +01001581 if (val > (~(WORD_MSBIT_HIGH) >> (DIG_SIZE - 1))) {
Damien Georgec9aa58e2014-07-31 13:41:43 +00001582 // will overflow
1583 return false;
1584 }
1585 val = (val << DIG_SIZE) | *d;
1586 }
1587
1588 *value = val;
1589 return true;
1590}
1591
Damien George271d18e2015-04-25 23:16:39 +01001592// writes at most len bytes to buf (so buf should be zeroed before calling)
1593void mpz_as_bytes(const mpz_t *z, bool big_endian, mp_uint_t len, byte *buf) {
1594 byte *b = buf;
1595 if (big_endian) {
1596 b += len;
1597 }
1598 mpz_dig_t *zdig = z->dig;
1599 int bits = 0;
1600 mpz_dbl_dig_t d = 0;
1601 mpz_dbl_dig_t carry = 1;
1602 for (mp_uint_t zlen = z->len; zlen > 0; --zlen) {
1603 bits += DIG_SIZE;
1604 d = (d << DIG_SIZE) | *zdig++;
1605 for (; bits >= 8; bits -= 8, d >>= 8) {
1606 mpz_dig_t val = d;
1607 if (z->neg) {
Damien George94729072015-04-25 23:51:14 +01001608 val = (~val & 0xff) + carry;
1609 carry = val >> 8;
Damien George271d18e2015-04-25 23:16:39 +01001610 }
1611 if (big_endian) {
1612 *--b = val;
1613 if (b == buf) {
1614 return;
1615 }
1616 } else {
1617 *b++ = val;
1618 if (b == buf + len) {
1619 return;
1620 }
1621 }
1622 }
1623 }
1624}
1625
Damien Georgefb510b32014-06-01 13:32:54 +01001626#if MICROPY_PY_BUILTINS_FLOAT
Damien George52608102014-03-08 15:04:54 +00001627mp_float_t mpz_as_float(const mpz_t *i) {
1628 mp_float_t val = 0;
Damien George438c88d2014-02-22 19:25:23 +00001629 mpz_dig_t *d = i->dig + i->len;
1630
Damien George58056b02015-01-09 20:58:58 +00001631 while (d-- > i->dig) {
Damien George9a21d2e2014-09-06 17:15:34 +01001632 val = val * DIG_BASE + *d;
Damien George438c88d2014-02-22 19:25:23 +00001633 }
1634
1635 if (i->neg != 0) {
1636 val = -val;
1637 }
1638
1639 return val;
1640}
Damien George52608102014-03-08 15:04:54 +00001641#endif
Damien George438c88d2014-02-22 19:25:23 +00001642
Damien Georgeafb1cf72014-09-05 20:37:06 +01001643#if 0
1644this function is unused
1645char *mpz_as_str(const mpz_t *i, mp_uint_t base) {
1646 char *s = m_new(char, mpz_as_str_size(i, base, NULL, '\0'));
1647 mpz_as_str_inpl(i, base, NULL, 'a', '\0', s);
Damien George438c88d2014-02-22 19:25:23 +00001648 return s;
1649}
Damien Georgeafb1cf72014-09-05 20:37:06 +01001650#endif
Damien George438c88d2014-02-22 19:25:23 +00001651
Damien George8bb7d952016-10-11 13:11:32 +11001652// assumes enough space as calculated by mp_int_format_size
Damien George438c88d2014-02-22 19:25:23 +00001653// returns length of string, not including null byte
Damien Georgeafb1cf72014-09-05 20:37:06 +01001654mp_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 +00001655 if (str == NULL || base < 2 || base > 32) {
1656 str[0] = 0;
1657 return 0;
1658 }
1659
Damien Georgeafb1cf72014-09-05 20:37:06 +01001660 mp_uint_t ilen = i->len;
Damien George438c88d2014-02-22 19:25:23 +00001661
Dave Hylandsc4029e52014-04-07 11:19:51 -07001662 char *s = str;
Damien George438c88d2014-02-22 19:25:23 +00001663 if (ilen == 0) {
Dave Hylandsc4029e52014-04-07 11:19:51 -07001664 if (prefix) {
1665 while (*prefix)
1666 *s++ = *prefix++;
1667 }
1668 *s++ = '0';
1669 *s = '\0';
1670 return s - str;
Damien George438c88d2014-02-22 19:25:23 +00001671 }
1672
Damien Georgeeec91052014-04-08 23:11:00 +01001673 // make a copy of mpz digits, so we can do the div/mod calculation
Damien George438c88d2014-02-22 19:25:23 +00001674 mpz_dig_t *dig = m_new(mpz_dig_t, ilen);
1675 memcpy(dig, i->dig, ilen * sizeof(mpz_dig_t));
1676
1677 // convert
Dave Hylandsc4029e52014-04-07 11:19:51 -07001678 char *last_comma = str;
Damien George438c88d2014-02-22 19:25:23 +00001679 bool done;
1680 do {
1681 mpz_dig_t *d = dig + ilen;
1682 mpz_dbl_dig_t a = 0;
1683
1684 // compute next remainder
1685 while (--d >= dig) {
1686 a = (a << DIG_SIZE) | *d;
1687 *d = a / base;
1688 a %= base;
1689 }
1690
1691 // convert to character
1692 a += '0';
1693 if (a > '9') {
Dave Hylandsc4029e52014-04-07 11:19:51 -07001694 a += base_char - '9' - 1;
Damien George438c88d2014-02-22 19:25:23 +00001695 }
1696 *s++ = a;
1697
1698 // check if number is zero
1699 done = true;
1700 for (d = dig; d < dig + ilen; ++d) {
1701 if (*d != 0) {
1702 done = false;
1703 break;
1704 }
1705 }
Dave Hylandsc4029e52014-04-07 11:19:51 -07001706 if (comma && (s - last_comma) == 3) {
1707 *s++ = comma;
1708 last_comma = s;
1709 }
1710 }
1711 while (!done);
Damien George438c88d2014-02-22 19:25:23 +00001712
Damien Georgeeec91052014-04-08 23:11:00 +01001713 // free the copy of the digits array
1714 m_del(mpz_dig_t, dig, ilen);
1715
Dave Hylandsc4029e52014-04-07 11:19:51 -07001716 if (prefix) {
1717 const char *p = &prefix[strlen(prefix)];
1718 while (p > prefix) {
1719 *s++ = *--p;
1720 }
1721 }
Damien George438c88d2014-02-22 19:25:23 +00001722 if (i->neg != 0) {
1723 *s++ = '-';
1724 }
1725
1726 // reverse string
1727 for (char *u = str, *v = s - 1; u < v; ++u, --v) {
1728 char temp = *u;
1729 *u = *v;
1730 *v = temp;
1731 }
1732
Dave Hylandsc4029e52014-04-07 11:19:51 -07001733 *s = '\0'; // null termination
Damien George438c88d2014-02-22 19:25:23 +00001734
1735 return s - str;
1736}
1737
1738#endif // MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_MPZ