blob: bb76479569ddf2ab6c159ad207c867e3cb75c118 [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 George1c70cbf2014-08-30 00:38:16 +0100648STATIC const uint8_t log_base2_floor[] = {
Damien George438c88d2014-02-22 19:25:23 +0000649 0,
650 0, 1, 1, 2,
651 2, 2, 2, 3,
652 3, 3, 3, 3,
653 3, 3, 3, 4,
654 4, 4, 4, 4,
655 4, 4, 4, 4,
656 4, 4, 4, 4,
657 4, 4, 4, 5
658};
659
Damien George438c88d2014-02-22 19:25:23 +0000660void mpz_init_zero(mpz_t *z) {
Damien George438c88d2014-02-22 19:25:23 +0000661 z->neg = 0;
Damien George06201ff2014-03-01 19:50:50 +0000662 z->fixed_dig = 0;
663 z->alloc = 0;
Damien George438c88d2014-02-22 19:25:23 +0000664 z->len = 0;
665 z->dig = NULL;
666}
667
Damien George40f3c022014-07-03 13:25:24 +0100668void mpz_init_from_int(mpz_t *z, mp_int_t val) {
Damien George438c88d2014-02-22 19:25:23 +0000669 mpz_init_zero(z);
670 mpz_set_from_int(z, val);
671}
672
Damien Georgeafb1cf72014-09-05 20:37:06 +0100673void 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 +0000674 z->neg = 0;
675 z->fixed_dig = 1;
676 z->alloc = alloc;
677 z->len = 0;
678 z->dig = dig;
679 mpz_set_from_int(z, val);
680}
681
Damien George438c88d2014-02-22 19:25:23 +0000682void mpz_deinit(mpz_t *z) {
Damien George06201ff2014-03-01 19:50:50 +0000683 if (z != NULL && !z->fixed_dig) {
Damien George438c88d2014-02-22 19:25:23 +0000684 m_del(mpz_dig_t, z->dig, z->alloc);
685 }
686}
687
Damien George848dd0e2015-03-12 15:59:40 +0000688#if 0
689these functions are unused
690
Damien George438c88d2014-02-22 19:25:23 +0000691mpz_t *mpz_zero(void) {
692 mpz_t *z = m_new_obj(mpz_t);
693 mpz_init_zero(z);
694 return z;
695}
696
Damien George40f3c022014-07-03 13:25:24 +0100697mpz_t *mpz_from_int(mp_int_t val) {
Damien George438c88d2014-02-22 19:25:23 +0000698 mpz_t *z = mpz_zero();
699 mpz_set_from_int(z, val);
700 return z;
701}
702
Damien George95307432014-09-10 22:10:33 +0100703mpz_t *mpz_from_ll(long long val, bool is_signed) {
Damien Georgebb4a43f2014-03-12 15:36:06 +0000704 mpz_t *z = mpz_zero();
Damien George95307432014-09-10 22:10:33 +0100705 mpz_set_from_ll(z, val, is_signed);
Damien Georgebb4a43f2014-03-12 15:36:06 +0000706 return z;
707}
708
David Steinberg6e0b6d02015-01-02 12:39:22 +0000709#if MICROPY_PY_BUILTINS_FLOAT
710mpz_t *mpz_from_float(mp_float_t val) {
711 mpz_t *z = mpz_zero();
712 mpz_set_from_float(z, val);
713 return z;
714}
715#endif
716
Damien Georgeafb1cf72014-09-05 20:37:06 +0100717mpz_t *mpz_from_str(const char *str, mp_uint_t len, bool neg, mp_uint_t base) {
Damien George438c88d2014-02-22 19:25:23 +0000718 mpz_t *z = mpz_zero();
719 mpz_set_from_str(z, str, len, neg, base);
720 return z;
721}
Damien George848dd0e2015-03-12 15:59:40 +0000722#endif
Damien George438c88d2014-02-22 19:25:23 +0000723
Damien George848dd0e2015-03-12 15:59:40 +0000724STATIC void mpz_free(mpz_t *z) {
Damien George438c88d2014-02-22 19:25:23 +0000725 if (z != NULL) {
726 m_del(mpz_dig_t, z->dig, z->alloc);
727 m_del_obj(mpz_t, z);
728 }
729}
730
Damien Georgeafb1cf72014-09-05 20:37:06 +0100731STATIC void mpz_need_dig(mpz_t *z, mp_uint_t need) {
Damien George438c88d2014-02-22 19:25:23 +0000732 if (need < MIN_ALLOC) {
Damien George06201ff2014-03-01 19:50:50 +0000733 need = MIN_ALLOC;
Damien George438c88d2014-02-22 19:25:23 +0000734 }
735
Damien George06201ff2014-03-01 19:50:50 +0000736 if (z->dig == NULL || z->alloc < need) {
737 if (z->fixed_dig) {
738 // cannot reallocate fixed buffers
739 assert(0);
740 return;
741 }
742 z->dig = m_renew(mpz_dig_t, z->dig, z->alloc, need);
743 z->alloc = need;
Damien George438c88d2014-02-22 19:25:23 +0000744 }
745}
746
Damien George848dd0e2015-03-12 15:59:40 +0000747STATIC mpz_t *mpz_clone(const mpz_t *src) {
Damien George438c88d2014-02-22 19:25:23 +0000748 mpz_t *z = m_new_obj(mpz_t);
Damien George438c88d2014-02-22 19:25:23 +0000749 z->neg = src->neg;
Damien George06201ff2014-03-01 19:50:50 +0000750 z->fixed_dig = 0;
751 z->alloc = src->alloc;
Damien George438c88d2014-02-22 19:25:23 +0000752 z->len = src->len;
753 if (src->dig == NULL) {
754 z->dig = NULL;
755 } else {
756 z->dig = m_new(mpz_dig_t, z->alloc);
757 memcpy(z->dig, src->dig, src->alloc * sizeof(mpz_dig_t));
758 }
759 return z;
760}
761
Damien George06201ff2014-03-01 19:50:50 +0000762/* sets dest = src
763 can have dest, src the same
764*/
Damien George438c88d2014-02-22 19:25:23 +0000765void mpz_set(mpz_t *dest, const mpz_t *src) {
766 mpz_need_dig(dest, src->len);
767 dest->neg = src->neg;
768 dest->len = src->len;
769 memcpy(dest->dig, src->dig, src->len * sizeof(mpz_dig_t));
770}
771
Damien George40f3c022014-07-03 13:25:24 +0100772void mpz_set_from_int(mpz_t *z, mp_int_t val) {
Damien George58056b02015-01-09 20:58:58 +0000773 if (val == 0) {
774 z->len = 0;
775 return;
776 }
777
Damien George06201ff2014-03-01 19:50:50 +0000778 mpz_need_dig(z, MPZ_NUM_DIG_FOR_INT);
Damien George438c88d2014-02-22 19:25:23 +0000779
Damien George40f3c022014-07-03 13:25:24 +0100780 mp_uint_t uval;
Damien George438c88d2014-02-22 19:25:23 +0000781 if (val < 0) {
782 z->neg = 1;
Damien Georgebb4a43f2014-03-12 15:36:06 +0000783 uval = -val;
Damien George438c88d2014-02-22 19:25:23 +0000784 } else {
785 z->neg = 0;
Damien Georgebb4a43f2014-03-12 15:36:06 +0000786 uval = val;
Damien George438c88d2014-02-22 19:25:23 +0000787 }
788
789 z->len = 0;
Damien Georgebb4a43f2014-03-12 15:36:06 +0000790 while (uval > 0) {
791 z->dig[z->len++] = uval & DIG_MASK;
792 uval >>= DIG_SIZE;
793 }
794}
795
Damien George95307432014-09-10 22:10:33 +0100796void mpz_set_from_ll(mpz_t *z, long long val, bool is_signed) {
Damien Georgebb4a43f2014-03-12 15:36:06 +0000797 mpz_need_dig(z, MPZ_NUM_DIG_FOR_LL);
798
799 unsigned long long uval;
Damien George95307432014-09-10 22:10:33 +0100800 if (is_signed && val < 0) {
Damien Georgebb4a43f2014-03-12 15:36:06 +0000801 z->neg = 1;
802 uval = -val;
803 } else {
804 z->neg = 0;
805 uval = val;
806 }
807
808 z->len = 0;
809 while (uval > 0) {
810 z->dig[z->len++] = uval & DIG_MASK;
811 uval >>= DIG_SIZE;
Damien George438c88d2014-02-22 19:25:23 +0000812 }
813}
814
David Steinberg6e0b6d02015-01-02 12:39:22 +0000815#if MICROPY_PY_BUILTINS_FLOAT
816void mpz_set_from_float(mpz_t *z, mp_float_t src) {
817#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE
David Steinberg6e0b6d02015-01-02 12:39:22 +0000818typedef uint64_t mp_float_int_t;
David Steinbergc585ad12015-01-13 15:19:37 +0000819#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
David Steinberg6e0b6d02015-01-02 12:39:22 +0000820typedef uint32_t mp_float_int_t;
821#endif
822 union {
823 mp_float_t f;
Damien George2adf7ec2016-01-08 17:56:58 +0000824 #if MP_ENDIANNESS_LITTLE
David Steinbergc585ad12015-01-13 15:19:37 +0000825 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 +0000826 #else
827 struct { mp_float_int_t sgn:1, exp:MP_FLOAT_EXP_BITS, frc:MP_FLOAT_FRAC_BITS; } p;
828 #endif
David Steinberg6e0b6d02015-01-02 12:39:22 +0000829 } u = {src};
830
831 z->neg = u.p.sgn;
832 if (u.p.exp == 0) {
833 // value == 0 || value < 1
Damien George58056b02015-01-09 20:58:58 +0000834 mpz_set_from_int(z, 0);
David Steinbergc585ad12015-01-13 15:19:37 +0000835 } else if (u.p.exp == ((1 << MP_FLOAT_EXP_BITS) - 1)) {
Damien George6fd4b362015-01-02 23:04:09 +0000836 // u.p.frc == 0 indicates inf, else NaN
837 // should be handled by caller
Damien George58056b02015-01-09 20:58:58 +0000838 mpz_set_from_int(z, 0);
David Steinberg6e0b6d02015-01-02 12:39:22 +0000839 } else {
David Steinbergc585ad12015-01-13 15:19:37 +0000840 const int adj_exp = (int)u.p.exp - MP_FLOAT_EXP_BIAS;
David Steinberg6e0b6d02015-01-02 12:39:22 +0000841 if (adj_exp < 0) {
842 // value < 1 , truncates to 0
Damien George58056b02015-01-09 20:58:58 +0000843 mpz_set_from_int(z, 0);
David Steinberg6e0b6d02015-01-02 12:39:22 +0000844 } else if (adj_exp == 0) {
845 // 1 <= value < 2 , so truncates to 1
Damien George58056b02015-01-09 20:58:58 +0000846 mpz_set_from_int(z, 1);
David Steinberg6e0b6d02015-01-02 12:39:22 +0000847 } else {
848 // 2 <= value
849 const int dig_cnt = (adj_exp + 1 + (DIG_SIZE - 1)) / DIG_SIZE;
850 const unsigned int rem = adj_exp % DIG_SIZE;
851 int dig_ind, shft;
David Steinbergc585ad12015-01-13 15:19:37 +0000852 mp_float_int_t frc = u.p.frc | ((mp_float_int_t)1 << MP_FLOAT_FRAC_BITS);
David Steinberg6e0b6d02015-01-02 12:39:22 +0000853
David Steinbergc585ad12015-01-13 15:19:37 +0000854 if (adj_exp < MP_FLOAT_FRAC_BITS) {
David Steinberg6e0b6d02015-01-02 12:39:22 +0000855 shft = 0;
856 dig_ind = 0;
David Steinbergc585ad12015-01-13 15:19:37 +0000857 frc >>= MP_FLOAT_FRAC_BITS - adj_exp;
David Steinberg6e0b6d02015-01-02 12:39:22 +0000858 } else {
David Steinbergc585ad12015-01-13 15:19:37 +0000859 shft = (rem - MP_FLOAT_FRAC_BITS) % DIG_SIZE;
860 dig_ind = (adj_exp - MP_FLOAT_FRAC_BITS) / DIG_SIZE;
David Steinberg6e0b6d02015-01-02 12:39:22 +0000861 }
862 mpz_need_dig(z, dig_cnt);
863 z->len = dig_cnt;
864 if (dig_ind != 0) {
865 memset(z->dig, 0, dig_ind * sizeof(mpz_dig_t));
866 }
867 if (shft != 0) {
868 z->dig[dig_ind++] = (frc << shft) & DIG_MASK;
869 frc >>= DIG_SIZE - shft;
870 }
David Steinberg8d427b72015-01-13 15:20:32 +0000871#if DIG_SIZE < (MP_FLOAT_FRAC_BITS + 1)
David Steinberg6e0b6d02015-01-02 12:39:22 +0000872 while (dig_ind != dig_cnt) {
873 z->dig[dig_ind++] = frc & DIG_MASK;
874 frc >>= DIG_SIZE;
875 }
David Steinberg8d427b72015-01-13 15:20:32 +0000876#else
877 if (dig_ind != dig_cnt) {
878 z->dig[dig_ind] = frc;
879 }
880#endif
David Steinberg6e0b6d02015-01-02 12:39:22 +0000881 }
882 }
883}
David Steinberg6e0b6d02015-01-02 12:39:22 +0000884#endif
885
Damien George438c88d2014-02-22 19:25:23 +0000886// returns number of bytes from str that were processed
Damien Georgeafb1cf72014-09-05 20:37:06 +0100887mp_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 +0000888 assert(base < 36);
889
890 const char *cur = str;
891 const char *top = str + len;
892
893 mpz_need_dig(z, len * 8 / DIG_SIZE + 1);
894
895 if (neg) {
896 z->neg = 1;
897 } else {
898 z->neg = 0;
899 }
900
901 z->len = 0;
902 for (; cur < top; ++cur) { // XXX UTF8 next char
Damien Georgeafb1cf72014-09-05 20:37:06 +0100903 //mp_uint_t v = char_to_numeric(cur#); // XXX UTF8 get char
904 mp_uint_t v = *cur;
Damien George438c88d2014-02-22 19:25:23 +0000905 if ('0' <= v && v <= '9') {
906 v -= '0';
907 } else if ('A' <= v && v <= 'Z') {
908 v -= 'A' - 10;
909 } else if ('a' <= v && v <= 'z') {
910 v -= 'a' - 10;
911 } else {
912 break;
913 }
914 if (v >= base) {
915 break;
916 }
917 z->len = mpn_mul_dig_add_dig(z->dig, z->len, base, v);
918 }
919
920 return cur - str;
921}
922
923bool mpz_is_zero(const mpz_t *z) {
924 return z->len == 0;
925}
926
Damien Georgea2e38382015-03-02 12:58:06 +0000927#if 0
928these functions are unused
929
Damien George438c88d2014-02-22 19:25:23 +0000930bool mpz_is_pos(const mpz_t *z) {
931 return z->len > 0 && z->neg == 0;
932}
933
934bool mpz_is_neg(const mpz_t *z) {
935 return z->len > 0 && z->neg != 0;
936}
937
938bool mpz_is_odd(const mpz_t *z) {
939 return z->len > 0 && (z->dig[0] & 1) != 0;
940}
941
942bool mpz_is_even(const mpz_t *z) {
943 return z->len == 0 || (z->dig[0] & 1) == 0;
944}
Damien Georgea2e38382015-03-02 12:58:06 +0000945#endif
Damien George438c88d2014-02-22 19:25:23 +0000946
Damien George42f3de92014-10-03 17:44:14 +0000947int mpz_cmp(const mpz_t *z1, const mpz_t *z2) {
Damien Georgea9dc9b82015-01-27 17:47:38 +0000948 // to catch comparison of -0 with +0
949 if (z1->len == 0 && z2->len == 0) {
950 return 0;
951 }
Damien George42f3de92014-10-03 17:44:14 +0000952 int cmp = (int)z2->neg - (int)z1->neg;
Damien George438c88d2014-02-22 19:25:23 +0000953 if (cmp != 0) {
954 return cmp;
955 }
956 cmp = mpn_cmp(z1->dig, z1->len, z2->dig, z2->len);
957 if (z1->neg != 0) {
958 cmp = -cmp;
959 }
960 return cmp;
961}
962
Damien George06201ff2014-03-01 19:50:50 +0000963#if 0
964// obsolete
965// compares mpz with an integer that fits within DIG_SIZE bits
Damien Georgeafb1cf72014-09-05 20:37:06 +0100966mp_int_t mpz_cmp_sml_int(const mpz_t *z, mp_int_t sml_int) {
967 mp_int_t cmp;
Damien George438c88d2014-02-22 19:25:23 +0000968 if (z->neg == 0) {
969 if (sml_int < 0) return 1;
970 if (sml_int == 0) {
971 if (z->len == 0) return 0;
972 return 1;
973 }
974 if (z->len == 0) return -1;
975 assert(sml_int < (1 << DIG_SIZE));
976 if (z->len != 1) return 1;
977 cmp = z->dig[0] - sml_int;
978 } else {
979 if (sml_int > 0) return -1;
980 if (sml_int == 0) {
981 if (z->len == 0) return 0;
982 return -1;
983 }
984 if (z->len == 0) return 1;
985 assert(sml_int > -(1 << DIG_SIZE));
986 if (z->len != 1) return -1;
987 cmp = -z->dig[0] - sml_int;
988 }
989 if (cmp < 0) return -1;
990 if (cmp > 0) return 1;
991 return 0;
992}
Damien George06201ff2014-03-01 19:50:50 +0000993#endif
Damien George438c88d2014-02-22 19:25:23 +0000994
Damien George438c88d2014-02-22 19:25:23 +0000995#if 0
996these functions are unused
997
998/* returns abs(z)
999*/
1000mpz_t *mpz_abs(const mpz_t *z) {
1001 mpz_t *z2 = mpz_clone(z);
1002 z2->neg = 0;
1003 return z2;
1004}
1005
1006/* returns -z
1007*/
1008mpz_t *mpz_neg(const mpz_t *z) {
1009 mpz_t *z2 = mpz_clone(z);
1010 z2->neg = 1 - z2->neg;
1011 return z2;
1012}
1013
1014/* returns lhs + rhs
1015 can have lhs, rhs the same
1016*/
1017mpz_t *mpz_add(const mpz_t *lhs, const mpz_t *rhs) {
1018 mpz_t *z = mpz_zero();
1019 mpz_add_inpl(z, lhs, rhs);
1020 return z;
1021}
1022
1023/* returns lhs - rhs
1024 can have lhs, rhs the same
1025*/
1026mpz_t *mpz_sub(const mpz_t *lhs, const mpz_t *rhs) {
1027 mpz_t *z = mpz_zero();
1028 mpz_sub_inpl(z, lhs, rhs);
1029 return z;
1030}
1031
1032/* returns lhs * rhs
1033 can have lhs, rhs the same
1034*/
1035mpz_t *mpz_mul(const mpz_t *lhs, const mpz_t *rhs) {
1036 mpz_t *z = mpz_zero();
1037 mpz_mul_inpl(z, lhs, rhs);
1038 return z;
1039}
1040
1041/* returns lhs ** rhs
1042 can have lhs, rhs the same
1043*/
1044mpz_t *mpz_pow(const mpz_t *lhs, const mpz_t *rhs) {
1045 mpz_t *z = mpz_zero();
1046 mpz_pow_inpl(z, lhs, rhs);
1047 return z;
1048}
Damien Georgea2e38382015-03-02 12:58:06 +00001049
1050/* computes new integers in quo and rem such that:
1051 quo * rhs + rem = lhs
1052 0 <= rem < rhs
1053 can have lhs, rhs the same
1054*/
1055void mpz_divmod(const mpz_t *lhs, const mpz_t *rhs, mpz_t **quo, mpz_t **rem) {
1056 *quo = mpz_zero();
1057 *rem = mpz_zero();
1058 mpz_divmod_inpl(*quo, *rem, lhs, rhs);
1059}
Damien George438c88d2014-02-22 19:25:23 +00001060#endif
1061
1062/* computes dest = abs(z)
1063 can have dest, z the same
1064*/
1065void mpz_abs_inpl(mpz_t *dest, const mpz_t *z) {
1066 if (dest != z) {
1067 mpz_set(dest, z);
1068 }
1069 dest->neg = 0;
1070}
1071
1072/* computes dest = -z
1073 can have dest, z the same
1074*/
1075void mpz_neg_inpl(mpz_t *dest, const mpz_t *z) {
1076 if (dest != z) {
1077 mpz_set(dest, z);
1078 }
1079 dest->neg = 1 - dest->neg;
1080}
1081
Damien George06201ff2014-03-01 19:50:50 +00001082/* computes dest = ~z (= -z - 1)
1083 can have dest, z the same
1084*/
1085void mpz_not_inpl(mpz_t *dest, const mpz_t *z) {
1086 if (dest != z) {
1087 mpz_set(dest, z);
1088 }
Damien Georgee0ac1942014-12-31 19:35:01 +00001089 if (dest->len == 0) {
1090 mpz_need_dig(dest, 1);
1091 dest->dig[0] = 1;
1092 dest->len = 1;
1093 dest->neg = 1;
1094 } else if (dest->neg) {
Damien George06201ff2014-03-01 19:50:50 +00001095 dest->neg = 0;
1096 mpz_dig_t k = 1;
1097 dest->len = mpn_sub(dest->dig, dest->dig, dest->len, &k, 1);
1098 } else {
Damien Georgee0ac1942014-12-31 19:35:01 +00001099 mpz_need_dig(dest, dest->len + 1);
Damien George06201ff2014-03-01 19:50:50 +00001100 mpz_dig_t k = 1;
1101 dest->len = mpn_add(dest->dig, dest->dig, dest->len, &k, 1);
1102 dest->neg = 1;
1103 }
1104}
1105
Damien Georgec5ac2ac2014-02-26 16:56:30 +00001106/* computes dest = lhs << rhs
1107 can have dest, lhs the same
1108*/
Damien George2f4e8512015-10-01 18:01:37 +01001109void mpz_shl_inpl(mpz_t *dest, const mpz_t *lhs, mp_uint_t rhs) {
Damien George06201ff2014-03-01 19:50:50 +00001110 if (lhs->len == 0 || rhs == 0) {
Damien Georgec5ac2ac2014-02-26 16:56:30 +00001111 mpz_set(dest, lhs);
Damien Georgec5ac2ac2014-02-26 16:56:30 +00001112 } else {
Damien George06201ff2014-03-01 19:50:50 +00001113 mpz_need_dig(dest, lhs->len + (rhs + DIG_SIZE - 1) / DIG_SIZE);
1114 dest->len = mpn_shl(dest->dig, lhs->dig, lhs->len, rhs);
1115 dest->neg = lhs->neg;
Damien Georgec5ac2ac2014-02-26 16:56:30 +00001116 }
Damien Georgec5ac2ac2014-02-26 16:56:30 +00001117}
1118
1119/* computes dest = lhs >> rhs
1120 can have dest, lhs the same
1121*/
Damien George2f4e8512015-10-01 18:01:37 +01001122void mpz_shr_inpl(mpz_t *dest, const mpz_t *lhs, mp_uint_t rhs) {
Damien George06201ff2014-03-01 19:50:50 +00001123 if (lhs->len == 0 || rhs == 0) {
Damien Georgec5ac2ac2014-02-26 16:56:30 +00001124 mpz_set(dest, lhs);
Damien Georgec5ac2ac2014-02-26 16:56:30 +00001125 } else {
Damien George06201ff2014-03-01 19:50:50 +00001126 mpz_need_dig(dest, lhs->len);
1127 dest->len = mpn_shr(dest->dig, lhs->dig, lhs->len, rhs);
1128 dest->neg = lhs->neg;
1129 if (dest->neg) {
1130 // arithmetic shift right, rounding to negative infinity
Damien Georgeafb1cf72014-09-05 20:37:06 +01001131 mp_uint_t n_whole = rhs / DIG_SIZE;
1132 mp_uint_t n_part = rhs % DIG_SIZE;
Damien George06201ff2014-03-01 19:50:50 +00001133 mpz_dig_t round_up = 0;
Damien Georgeafb1cf72014-09-05 20:37:06 +01001134 for (mp_uint_t i = 0; i < lhs->len && i < n_whole; i++) {
Damien George06201ff2014-03-01 19:50:50 +00001135 if (lhs->dig[i] != 0) {
1136 round_up = 1;
1137 break;
1138 }
1139 }
1140 if (n_whole < lhs->len && (lhs->dig[n_whole] & ((1 << n_part) - 1)) != 0) {
1141 round_up = 1;
1142 }
1143 if (round_up) {
Damien Georgee0ac1942014-12-31 19:35:01 +00001144 if (dest->len == 0) {
1145 // dest == 0, so need to add 1 by hand (answer will be -1)
1146 dest->dig[0] = 1;
1147 dest->len = 1;
1148 } else {
1149 // dest > 0, so can use mpn_add to add 1
1150 dest->len = mpn_add(dest->dig, dest->dig, dest->len, &round_up, 1);
1151 }
Damien George06201ff2014-03-01 19:50:50 +00001152 }
1153 }
Damien Georgec5ac2ac2014-02-26 16:56:30 +00001154 }
Damien Georgec5ac2ac2014-02-26 16:56:30 +00001155}
Damien Georgec5ac2ac2014-02-26 16:56:30 +00001156
Damien George438c88d2014-02-22 19:25:23 +00001157/* computes dest = lhs + rhs
1158 can have dest, lhs, rhs the same
1159*/
1160void mpz_add_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
1161 if (mpn_cmp(lhs->dig, lhs->len, rhs->dig, rhs->len) < 0) {
1162 const mpz_t *temp = lhs;
1163 lhs = rhs;
1164 rhs = temp;
1165 }
1166
1167 if (lhs->neg == rhs->neg) {
1168 mpz_need_dig(dest, lhs->len + 1);
1169 dest->len = mpn_add(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
1170 } else {
1171 mpz_need_dig(dest, lhs->len);
1172 dest->len = mpn_sub(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
1173 }
1174
1175 dest->neg = lhs->neg;
1176}
1177
1178/* computes dest = lhs - rhs
1179 can have dest, lhs, rhs the same
1180*/
1181void mpz_sub_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
1182 bool neg = false;
1183
1184 if (mpn_cmp(lhs->dig, lhs->len, rhs->dig, rhs->len) < 0) {
1185 const mpz_t *temp = lhs;
1186 lhs = rhs;
1187 rhs = temp;
1188 neg = true;
1189 }
1190
1191 if (lhs->neg != rhs->neg) {
1192 mpz_need_dig(dest, lhs->len + 1);
1193 dest->len = mpn_add(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
1194 } else {
1195 mpz_need_dig(dest, lhs->len);
1196 dest->len = mpn_sub(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
1197 }
1198
1199 if (neg) {
1200 dest->neg = 1 - lhs->neg;
1201 } else {
1202 dest->neg = lhs->neg;
1203 }
1204}
1205
Paul Sokolovsky57207b82014-03-23 01:52:36 +02001206/* computes dest = lhs & rhs
1207 can have dest, lhs, rhs the same
1208*/
1209void mpz_and_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
Doug Currie2e2e15c2016-01-30 22:35:58 -05001210 // make sure lhs has the most digits
1211 if (lhs->len < rhs->len) {
1212 const mpz_t *temp = lhs;
1213 lhs = rhs;
1214 rhs = temp;
Paul Sokolovsky57207b82014-03-23 01:52:36 +02001215 }
Doug Currie2e2e15c2016-01-30 22:35:58 -05001216
1217 #if MICROPY_OPT_MPZ_BITWISE
1218
1219 if ((0 == lhs->neg) && (0 == rhs->neg)) {
1220 mpz_need_dig(dest, lhs->len);
1221 dest->len = mpn_and(dest->dig, lhs->dig, rhs->dig, rhs->len);
1222 dest->neg = 0;
1223 } else {
1224 mpz_need_dig(dest, lhs->len + 1);
1225 dest->len = mpn_and_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len,
1226 lhs->neg == rhs->neg, 0 != lhs->neg, 0 != rhs->neg);
1227 dest->neg = lhs->neg & rhs->neg;
1228 }
1229
1230 #else
1231
1232 mpz_need_dig(dest, lhs->len + (lhs->neg || rhs->neg));
1233 dest->len = mpn_and_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len,
1234 (lhs->neg == rhs->neg) ? lhs->neg : 0, lhs->neg, rhs->neg);
1235 dest->neg = lhs->neg & rhs->neg;
1236
1237 #endif
Paul Sokolovsky57207b82014-03-23 01:52:36 +02001238}
1239
1240/* computes dest = lhs | rhs
1241 can have dest, lhs, rhs the same
1242*/
1243void mpz_or_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
Doug Currie2e2e15c2016-01-30 22:35:58 -05001244 // make sure lhs has the most digits
1245 if (lhs->len < rhs->len) {
Paul Sokolovsky57207b82014-03-23 01:52:36 +02001246 const mpz_t *temp = lhs;
1247 lhs = rhs;
1248 rhs = temp;
1249 }
1250
Doug Currie2e2e15c2016-01-30 22:35:58 -05001251 #if MICROPY_OPT_MPZ_BITWISE
1252
1253 if ((0 == lhs->neg) && (0 == rhs->neg)) {
Paul Sokolovsky57207b82014-03-23 01:52:36 +02001254 mpz_need_dig(dest, lhs->len);
1255 dest->len = mpn_or(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
Doug Currie2e2e15c2016-01-30 22:35:58 -05001256 dest->neg = 0;
Paul Sokolovsky57207b82014-03-23 01:52:36 +02001257 } else {
Doug Currie2e2e15c2016-01-30 22:35:58 -05001258 mpz_need_dig(dest, lhs->len + 1);
1259 dest->len = mpn_or_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len,
1260 0 != lhs->neg, 0 != rhs->neg);
1261 dest->neg = 1;
Paul Sokolovsky57207b82014-03-23 01:52:36 +02001262 }
1263
Doug Currie2e2e15c2016-01-30 22:35:58 -05001264 #else
1265
1266 mpz_need_dig(dest, lhs->len + (lhs->neg || rhs->neg));
1267 dest->len = mpn_or_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len,
1268 (lhs->neg || rhs->neg), lhs->neg, rhs->neg);
1269 dest->neg = lhs->neg | rhs->neg;
1270
1271 #endif
Paul Sokolovsky57207b82014-03-23 01:52:36 +02001272}
1273
1274/* computes dest = lhs ^ rhs
1275 can have dest, lhs, rhs the same
1276*/
1277void mpz_xor_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
Doug Currie2e2e15c2016-01-30 22:35:58 -05001278 // make sure lhs has the most digits
1279 if (lhs->len < rhs->len) {
Paul Sokolovsky57207b82014-03-23 01:52:36 +02001280 const mpz_t *temp = lhs;
1281 lhs = rhs;
1282 rhs = temp;
1283 }
1284
Doug Currie2e2e15c2016-01-30 22:35:58 -05001285 #if MICROPY_OPT_MPZ_BITWISE
1286
Paul Sokolovsky57207b82014-03-23 01:52:36 +02001287 if (lhs->neg == rhs->neg) {
1288 mpz_need_dig(dest, lhs->len);
Doug Currie2e2e15c2016-01-30 22:35:58 -05001289 if (lhs->neg == 0) {
1290 dest->len = mpn_xor(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
1291 } else {
1292 dest->len = mpn_xor_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len, 0, 0, 0);
1293 }
1294 dest->neg = 0;
Paul Sokolovsky57207b82014-03-23 01:52:36 +02001295 } else {
Doug Currie2e2e15c2016-01-30 22:35:58 -05001296 mpz_need_dig(dest, lhs->len + 1);
1297 dest->len = mpn_xor_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len, 1,
1298 0 == lhs->neg, 0 == rhs->neg);
1299 dest->neg = 1;
Paul Sokolovsky57207b82014-03-23 01:52:36 +02001300 }
1301
Doug Currie2e2e15c2016-01-30 22:35:58 -05001302 #else
1303
1304 mpz_need_dig(dest, lhs->len + (lhs->neg || rhs->neg));
1305 dest->len = mpn_xor_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len,
1306 (lhs->neg != rhs->neg), 0 == lhs->neg, 0 == rhs->neg);
1307 dest->neg = lhs->neg ^ rhs->neg;
1308
1309 #endif
Paul Sokolovsky57207b82014-03-23 01:52:36 +02001310}
1311
Damien George438c88d2014-02-22 19:25:23 +00001312/* computes dest = lhs * rhs
1313 can have dest, lhs, rhs the same
1314*/
Damien George4dea9222015-04-09 15:29:54 +00001315void mpz_mul_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
Damien George438c88d2014-02-22 19:25:23 +00001316 if (lhs->len == 0 || rhs->len == 0) {
Damien Georgec5ac2ac2014-02-26 16:56:30 +00001317 mpz_set_from_int(dest, 0);
1318 return;
Damien George438c88d2014-02-22 19:25:23 +00001319 }
1320
1321 mpz_t *temp = NULL;
1322 if (lhs == dest) {
1323 lhs = temp = mpz_clone(lhs);
1324 if (rhs == dest) {
1325 rhs = lhs;
1326 }
1327 } else if (rhs == dest) {
1328 rhs = temp = mpz_clone(rhs);
1329 }
1330
1331 mpz_need_dig(dest, lhs->len + rhs->len); // min mem l+r-1, max mem l+r
1332 memset(dest->dig, 0, dest->alloc * sizeof(mpz_dig_t));
1333 dest->len = mpn_mul(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
1334
1335 if (lhs->neg == rhs->neg) {
1336 dest->neg = 0;
1337 } else {
1338 dest->neg = 1;
1339 }
1340
1341 mpz_free(temp);
1342}
1343
1344/* computes dest = lhs ** rhs
1345 can have dest, lhs, rhs the same
1346*/
1347void mpz_pow_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
1348 if (lhs->len == 0 || rhs->neg != 0) {
Damien Georgec5ac2ac2014-02-26 16:56:30 +00001349 mpz_set_from_int(dest, 0);
1350 return;
Damien George438c88d2014-02-22 19:25:23 +00001351 }
1352
1353 if (rhs->len == 0) {
Damien Georgec5ac2ac2014-02-26 16:56:30 +00001354 mpz_set_from_int(dest, 1);
1355 return;
Damien George438c88d2014-02-22 19:25:23 +00001356 }
1357
1358 mpz_t *x = mpz_clone(lhs);
1359 mpz_t *n = mpz_clone(rhs);
1360
1361 mpz_set_from_int(dest, 1);
1362
1363 while (n->len > 0) {
Damien Georgea2e38382015-03-02 12:58:06 +00001364 if ((n->dig[0] & 1) != 0) {
Damien George438c88d2014-02-22 19:25:23 +00001365 mpz_mul_inpl(dest, dest, x);
1366 }
Damien George438c88d2014-02-22 19:25:23 +00001367 n->len = mpn_shr(n->dig, n->dig, n->len, 1);
Damien George5bf565e2014-04-04 00:16:32 +01001368 if (n->len == 0) {
1369 break;
1370 }
1371 mpz_mul_inpl(x, x, x);
Damien George438c88d2014-02-22 19:25:23 +00001372 }
1373
1374 mpz_free(x);
1375 mpz_free(n);
1376}
1377
Damien Georgea2e38382015-03-02 12:58:06 +00001378#if 0
1379these functions are unused
1380
Damien Georgeff1a96c2016-02-03 22:30:49 +00001381/* computes dest = (lhs ** rhs) % mod
1382 can have dest, lhs, rhs the same; mod can't be the same as dest
1383*/
1384void mpz_pow3_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs, const mpz_t *mod) {
1385 if (lhs->len == 0 || rhs->neg != 0) {
1386 mpz_set_from_int(dest, 0);
1387 return;
1388 }
1389
1390 if (rhs->len == 0) {
1391 mpz_set_from_int(dest, 1);
1392 return;
1393 }
1394
1395 mpz_t *x = mpz_clone(lhs);
1396 mpz_t *n = mpz_clone(rhs);
1397 mpz_t quo; mpz_init_zero(&quo);
1398
1399 mpz_set_from_int(dest, 1);
1400
1401 while (n->len > 0) {
1402 if ((n->dig[0] & 1) != 0) {
1403 mpz_mul_inpl(dest, dest, x);
1404 mpz_divmod_inpl(&quo, dest, dest, mod);
1405 }
1406 n->len = mpn_shr(n->dig, n->dig, n->len, 1);
1407 if (n->len == 0) {
1408 break;
1409 }
1410 mpz_mul_inpl(x, x, x);
1411 mpz_divmod_inpl(&quo, x, x, mod);
1412 }
1413
1414 mpz_deinit(&quo);
1415 mpz_free(x);
1416 mpz_free(n);
1417}
1418
Damien George438c88d2014-02-22 19:25:23 +00001419/* computes gcd(z1, z2)
1420 based on Knuth's modified gcd algorithm (I think?)
1421 gcd(z1, z2) >= 0
1422 gcd(0, 0) = 0
1423 gcd(z, 0) = abs(z)
1424*/
1425mpz_t *mpz_gcd(const mpz_t *z1, const mpz_t *z2) {
1426 if (z1->len == 0) {
1427 mpz_t *a = mpz_clone(z2);
1428 a->neg = 0;
1429 return a;
1430 } else if (z2->len == 0) {
1431 mpz_t *a = mpz_clone(z1);
1432 a->neg = 0;
1433 return a;
1434 }
1435
1436 mpz_t *a = mpz_clone(z1);
1437 mpz_t *b = mpz_clone(z2);
1438 mpz_t c; mpz_init_zero(&c);
1439 a->neg = 0;
1440 b->neg = 0;
1441
1442 for (;;) {
1443 if (mpz_cmp(a, b) < 0) {
1444 if (a->len == 0) {
1445 mpz_free(a);
1446 mpz_deinit(&c);
1447 return b;
1448 }
1449 mpz_t *t = a; a = b; b = t;
1450 }
1451 if (!(b->len >= 2 || (b->len == 1 && b->dig[0] > 1))) { // compute b > 0; could be mpz_cmp_small_int(b, 1) > 0
1452 break;
1453 }
1454 mpz_set(&c, b);
1455 do {
1456 mpz_add_inpl(&c, &c, &c);
1457 } while (mpz_cmp(&c, a) <= 0);
1458 c.len = mpn_shr(c.dig, c.dig, c.len, 1);
1459 mpz_sub_inpl(a, a, &c);
1460 }
1461
1462 mpz_deinit(&c);
1463
1464 if (b->len == 1 && b->dig[0] == 1) { // compute b == 1; could be mpz_cmp_small_int(b, 1) == 0
1465 mpz_free(a);
1466 return b;
1467 } else {
1468 mpz_free(b);
1469 return a;
1470 }
1471}
1472
1473/* computes lcm(z1, z2)
1474 = abs(z1) / gcd(z1, z2) * abs(z2)
1475 lcm(z1, z1) >= 0
1476 lcm(0, 0) = 0
1477 lcm(z, 0) = 0
1478*/
Damien George5d9b8162014-08-07 14:27:48 +00001479mpz_t *mpz_lcm(const mpz_t *z1, const mpz_t *z2) {
1480 if (z1->len == 0 || z2->len == 0) {
1481 return mpz_zero();
stijn01d6be42014-05-05 12:18:27 +02001482 }
Damien George438c88d2014-02-22 19:25:23 +00001483
1484 mpz_t *gcd = mpz_gcd(z1, z2);
1485 mpz_t *quo = mpz_zero();
1486 mpz_t *rem = mpz_zero();
1487 mpz_divmod_inpl(quo, rem, z1, gcd);
1488 mpz_mul_inpl(rem, quo, z2);
1489 mpz_free(gcd);
1490 mpz_free(quo);
1491 rem->neg = 0;
1492 return rem;
1493}
Damien Georgea2e38382015-03-02 12:58:06 +00001494#endif
Damien George438c88d2014-02-22 19:25:23 +00001495
1496/* computes new integers in quo and rem such that:
1497 quo * rhs + rem = lhs
1498 0 <= rem < rhs
1499 can have lhs, rhs the same
1500*/
1501void mpz_divmod_inpl(mpz_t *dest_quo, mpz_t *dest_rem, const mpz_t *lhs, const mpz_t *rhs) {
1502 if (rhs->len == 0) {
1503 mpz_set_from_int(dest_quo, 0);
1504 mpz_set_from_int(dest_rem, 0);
1505 return;
1506 }
1507
1508 mpz_need_dig(dest_quo, lhs->len + 1); // +1 necessary?
1509 memset(dest_quo->dig, 0, (lhs->len + 1) * sizeof(mpz_dig_t));
1510 dest_quo->len = 0;
1511 mpz_need_dig(dest_rem, lhs->len + 1); // +1 necessary?
1512 mpz_set(dest_rem, lhs);
Damien George438c88d2014-02-22 19:25:23 +00001513 mpn_div(dest_rem->dig, &dest_rem->len, rhs->dig, rhs->len, dest_quo->dig, &dest_quo->len);
1514
Damien George65402ab2016-05-08 22:21:21 +01001515 // check signs and do Python style modulo
Damien George438c88d2014-02-22 19:25:23 +00001516 if (lhs->neg != rhs->neg) {
1517 dest_quo->neg = 1;
Damien George65402ab2016-05-08 22:21:21 +01001518 if (!mpz_is_zero(dest_rem)) {
1519 mpz_t mpzone; mpz_init_from_int(&mpzone, -1);
1520 mpz_add_inpl(dest_quo, dest_quo, &mpzone);
1521 mpz_add_inpl(dest_rem, dest_rem, rhs);
1522 }
Damien George438c88d2014-02-22 19:25:23 +00001523 }
1524}
1525
1526#if 0
1527these functions are unused
1528
1529/* computes floor(lhs / rhs)
1530 can have lhs, rhs the same
1531*/
1532mpz_t *mpz_div(const mpz_t *lhs, const mpz_t *rhs) {
1533 mpz_t *quo = mpz_zero();
1534 mpz_t rem; mpz_init_zero(&rem);
1535 mpz_divmod_inpl(quo, &rem, lhs, rhs);
1536 mpz_deinit(&rem);
1537 return quo;
1538}
1539
1540/* computes lhs % rhs ( >= 0)
1541 can have lhs, rhs the same
1542*/
1543mpz_t *mpz_mod(const mpz_t *lhs, const mpz_t *rhs) {
1544 mpz_t quo; mpz_init_zero(&quo);
1545 mpz_t *rem = mpz_zero();
1546 mpz_divmod_inpl(&quo, rem, lhs, rhs);
1547 mpz_deinit(&quo);
1548 return rem;
1549}
1550#endif
1551
Damien Georgeffe911d2014-07-24 14:21:37 +01001552// must return actual int value if it fits in mp_int_t
1553mp_int_t mpz_hash(const mpz_t *z) {
1554 mp_int_t val = 0;
1555 mpz_dig_t *d = z->dig + z->len;
1556
Damien George58056b02015-01-09 20:58:58 +00001557 while (d-- > z->dig) {
Damien Georgeffe911d2014-07-24 14:21:37 +01001558 val = (val << DIG_SIZE) | *d;
1559 }
1560
1561 if (z->neg != 0) {
1562 val = -val;
1563 }
1564
1565 return val;
1566}
1567
Damien George40f3c022014-07-03 13:25:24 +01001568bool mpz_as_int_checked(const mpz_t *i, mp_int_t *value) {
Damien George963a5a32015-01-16 17:47:07 +00001569 mp_uint_t val = 0;
Damien George8270e382014-04-03 11:00:54 +00001570 mpz_dig_t *d = i->dig + i->len;
1571
Damien George58056b02015-01-09 20:58:58 +00001572 while (d-- > i->dig) {
Damien Georgec9aa58e2014-07-31 13:41:43 +00001573 if (val > (~(WORD_MSBIT_HIGH) >> DIG_SIZE)) {
1574 // will overflow
Damien George8270e382014-04-03 11:00:54 +00001575 return false;
1576 }
Damien Georgec9aa58e2014-07-31 13:41:43 +00001577 val = (val << DIG_SIZE) | *d;
Damien George8270e382014-04-03 11:00:54 +00001578 }
1579
1580 if (i->neg != 0) {
1581 val = -val;
1582 }
1583
1584 *value = val;
1585 return true;
1586}
1587
Damien Georgec9aa58e2014-07-31 13:41:43 +00001588bool mpz_as_uint_checked(const mpz_t *i, mp_uint_t *value) {
1589 if (i->neg != 0) {
1590 // can't represent signed values
1591 return false;
1592 }
1593
1594 mp_uint_t val = 0;
1595 mpz_dig_t *d = i->dig + i->len;
1596
Damien George58056b02015-01-09 20:58:58 +00001597 while (d-- > i->dig) {
Damien George9a21d2e2014-09-06 17:15:34 +01001598 if (val > (~(WORD_MSBIT_HIGH) >> (DIG_SIZE - 1))) {
Damien Georgec9aa58e2014-07-31 13:41:43 +00001599 // will overflow
1600 return false;
1601 }
1602 val = (val << DIG_SIZE) | *d;
1603 }
1604
1605 *value = val;
1606 return true;
1607}
1608
Damien George271d18e2015-04-25 23:16:39 +01001609// writes at most len bytes to buf (so buf should be zeroed before calling)
1610void mpz_as_bytes(const mpz_t *z, bool big_endian, mp_uint_t len, byte *buf) {
1611 byte *b = buf;
1612 if (big_endian) {
1613 b += len;
1614 }
1615 mpz_dig_t *zdig = z->dig;
1616 int bits = 0;
1617 mpz_dbl_dig_t d = 0;
1618 mpz_dbl_dig_t carry = 1;
1619 for (mp_uint_t zlen = z->len; zlen > 0; --zlen) {
1620 bits += DIG_SIZE;
1621 d = (d << DIG_SIZE) | *zdig++;
1622 for (; bits >= 8; bits -= 8, d >>= 8) {
1623 mpz_dig_t val = d;
1624 if (z->neg) {
Damien George94729072015-04-25 23:51:14 +01001625 val = (~val & 0xff) + carry;
1626 carry = val >> 8;
Damien George271d18e2015-04-25 23:16:39 +01001627 }
1628 if (big_endian) {
1629 *--b = val;
1630 if (b == buf) {
1631 return;
1632 }
1633 } else {
1634 *b++ = val;
1635 if (b == buf + len) {
1636 return;
1637 }
1638 }
1639 }
1640 }
1641}
1642
Damien Georgefb510b32014-06-01 13:32:54 +01001643#if MICROPY_PY_BUILTINS_FLOAT
Damien George52608102014-03-08 15:04:54 +00001644mp_float_t mpz_as_float(const mpz_t *i) {
1645 mp_float_t val = 0;
Damien George438c88d2014-02-22 19:25:23 +00001646 mpz_dig_t *d = i->dig + i->len;
1647
Damien George58056b02015-01-09 20:58:58 +00001648 while (d-- > i->dig) {
Damien George9a21d2e2014-09-06 17:15:34 +01001649 val = val * DIG_BASE + *d;
Damien George438c88d2014-02-22 19:25:23 +00001650 }
1651
1652 if (i->neg != 0) {
1653 val = -val;
1654 }
1655
1656 return val;
1657}
Damien George52608102014-03-08 15:04:54 +00001658#endif
Damien George438c88d2014-02-22 19:25:23 +00001659
Damien Georgeafb1cf72014-09-05 20:37:06 +01001660mp_uint_t mpz_as_str_size(const mpz_t *i, mp_uint_t base, const char *prefix, char comma) {
Damien George438c88d2014-02-22 19:25:23 +00001661 if (base < 2 || base > 32) {
1662 return 0;
1663 }
1664
Damien Georgeafb1cf72014-09-05 20:37:06 +01001665 mp_uint_t num_digits = i->len * DIG_SIZE / log_base2_floor[base] + 1;
1666 mp_uint_t num_commas = comma ? num_digits / 3: 0;
1667 mp_uint_t prefix_len = prefix ? strlen(prefix) : 0;
Dave Hylandsc4029e52014-04-07 11:19:51 -07001668
1669 return num_digits + num_commas + prefix_len + 2; // +1 for sign, +1 for null byte
1670}
1671
Damien Georgeafb1cf72014-09-05 20:37:06 +01001672#if 0
1673this function is unused
1674char *mpz_as_str(const mpz_t *i, mp_uint_t base) {
1675 char *s = m_new(char, mpz_as_str_size(i, base, NULL, '\0'));
1676 mpz_as_str_inpl(i, base, NULL, 'a', '\0', s);
Damien George438c88d2014-02-22 19:25:23 +00001677 return s;
1678}
Damien Georgeafb1cf72014-09-05 20:37:06 +01001679#endif
Damien George438c88d2014-02-22 19:25:23 +00001680
1681// assumes enough space as calculated by mpz_as_str_size
1682// returns length of string, not including null byte
Damien Georgeafb1cf72014-09-05 20:37:06 +01001683mp_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 +00001684 if (str == NULL || base < 2 || base > 32) {
1685 str[0] = 0;
1686 return 0;
1687 }
1688
Damien Georgeafb1cf72014-09-05 20:37:06 +01001689 mp_uint_t ilen = i->len;
Damien George438c88d2014-02-22 19:25:23 +00001690
Dave Hylandsc4029e52014-04-07 11:19:51 -07001691 char *s = str;
Damien George438c88d2014-02-22 19:25:23 +00001692 if (ilen == 0) {
Dave Hylandsc4029e52014-04-07 11:19:51 -07001693 if (prefix) {
1694 while (*prefix)
1695 *s++ = *prefix++;
1696 }
1697 *s++ = '0';
1698 *s = '\0';
1699 return s - str;
Damien George438c88d2014-02-22 19:25:23 +00001700 }
1701
Damien Georgeeec91052014-04-08 23:11:00 +01001702 // make a copy of mpz digits, so we can do the div/mod calculation
Damien George438c88d2014-02-22 19:25:23 +00001703 mpz_dig_t *dig = m_new(mpz_dig_t, ilen);
1704 memcpy(dig, i->dig, ilen * sizeof(mpz_dig_t));
1705
1706 // convert
Dave Hylandsc4029e52014-04-07 11:19:51 -07001707 char *last_comma = str;
Damien George438c88d2014-02-22 19:25:23 +00001708 bool done;
1709 do {
1710 mpz_dig_t *d = dig + ilen;
1711 mpz_dbl_dig_t a = 0;
1712
1713 // compute next remainder
1714 while (--d >= dig) {
1715 a = (a << DIG_SIZE) | *d;
1716 *d = a / base;
1717 a %= base;
1718 }
1719
1720 // convert to character
1721 a += '0';
1722 if (a > '9') {
Dave Hylandsc4029e52014-04-07 11:19:51 -07001723 a += base_char - '9' - 1;
Damien George438c88d2014-02-22 19:25:23 +00001724 }
1725 *s++ = a;
1726
1727 // check if number is zero
1728 done = true;
1729 for (d = dig; d < dig + ilen; ++d) {
1730 if (*d != 0) {
1731 done = false;
1732 break;
1733 }
1734 }
Dave Hylandsc4029e52014-04-07 11:19:51 -07001735 if (comma && (s - last_comma) == 3) {
1736 *s++ = comma;
1737 last_comma = s;
1738 }
1739 }
1740 while (!done);
Damien George438c88d2014-02-22 19:25:23 +00001741
Damien Georgeeec91052014-04-08 23:11:00 +01001742 // free the copy of the digits array
1743 m_del(mpz_dig_t, dig, ilen);
1744
Dave Hylandsc4029e52014-04-07 11:19:51 -07001745 if (prefix) {
1746 const char *p = &prefix[strlen(prefix)];
1747 while (p > prefix) {
1748 *s++ = *--p;
1749 }
1750 }
Damien George438c88d2014-02-22 19:25:23 +00001751 if (i->neg != 0) {
1752 *s++ = '-';
1753 }
1754
1755 // reverse string
1756 for (char *u = str, *v = s - 1; u < v; ++u, --v) {
1757 char temp = *u;
1758 *u = *v;
1759 *v = temp;
1760 }
1761
Dave Hylandsc4029e52014-04-07 11:19:51 -07001762 *s = '\0'; // null termination
Damien George438c88d2014-02-22 19:25:23 +00001763
1764 return s - str;
1765}
1766
1767#endif // MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_MPZ