blob: 8e6aecbcae34a3e3a17f3186d70d8e7bc0f1a06e [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 <stdint.h>
28#include <stdbool.h>
29#include <stdlib.h>
30#include <string.h>
31#include <assert.h>
32
Damien George438c88d2014-02-22 19:25:23 +000033#include "mpconfig.h"
Paul Sokolovsky59c675a2014-06-21 22:43:22 +030034#include "misc.h"
Damien George438c88d2014-02-22 19:25:23 +000035#include "mpz.h"
36
37#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_MPZ
38
Damien George06201ff2014-03-01 19:50:50 +000039#define DIG_SIZE (MPZ_DIG_SIZE)
Damien George438c88d2014-02-22 19:25:23 +000040#define DIG_MASK ((1 << DIG_SIZE) - 1)
41
42/*
Damien George06201ff2014-03-01 19:50:50 +000043 mpz is an arbitrary precision integer type with a public API.
44
45 mpn functions act on non-negative integers represented by an array of generalised
46 digits (eg a word per digit). You also need to specify separately the length of the
47 array. There is no public API for mpn. Rather, the functions are used by mpz to
48 implement its features.
49
50 Integer values are stored little endian (first digit is first in memory).
51
52 Definition of normalise: ?
Damien George438c88d2014-02-22 19:25:23 +000053*/
54
55/* compares i with j
56 returns sign(i - j)
57 assumes i, j are normalised
58*/
Damien Georgeafb1cf72014-09-05 20:37:06 +010059STATIC mp_int_t 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 +000060 if (ilen < jlen) { return -1; }
61 if (ilen > jlen) { return 1; }
62
63 for (idig += ilen, jdig += ilen; ilen > 0; --ilen) {
Damien Georgeafb1cf72014-09-05 20:37:06 +010064 mp_int_t cmp = *(--idig) - *(--jdig);
Damien George438c88d2014-02-22 19:25:23 +000065 if (cmp < 0) { return -1; }
66 if (cmp > 0) { return 1; }
67 }
68
69 return 0;
70}
71
Damien Georgec5ac2ac2014-02-26 16:56:30 +000072/* computes i = j << n
73 returns number of digits in i
Damien George06201ff2014-03-01 19:50:50 +000074 assumes enough memory in i; assumes normalised j; assumes n > 0
Damien Georgec5ac2ac2014-02-26 16:56:30 +000075 can have i, j pointing to same memory
76*/
Damien Georgeafb1cf72014-09-05 20:37:06 +010077STATIC mp_uint_t mpn_shl(mpz_dig_t *idig, mpz_dig_t *jdig, mp_uint_t jlen, mp_uint_t n) {
78 mp_uint_t n_whole = (n + DIG_SIZE - 1) / DIG_SIZE;
79 mp_uint_t n_part = n % DIG_SIZE;
Damien Georgebb4a43f2014-03-12 15:36:06 +000080 if (n_part == 0) {
81 n_part = DIG_SIZE;
82 }
Damien Georgec5ac2ac2014-02-26 16:56:30 +000083
Damien George06201ff2014-03-01 19:50:50 +000084 // start from the high end of the digit arrays
85 idig += jlen + n_whole - 1;
86 jdig += jlen - 1;
Damien Georgec5ac2ac2014-02-26 16:56:30 +000087
Damien George06201ff2014-03-01 19:50:50 +000088 // shift the digits
89 mpz_dbl_dig_t d = 0;
Damien Georgeafb1cf72014-09-05 20:37:06 +010090 for (mp_uint_t i = jlen; i > 0; i--, idig--, jdig--) {
Damien George06201ff2014-03-01 19:50:50 +000091 d |= *jdig;
Damien George5d9b8162014-08-07 14:27:48 +000092 *idig = (d >> (DIG_SIZE - n_part)) & DIG_MASK;
Damien George06201ff2014-03-01 19:50:50 +000093 d <<= DIG_SIZE;
Damien Georgec5ac2ac2014-02-26 16:56:30 +000094 }
95
Damien George06201ff2014-03-01 19:50:50 +000096 // store remaining bits
Damien George5d9b8162014-08-07 14:27:48 +000097 *idig = (d >> (DIG_SIZE - n_part)) & DIG_MASK;
Damien George06201ff2014-03-01 19:50:50 +000098 idig -= n_whole - 1;
Damien Georgebb4a43f2014-03-12 15:36:06 +000099 memset(idig, 0, (n_whole - 1) * sizeof(mpz_dig_t));
Damien George06201ff2014-03-01 19:50:50 +0000100
101 // work out length of result
102 jlen += n_whole;
103 if (idig[jlen - 1] == 0) {
104 jlen--;
Damien Georgec5ac2ac2014-02-26 16:56:30 +0000105 }
106
Damien George06201ff2014-03-01 19:50:50 +0000107 // return length of result
Damien Georgec5ac2ac2014-02-26 16:56:30 +0000108 return jlen;
109}
Damien Georgec5ac2ac2014-02-26 16:56:30 +0000110
Damien George438c88d2014-02-22 19:25:23 +0000111/* computes i = j >> n
112 returns number of digits in i
Damien George06201ff2014-03-01 19:50:50 +0000113 assumes enough memory in i; assumes normalised j; assumes n > 0
Damien George438c88d2014-02-22 19:25:23 +0000114 can have i, j pointing to same memory
115*/
Damien Georgeafb1cf72014-09-05 20:37:06 +0100116STATIC mp_uint_t mpn_shr(mpz_dig_t *idig, mpz_dig_t *jdig, mp_uint_t jlen, mp_uint_t n) {
117 mp_uint_t n_whole = n / DIG_SIZE;
118 mp_uint_t n_part = n % DIG_SIZE;
Damien George438c88d2014-02-22 19:25:23 +0000119
120 if (n_whole >= jlen) {
121 return 0;
122 }
123
124 jdig += n_whole;
125 jlen -= n_whole;
126
Damien Georgeafb1cf72014-09-05 20:37:06 +0100127 for (mp_uint_t i = jlen; i > 0; i--, idig++, jdig++) {
Damien George438c88d2014-02-22 19:25:23 +0000128 mpz_dbl_dig_t d = *jdig;
Damien Georgec5ac2ac2014-02-26 16:56:30 +0000129 if (i > 1) {
Damien George438c88d2014-02-22 19:25:23 +0000130 d |= jdig[1] << DIG_SIZE;
Damien Georgec5ac2ac2014-02-26 16:56:30 +0000131 }
Damien George438c88d2014-02-22 19:25:23 +0000132 d >>= n_part;
133 *idig = d & DIG_MASK;
134 }
135
136 if (idig[-1] == 0) {
Damien George06201ff2014-03-01 19:50:50 +0000137 jlen--;
Damien George438c88d2014-02-22 19:25:23 +0000138 }
139
140 return jlen;
141}
142
143/* computes i = j + k
144 returns number of digits in i
145 assumes enough memory in i; assumes normalised j, k; assumes jlen >= klen
146 can have i, j, k pointing to same memory
147*/
Damien Georgeafb1cf72014-09-05 20:37:06 +0100148STATIC 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 +0000149 mpz_dig_t *oidig = idig;
150 mpz_dbl_dig_t carry = 0;
151
152 jlen -= klen;
153
154 for (; klen > 0; --klen, ++idig, ++jdig, ++kdig) {
155 carry += *jdig + *kdig;
156 *idig = carry & DIG_MASK;
157 carry >>= DIG_SIZE;
158 }
159
160 for (; jlen > 0; --jlen, ++idig, ++jdig) {
161 carry += *jdig;
162 *idig = carry & DIG_MASK;
163 carry >>= DIG_SIZE;
164 }
165
166 if (carry != 0) {
167 *idig++ = carry;
168 }
169
170 return idig - oidig;
171}
172
173/* computes i = j - k
174 returns number of digits in i
175 assumes enough memory in i; assumes normalised j, k; assumes j >= k
176 can have i, j, k pointing to same memory
177*/
Damien Georgeafb1cf72014-09-05 20:37:06 +0100178STATIC 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 +0000179 mpz_dig_t *oidig = idig;
180 mpz_dbl_dig_signed_t borrow = 0;
181
182 jlen -= klen;
183
184 for (; klen > 0; --klen, ++idig, ++jdig, ++kdig) {
185 borrow += *jdig - *kdig;
186 *idig = borrow & DIG_MASK;
187 borrow >>= DIG_SIZE;
188 }
189
Damien Georgeaca14122014-02-24 21:32:52 +0000190 for (; jlen > 0; --jlen, ++idig, ++jdig) {
Damien George438c88d2014-02-22 19:25:23 +0000191 borrow += *jdig;
192 *idig = borrow & DIG_MASK;
193 borrow >>= DIG_SIZE;
194 }
195
196 for (--idig; idig >= oidig && *idig == 0; --idig) {
197 }
198
199 return idig + 1 - oidig;
200}
201
Paul Sokolovsky57207b82014-03-23 01:52:36 +0200202/* computes i = j & k
203 returns number of digits in i
204 assumes enough memory in i; assumes normalised j, k; assumes jlen >= klen
205 can have i, j, k pointing to same memory
206*/
Damien Georgeafb1cf72014-09-05 20:37:06 +0100207STATIC mp_uint_t mpn_and(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 +0200208 mpz_dig_t *oidig = idig;
209
Paul Sokolovsky57207b82014-03-23 01:52:36 +0200210 for (; klen > 0; --klen, ++idig, ++jdig, ++kdig) {
211 *idig = *jdig & *kdig;
212 }
213
Damien George561e4252014-05-12 23:27:29 +0100214 // remove trailing zeros
Damien George51fab282014-05-13 22:58:00 +0100215 for (--idig; idig >= oidig && *idig == 0; --idig) {
Paul Sokolovsky57207b82014-03-23 01:52:36 +0200216 }
217
Damien George51fab282014-05-13 22:58:00 +0100218 return idig + 1 - oidig;
Paul Sokolovsky57207b82014-03-23 01:52:36 +0200219}
220
Damien Georgef55cf102014-05-29 15:01:49 +0100221/* computes i = j & -k = j & (~k + 1)
222 returns number of digits in i
223 assumes enough memory in i; assumes normalised j, k
224 can have i, j, k pointing to same memory
225*/
Damien Georgeafb1cf72014-09-05 20:37:06 +0100226STATIC 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) {
Damien Georgef55cf102014-05-29 15:01:49 +0100227 mpz_dig_t *oidig = idig;
228 mpz_dbl_dig_t carry = 1;
229
230 for (; jlen > 0 && klen > 0; --jlen, --klen, ++idig, ++jdig, ++kdig) {
231 carry += *kdig ^ DIG_MASK;
232 *idig = (*jdig & carry) & DIG_MASK;
233 carry >>= DIG_SIZE;
234 }
235
236 for (; jlen > 0; --jlen, ++idig, ++jdig) {
237 carry += DIG_MASK;
238 *idig = (*jdig & carry) & DIG_MASK;
239 carry >>= DIG_SIZE;
240 }
241
242 if (carry != 0) {
243 *idig = carry;
244 } else {
245 // remove trailing zeros
246 for (--idig; idig >= oidig && *idig == 0; --idig) {
247 }
248 }
249
250 return idig + 1 - oidig;
251}
252
Paul Sokolovsky57207b82014-03-23 01:52:36 +0200253/* computes i = j | k
254 returns number of digits in i
255 assumes enough memory in i; assumes normalised j, k; assumes jlen >= klen
256 can have i, j, k pointing to same memory
257*/
Damien Georgeafb1cf72014-09-05 20:37:06 +0100258STATIC 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 +0200259 mpz_dig_t *oidig = idig;
260
261 jlen -= klen;
262
263 for (; klen > 0; --klen, ++idig, ++jdig, ++kdig) {
264 *idig = *jdig | *kdig;
265 }
266
267 for (; jlen > 0; --jlen, ++idig, ++jdig) {
268 *idig = *jdig;
269 }
270
271 return idig - oidig;
272}
273
274/* computes i = j ^ k
275 returns number of digits in i
276 assumes enough memory in i; assumes normalised j, k; assumes jlen >= klen
277 can have i, j, k pointing to same memory
278*/
Damien Georgeafb1cf72014-09-05 20:37:06 +0100279STATIC 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 +0200280 mpz_dig_t *oidig = idig;
281
282 jlen -= klen;
283
284 for (; klen > 0; --klen, ++idig, ++jdig, ++kdig) {
285 *idig = *jdig ^ *kdig;
286 }
287
288 for (; jlen > 0; --jlen, ++idig, ++jdig) {
289 *idig = *jdig;
290 }
291
292 return idig - oidig;
293}
294
Damien George438c88d2014-02-22 19:25:23 +0000295/* computes i = i * d1 + d2
296 returns number of digits in i
297 assumes enough memory in i; assumes normalised i; assumes dmul != 0
298*/
Damien Georgeafb1cf72014-09-05 20:37:06 +0100299STATIC 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 +0000300 mpz_dig_t *oidig = idig;
301 mpz_dbl_dig_t carry = dadd;
302
303 for (; ilen > 0; --ilen, ++idig) {
304 carry += *idig * dmul; // will never overflow so long as DIG_SIZE <= WORD_SIZE / 2
305 *idig = carry & DIG_MASK;
306 carry >>= DIG_SIZE;
307 }
308
309 if (carry != 0) {
310 *idig++ = carry;
311 }
312
313 return idig - oidig;
314}
315
316/* computes i = j * k
317 returns number of digits in i
318 assumes enough memory in i; assumes i is zeroed; assumes normalised j, k
319 can have j, k point to same memory
320*/
Damien Georgeafb1cf72014-09-05 20:37:06 +0100321STATIC 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 +0000322 mpz_dig_t *oidig = idig;
Damien Georgeafb1cf72014-09-05 20:37:06 +0100323 mp_uint_t ilen = 0;
Damien George438c88d2014-02-22 19:25:23 +0000324
325 for (; klen > 0; --klen, ++idig, ++kdig) {
326 mpz_dig_t *id = idig;
327 mpz_dbl_dig_t carry = 0;
328
Damien Georgeafb1cf72014-09-05 20:37:06 +0100329 mp_uint_t jl = jlen;
Damien George438c88d2014-02-22 19:25:23 +0000330 for (mpz_dig_t *jd = jdig; jl > 0; --jl, ++jd, ++id) {
331 carry += *id + *jd * *kdig; // will never overflow so long as DIG_SIZE <= WORD_SIZE / 2
332 *id = carry & DIG_MASK;
333 carry >>= DIG_SIZE;
334 }
335
336 if (carry != 0) {
337 *id++ = carry;
338 }
339
340 ilen = id - oidig;
341 }
342
343 return ilen;
344}
345
346/* natural_div - quo * den + new_num = old_num (ie num is replaced with rem)
347 assumes den != 0
348 assumes num_dig has enough memory to be extended by 1 digit
349 assumes quo_dig has enough memory (as many digits as num)
350 assumes quo_dig is filled with zeros
351 modifies den_dig memory, but restors it to original state at end
352*/
353
Damien George40f3c022014-07-03 13:25:24 +0100354STATIC void mpn_div(mpz_dig_t *num_dig, mp_uint_t *num_len, mpz_dig_t *den_dig, mp_uint_t den_len, mpz_dig_t *quo_dig, mp_uint_t *quo_len) {
Damien George438c88d2014-02-22 19:25:23 +0000355 mpz_dig_t *orig_num_dig = num_dig;
356 mpz_dig_t *orig_quo_dig = quo_dig;
357 mpz_dig_t norm_shift = 0;
358 mpz_dbl_dig_t lead_den_digit;
359
360 // handle simple cases
361 {
Damien Georgeafb1cf72014-09-05 20:37:06 +0100362 mp_int_t cmp = mpn_cmp(num_dig, *num_len, den_dig, den_len);
Damien George438c88d2014-02-22 19:25:23 +0000363 if (cmp == 0) {
364 *num_len = 0;
365 quo_dig[0] = 1;
366 *quo_len = 1;
367 return;
368 } else if (cmp < 0) {
369 // numerator remains the same
370 *quo_len = 0;
371 return;
372 }
373 }
374
375 // count number of leading zeros in leading digit of denominator
376 {
377 mpz_dig_t d = den_dig[den_len - 1];
378 while ((d & (1 << (DIG_SIZE - 1))) == 0) {
379 d <<= 1;
380 ++norm_shift;
381 }
382 }
383
384 // normalise denomenator (leading bit of leading digit is 1)
385 for (mpz_dig_t *den = den_dig, carry = 0; den < den_dig + den_len; ++den) {
386 mpz_dig_t d = *den;
387 *den = ((d << norm_shift) | carry) & DIG_MASK;
388 carry = d >> (DIG_SIZE - norm_shift);
389 }
390
391 // now need to shift numerator by same amount as denominator
392 // first, increase length of numerator in case we need more room to shift
393 num_dig[*num_len] = 0;
394 ++(*num_len);
395 for (mpz_dig_t *num = num_dig, carry = 0; num < num_dig + *num_len; ++num) {
396 mpz_dig_t n = *num;
397 *num = ((n << norm_shift) | carry) & DIG_MASK;
398 carry = n >> (DIG_SIZE - norm_shift);
399 }
400
401 // cache the leading digit of the denominator
402 lead_den_digit = den_dig[den_len - 1];
403
404 // point num_dig to last digit in numerator
405 num_dig += *num_len - 1;
406
407 // calculate number of digits in quotient
408 *quo_len = *num_len - den_len;
409
410 // point to last digit to store for quotient
411 quo_dig += *quo_len - 1;
412
413 // keep going while we have enough digits to divide
414 while (*num_len > den_len) {
415 mpz_dbl_dig_t quo = (*num_dig << DIG_SIZE) | num_dig[-1];
416
417 // get approximate quotient
418 quo /= lead_den_digit;
419
420 // multiply quo by den and subtract from num get remainder
421 {
422 mpz_dbl_dig_signed_t borrow = 0;
423
424 for (mpz_dig_t *n = num_dig - den_len, *d = den_dig; n < num_dig; ++n, ++d) {
425 borrow += *n - quo * *d; // will overflow if DIG_SIZE >= 16
426 *n = borrow & DIG_MASK;
427 borrow >>= DIG_SIZE;
428 }
429 borrow += *num_dig; // will overflow if DIG_SIZE >= 16
430 *num_dig = borrow & DIG_MASK;
431 borrow >>= DIG_SIZE;
432
433 // adjust quotient if it is too big
434 for (; borrow != 0; --quo) {
435 mpz_dbl_dig_t carry = 0;
436 for (mpz_dig_t *n = num_dig - den_len, *d = den_dig; n < num_dig; ++n, ++d) {
437 carry += *n + *d;
438 *n = carry & DIG_MASK;
439 carry >>= DIG_SIZE;
440 }
441 carry += *num_dig;
442 *num_dig = carry & DIG_MASK;
443 carry >>= DIG_SIZE;
444
445 borrow += carry;
446 }
447 }
448
449 // store this digit of the quotient
450 *quo_dig = quo & DIG_MASK;
451 --quo_dig;
452
453 // move down to next digit of numerator
454 --num_dig;
455 --(*num_len);
456 }
457
458 // unnormalise denomenator
459 for (mpz_dig_t *den = den_dig + den_len - 1, carry = 0; den >= den_dig; --den) {
460 mpz_dig_t d = *den;
461 *den = ((d >> norm_shift) | carry) & DIG_MASK;
462 carry = d << (DIG_SIZE - norm_shift);
463 }
464
465 // unnormalise numerator (remainder now)
466 for (mpz_dig_t *num = orig_num_dig + *num_len - 1, carry = 0; num >= orig_num_dig; --num) {
467 mpz_dig_t n = *num;
468 *num = ((n >> norm_shift) | carry) & DIG_MASK;
469 carry = n << (DIG_SIZE - norm_shift);
470 }
471
472 // strip trailing zeros
473
474 while (*quo_len > 0 && orig_quo_dig[*quo_len - 1] == 0) {
475 --(*quo_len);
476 }
477
478 while (*num_len > 0 && orig_num_dig[*num_len - 1] == 0) {
479 --(*num_len);
480 }
481}
482
Damien George06201ff2014-03-01 19:50:50 +0000483#define MIN_ALLOC (2)
Damien George438c88d2014-02-22 19:25:23 +0000484
Damien George1c70cbf2014-08-30 00:38:16 +0100485STATIC const uint8_t log_base2_floor[] = {
Damien George438c88d2014-02-22 19:25:23 +0000486 0,
487 0, 1, 1, 2,
488 2, 2, 2, 3,
489 3, 3, 3, 3,
490 3, 3, 3, 4,
491 4, 4, 4, 4,
492 4, 4, 4, 4,
493 4, 4, 4, 4,
494 4, 4, 4, 5
495};
496
Damien George438c88d2014-02-22 19:25:23 +0000497void mpz_init_zero(mpz_t *z) {
Damien George438c88d2014-02-22 19:25:23 +0000498 z->neg = 0;
Damien George06201ff2014-03-01 19:50:50 +0000499 z->fixed_dig = 0;
500 z->alloc = 0;
Damien George438c88d2014-02-22 19:25:23 +0000501 z->len = 0;
502 z->dig = NULL;
503}
504
Damien George40f3c022014-07-03 13:25:24 +0100505void mpz_init_from_int(mpz_t *z, mp_int_t val) {
Damien George438c88d2014-02-22 19:25:23 +0000506 mpz_init_zero(z);
507 mpz_set_from_int(z, val);
508}
509
Damien Georgeafb1cf72014-09-05 20:37:06 +0100510void 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 +0000511 z->neg = 0;
512 z->fixed_dig = 1;
513 z->alloc = alloc;
514 z->len = 0;
515 z->dig = dig;
516 mpz_set_from_int(z, val);
517}
518
Damien George438c88d2014-02-22 19:25:23 +0000519void mpz_deinit(mpz_t *z) {
Damien George06201ff2014-03-01 19:50:50 +0000520 if (z != NULL && !z->fixed_dig) {
Damien George438c88d2014-02-22 19:25:23 +0000521 m_del(mpz_dig_t, z->dig, z->alloc);
522 }
523}
524
525mpz_t *mpz_zero(void) {
526 mpz_t *z = m_new_obj(mpz_t);
527 mpz_init_zero(z);
528 return z;
529}
530
Damien George40f3c022014-07-03 13:25:24 +0100531mpz_t *mpz_from_int(mp_int_t val) {
Damien George438c88d2014-02-22 19:25:23 +0000532 mpz_t *z = mpz_zero();
533 mpz_set_from_int(z, val);
534 return z;
535}
536
Damien Georgebb4a43f2014-03-12 15:36:06 +0000537mpz_t *mpz_from_ll(long long val) {
538 mpz_t *z = mpz_zero();
539 mpz_set_from_ll(z, val);
540 return z;
541}
542
Damien Georgeafb1cf72014-09-05 20:37:06 +0100543mpz_t *mpz_from_str(const char *str, mp_uint_t len, bool neg, mp_uint_t base) {
Damien George438c88d2014-02-22 19:25:23 +0000544 mpz_t *z = mpz_zero();
545 mpz_set_from_str(z, str, len, neg, base);
546 return z;
547}
548
549void mpz_free(mpz_t *z) {
550 if (z != NULL) {
551 m_del(mpz_dig_t, z->dig, z->alloc);
552 m_del_obj(mpz_t, z);
553 }
554}
555
Damien Georgeafb1cf72014-09-05 20:37:06 +0100556STATIC void mpz_need_dig(mpz_t *z, mp_uint_t need) {
Damien George438c88d2014-02-22 19:25:23 +0000557 if (need < MIN_ALLOC) {
Damien George06201ff2014-03-01 19:50:50 +0000558 need = MIN_ALLOC;
Damien George438c88d2014-02-22 19:25:23 +0000559 }
560
Damien George06201ff2014-03-01 19:50:50 +0000561 if (z->dig == NULL || z->alloc < need) {
562 if (z->fixed_dig) {
563 // cannot reallocate fixed buffers
564 assert(0);
565 return;
566 }
567 z->dig = m_renew(mpz_dig_t, z->dig, z->alloc, need);
568 z->alloc = need;
Damien George438c88d2014-02-22 19:25:23 +0000569 }
570}
571
572mpz_t *mpz_clone(const mpz_t *src) {
573 mpz_t *z = m_new_obj(mpz_t);
Damien George438c88d2014-02-22 19:25:23 +0000574 z->neg = src->neg;
Damien George06201ff2014-03-01 19:50:50 +0000575 z->fixed_dig = 0;
576 z->alloc = src->alloc;
Damien George438c88d2014-02-22 19:25:23 +0000577 z->len = src->len;
578 if (src->dig == NULL) {
579 z->dig = NULL;
580 } else {
581 z->dig = m_new(mpz_dig_t, z->alloc);
582 memcpy(z->dig, src->dig, src->alloc * sizeof(mpz_dig_t));
583 }
584 return z;
585}
586
Damien George06201ff2014-03-01 19:50:50 +0000587/* sets dest = src
588 can have dest, src the same
589*/
Damien George438c88d2014-02-22 19:25:23 +0000590void mpz_set(mpz_t *dest, const mpz_t *src) {
591 mpz_need_dig(dest, src->len);
592 dest->neg = src->neg;
593 dest->len = src->len;
594 memcpy(dest->dig, src->dig, src->len * sizeof(mpz_dig_t));
595}
596
Damien George40f3c022014-07-03 13:25:24 +0100597void mpz_set_from_int(mpz_t *z, mp_int_t val) {
Damien George06201ff2014-03-01 19:50:50 +0000598 mpz_need_dig(z, MPZ_NUM_DIG_FOR_INT);
Damien George438c88d2014-02-22 19:25:23 +0000599
Damien George40f3c022014-07-03 13:25:24 +0100600 mp_uint_t uval;
Damien George438c88d2014-02-22 19:25:23 +0000601 if (val < 0) {
602 z->neg = 1;
Damien Georgebb4a43f2014-03-12 15:36:06 +0000603 uval = -val;
Damien George438c88d2014-02-22 19:25:23 +0000604 } else {
605 z->neg = 0;
Damien Georgebb4a43f2014-03-12 15:36:06 +0000606 uval = val;
Damien George438c88d2014-02-22 19:25:23 +0000607 }
608
609 z->len = 0;
Damien Georgebb4a43f2014-03-12 15:36:06 +0000610 while (uval > 0) {
611 z->dig[z->len++] = uval & DIG_MASK;
612 uval >>= DIG_SIZE;
613 }
614}
615
616void mpz_set_from_ll(mpz_t *z, long long val) {
617 mpz_need_dig(z, MPZ_NUM_DIG_FOR_LL);
618
619 unsigned long long uval;
620 if (val < 0) {
621 z->neg = 1;
622 uval = -val;
623 } else {
624 z->neg = 0;
625 uval = val;
626 }
627
628 z->len = 0;
629 while (uval > 0) {
630 z->dig[z->len++] = uval & DIG_MASK;
631 uval >>= DIG_SIZE;
Damien George438c88d2014-02-22 19:25:23 +0000632 }
633}
634
635// returns number of bytes from str that were processed
Damien Georgeafb1cf72014-09-05 20:37:06 +0100636mp_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 +0000637 assert(base < 36);
638
639 const char *cur = str;
640 const char *top = str + len;
641
642 mpz_need_dig(z, len * 8 / DIG_SIZE + 1);
643
644 if (neg) {
645 z->neg = 1;
646 } else {
647 z->neg = 0;
648 }
649
650 z->len = 0;
651 for (; cur < top; ++cur) { // XXX UTF8 next char
Damien Georgeafb1cf72014-09-05 20:37:06 +0100652 //mp_uint_t v = char_to_numeric(cur#); // XXX UTF8 get char
653 mp_uint_t v = *cur;
Damien George438c88d2014-02-22 19:25:23 +0000654 if ('0' <= v && v <= '9') {
655 v -= '0';
656 } else if ('A' <= v && v <= 'Z') {
657 v -= 'A' - 10;
658 } else if ('a' <= v && v <= 'z') {
659 v -= 'a' - 10;
660 } else {
661 break;
662 }
663 if (v >= base) {
664 break;
665 }
666 z->len = mpn_mul_dig_add_dig(z->dig, z->len, base, v);
667 }
668
669 return cur - str;
670}
671
672bool mpz_is_zero(const mpz_t *z) {
673 return z->len == 0;
674}
675
676bool mpz_is_pos(const mpz_t *z) {
677 return z->len > 0 && z->neg == 0;
678}
679
680bool mpz_is_neg(const mpz_t *z) {
681 return z->len > 0 && z->neg != 0;
682}
683
684bool mpz_is_odd(const mpz_t *z) {
685 return z->len > 0 && (z->dig[0] & 1) != 0;
686}
687
688bool mpz_is_even(const mpz_t *z) {
689 return z->len == 0 || (z->dig[0] & 1) == 0;
690}
691
Damien Georgeafb1cf72014-09-05 20:37:06 +0100692mp_int_t mpz_cmp(const mpz_t *z1, const mpz_t *z2) {
693 mp_int_t cmp = z2->neg - z1->neg;
Damien George438c88d2014-02-22 19:25:23 +0000694 if (cmp != 0) {
695 return cmp;
696 }
697 cmp = mpn_cmp(z1->dig, z1->len, z2->dig, z2->len);
698 if (z1->neg != 0) {
699 cmp = -cmp;
700 }
701 return cmp;
702}
703
Damien George06201ff2014-03-01 19:50:50 +0000704#if 0
705// obsolete
706// compares mpz with an integer that fits within DIG_SIZE bits
Damien Georgeafb1cf72014-09-05 20:37:06 +0100707mp_int_t mpz_cmp_sml_int(const mpz_t *z, mp_int_t sml_int) {
708 mp_int_t cmp;
Damien George438c88d2014-02-22 19:25:23 +0000709 if (z->neg == 0) {
710 if (sml_int < 0) return 1;
711 if (sml_int == 0) {
712 if (z->len == 0) return 0;
713 return 1;
714 }
715 if (z->len == 0) return -1;
716 assert(sml_int < (1 << DIG_SIZE));
717 if (z->len != 1) return 1;
718 cmp = z->dig[0] - sml_int;
719 } else {
720 if (sml_int > 0) return -1;
721 if (sml_int == 0) {
722 if (z->len == 0) return 0;
723 return -1;
724 }
725 if (z->len == 0) return 1;
726 assert(sml_int > -(1 << DIG_SIZE));
727 if (z->len != 1) return -1;
728 cmp = -z->dig[0] - sml_int;
729 }
730 if (cmp < 0) return -1;
731 if (cmp > 0) return 1;
732 return 0;
733}
Damien George06201ff2014-03-01 19:50:50 +0000734#endif
Damien George438c88d2014-02-22 19:25:23 +0000735
Damien George438c88d2014-02-22 19:25:23 +0000736#if 0
737these functions are unused
738
739/* returns abs(z)
740*/
741mpz_t *mpz_abs(const mpz_t *z) {
742 mpz_t *z2 = mpz_clone(z);
743 z2->neg = 0;
744 return z2;
745}
746
747/* returns -z
748*/
749mpz_t *mpz_neg(const mpz_t *z) {
750 mpz_t *z2 = mpz_clone(z);
751 z2->neg = 1 - z2->neg;
752 return z2;
753}
754
755/* returns lhs + rhs
756 can have lhs, rhs the same
757*/
758mpz_t *mpz_add(const mpz_t *lhs, const mpz_t *rhs) {
759 mpz_t *z = mpz_zero();
760 mpz_add_inpl(z, lhs, rhs);
761 return z;
762}
763
764/* returns lhs - rhs
765 can have lhs, rhs the same
766*/
767mpz_t *mpz_sub(const mpz_t *lhs, const mpz_t *rhs) {
768 mpz_t *z = mpz_zero();
769 mpz_sub_inpl(z, lhs, rhs);
770 return z;
771}
772
773/* returns lhs * rhs
774 can have lhs, rhs the same
775*/
776mpz_t *mpz_mul(const mpz_t *lhs, const mpz_t *rhs) {
777 mpz_t *z = mpz_zero();
778 mpz_mul_inpl(z, lhs, rhs);
779 return z;
780}
781
782/* returns lhs ** rhs
783 can have lhs, rhs the same
784*/
785mpz_t *mpz_pow(const mpz_t *lhs, const mpz_t *rhs) {
786 mpz_t *z = mpz_zero();
787 mpz_pow_inpl(z, lhs, rhs);
788 return z;
789}
790#endif
791
792/* computes dest = abs(z)
793 can have dest, z the same
794*/
795void mpz_abs_inpl(mpz_t *dest, const mpz_t *z) {
796 if (dest != z) {
797 mpz_set(dest, z);
798 }
799 dest->neg = 0;
800}
801
802/* computes dest = -z
803 can have dest, z the same
804*/
805void mpz_neg_inpl(mpz_t *dest, const mpz_t *z) {
806 if (dest != z) {
807 mpz_set(dest, z);
808 }
809 dest->neg = 1 - dest->neg;
810}
811
Damien George06201ff2014-03-01 19:50:50 +0000812/* computes dest = ~z (= -z - 1)
813 can have dest, z the same
814*/
815void mpz_not_inpl(mpz_t *dest, const mpz_t *z) {
816 if (dest != z) {
817 mpz_set(dest, z);
818 }
819 if (dest->neg) {
820 dest->neg = 0;
821 mpz_dig_t k = 1;
822 dest->len = mpn_sub(dest->dig, dest->dig, dest->len, &k, 1);
823 } else {
824 mpz_dig_t k = 1;
825 dest->len = mpn_add(dest->dig, dest->dig, dest->len, &k, 1);
826 dest->neg = 1;
827 }
828}
829
Damien Georgec5ac2ac2014-02-26 16:56:30 +0000830/* computes dest = lhs << rhs
831 can have dest, lhs the same
832*/
Damien George40f3c022014-07-03 13:25:24 +0100833void mpz_shl_inpl(mpz_t *dest, const mpz_t *lhs, mp_int_t rhs) {
Damien George06201ff2014-03-01 19:50:50 +0000834 if (lhs->len == 0 || rhs == 0) {
Damien Georgec5ac2ac2014-02-26 16:56:30 +0000835 mpz_set(dest, lhs);
Damien George06201ff2014-03-01 19:50:50 +0000836 } else if (rhs < 0) {
837 mpz_shr_inpl(dest, lhs, -rhs);
Damien Georgec5ac2ac2014-02-26 16:56:30 +0000838 } else {
Damien George06201ff2014-03-01 19:50:50 +0000839 mpz_need_dig(dest, lhs->len + (rhs + DIG_SIZE - 1) / DIG_SIZE);
840 dest->len = mpn_shl(dest->dig, lhs->dig, lhs->len, rhs);
841 dest->neg = lhs->neg;
Damien Georgec5ac2ac2014-02-26 16:56:30 +0000842 }
Damien Georgec5ac2ac2014-02-26 16:56:30 +0000843}
844
845/* computes dest = lhs >> rhs
846 can have dest, lhs the same
847*/
Damien George40f3c022014-07-03 13:25:24 +0100848void mpz_shr_inpl(mpz_t *dest, const mpz_t *lhs, mp_int_t rhs) {
Damien George06201ff2014-03-01 19:50:50 +0000849 if (lhs->len == 0 || rhs == 0) {
Damien Georgec5ac2ac2014-02-26 16:56:30 +0000850 mpz_set(dest, lhs);
Damien George06201ff2014-03-01 19:50:50 +0000851 } else if (rhs < 0) {
852 mpz_shl_inpl(dest, lhs, -rhs);
Damien Georgec5ac2ac2014-02-26 16:56:30 +0000853 } else {
Damien George06201ff2014-03-01 19:50:50 +0000854 mpz_need_dig(dest, lhs->len);
855 dest->len = mpn_shr(dest->dig, lhs->dig, lhs->len, rhs);
856 dest->neg = lhs->neg;
857 if (dest->neg) {
858 // arithmetic shift right, rounding to negative infinity
Damien Georgeafb1cf72014-09-05 20:37:06 +0100859 mp_uint_t n_whole = rhs / DIG_SIZE;
860 mp_uint_t n_part = rhs % DIG_SIZE;
Damien George06201ff2014-03-01 19:50:50 +0000861 mpz_dig_t round_up = 0;
Damien Georgeafb1cf72014-09-05 20:37:06 +0100862 for (mp_uint_t i = 0; i < lhs->len && i < n_whole; i++) {
Damien George06201ff2014-03-01 19:50:50 +0000863 if (lhs->dig[i] != 0) {
864 round_up = 1;
865 break;
866 }
867 }
868 if (n_whole < lhs->len && (lhs->dig[n_whole] & ((1 << n_part) - 1)) != 0) {
869 round_up = 1;
870 }
871 if (round_up) {
872 dest->len = mpn_add(dest->dig, dest->dig, dest->len, &round_up, 1);
873 }
874 }
Damien Georgec5ac2ac2014-02-26 16:56:30 +0000875 }
Damien Georgec5ac2ac2014-02-26 16:56:30 +0000876}
Damien Georgec5ac2ac2014-02-26 16:56:30 +0000877
Damien George438c88d2014-02-22 19:25:23 +0000878/* computes dest = lhs + rhs
879 can have dest, lhs, rhs the same
880*/
881void mpz_add_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
882 if (mpn_cmp(lhs->dig, lhs->len, rhs->dig, rhs->len) < 0) {
883 const mpz_t *temp = lhs;
884 lhs = rhs;
885 rhs = temp;
886 }
887
888 if (lhs->neg == rhs->neg) {
889 mpz_need_dig(dest, lhs->len + 1);
890 dest->len = mpn_add(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
891 } else {
892 mpz_need_dig(dest, lhs->len);
893 dest->len = mpn_sub(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
894 }
895
896 dest->neg = lhs->neg;
897}
898
899/* computes dest = lhs - rhs
900 can have dest, lhs, rhs the same
901*/
902void mpz_sub_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
903 bool neg = false;
904
905 if (mpn_cmp(lhs->dig, lhs->len, rhs->dig, rhs->len) < 0) {
906 const mpz_t *temp = lhs;
907 lhs = rhs;
908 rhs = temp;
909 neg = true;
910 }
911
912 if (lhs->neg != rhs->neg) {
913 mpz_need_dig(dest, lhs->len + 1);
914 dest->len = mpn_add(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
915 } else {
916 mpz_need_dig(dest, lhs->len);
917 dest->len = mpn_sub(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
918 }
919
920 if (neg) {
921 dest->neg = 1 - lhs->neg;
922 } else {
923 dest->neg = lhs->neg;
924 }
925}
926
Paul Sokolovsky57207b82014-03-23 01:52:36 +0200927/* computes dest = lhs & rhs
928 can have dest, lhs, rhs the same
929*/
930void mpz_and_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
Paul Sokolovsky57207b82014-03-23 01:52:36 +0200931 if (lhs->neg == rhs->neg) {
Damien Georgef55cf102014-05-29 15:01:49 +0100932 if (lhs->neg == 0) {
933 // make sure lhs has the most digits
934 if (lhs->len < rhs->len) {
935 const mpz_t *temp = lhs;
936 lhs = rhs;
937 rhs = temp;
938 }
939 // do the and'ing
940 mpz_need_dig(dest, rhs->len);
941 dest->len = mpn_and(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
942 dest->neg = 0;
943 } else {
944 // TODO both args are negative
945 assert(0);
946 }
Paul Sokolovsky57207b82014-03-23 01:52:36 +0200947 } else {
Damien Georgef55cf102014-05-29 15:01:49 +0100948 // args have different sign
949 // make sure lhs is the positive arg
950 if (rhs->neg == 0) {
951 const mpz_t *temp = lhs;
952 lhs = rhs;
953 rhs = temp;
954 }
955 mpz_need_dig(dest, lhs->len + 1);
956 dest->len = mpn_and_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
957 assert(dest->len <= dest->alloc);
958 dest->neg = 0;
Paul Sokolovsky57207b82014-03-23 01:52:36 +0200959 }
Paul Sokolovsky57207b82014-03-23 01:52:36 +0200960}
961
962/* computes dest = lhs | rhs
963 can have dest, lhs, rhs the same
964*/
965void mpz_or_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
966 if (mpn_cmp(lhs->dig, lhs->len, rhs->dig, rhs->len) < 0) {
967 const mpz_t *temp = lhs;
968 lhs = rhs;
969 rhs = temp;
970 }
971
972 if (lhs->neg == rhs->neg) {
973 mpz_need_dig(dest, lhs->len);
974 dest->len = mpn_or(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
975 } else {
976 mpz_need_dig(dest, lhs->len);
977 // TODO
978 assert(0);
979// dest->len = mpn_or_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
980 }
981
982 dest->neg = lhs->neg;
983}
984
985/* computes dest = lhs ^ rhs
986 can have dest, lhs, rhs the same
987*/
988void mpz_xor_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
989 if (mpn_cmp(lhs->dig, lhs->len, rhs->dig, rhs->len) < 0) {
990 const mpz_t *temp = lhs;
991 lhs = rhs;
992 rhs = temp;
993 }
994
995 if (lhs->neg == rhs->neg) {
996 mpz_need_dig(dest, lhs->len);
997 dest->len = mpn_xor(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
998 } else {
999 mpz_need_dig(dest, lhs->len);
1000 // TODO
1001 assert(0);
1002// dest->len = mpn_xor_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
1003 }
1004
1005 dest->neg = 0;
1006}
1007
Damien George438c88d2014-02-22 19:25:23 +00001008/* computes dest = lhs * rhs
1009 can have dest, lhs, rhs the same
1010*/
1011void mpz_mul_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs)
1012{
1013 if (lhs->len == 0 || rhs->len == 0) {
Damien Georgec5ac2ac2014-02-26 16:56:30 +00001014 mpz_set_from_int(dest, 0);
1015 return;
Damien George438c88d2014-02-22 19:25:23 +00001016 }
1017
1018 mpz_t *temp = NULL;
1019 if (lhs == dest) {
1020 lhs = temp = mpz_clone(lhs);
1021 if (rhs == dest) {
1022 rhs = lhs;
1023 }
1024 } else if (rhs == dest) {
1025 rhs = temp = mpz_clone(rhs);
1026 }
1027
1028 mpz_need_dig(dest, lhs->len + rhs->len); // min mem l+r-1, max mem l+r
1029 memset(dest->dig, 0, dest->alloc * sizeof(mpz_dig_t));
1030 dest->len = mpn_mul(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
1031
1032 if (lhs->neg == rhs->neg) {
1033 dest->neg = 0;
1034 } else {
1035 dest->neg = 1;
1036 }
1037
1038 mpz_free(temp);
1039}
1040
1041/* computes dest = lhs ** rhs
1042 can have dest, lhs, rhs the same
1043*/
1044void mpz_pow_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
1045 if (lhs->len == 0 || rhs->neg != 0) {
Damien Georgec5ac2ac2014-02-26 16:56:30 +00001046 mpz_set_from_int(dest, 0);
1047 return;
Damien George438c88d2014-02-22 19:25:23 +00001048 }
1049
1050 if (rhs->len == 0) {
Damien Georgec5ac2ac2014-02-26 16:56:30 +00001051 mpz_set_from_int(dest, 1);
1052 return;
Damien George438c88d2014-02-22 19:25:23 +00001053 }
1054
1055 mpz_t *x = mpz_clone(lhs);
1056 mpz_t *n = mpz_clone(rhs);
1057
1058 mpz_set_from_int(dest, 1);
1059
1060 while (n->len > 0) {
1061 if (mpz_is_odd(n)) {
1062 mpz_mul_inpl(dest, dest, x);
1063 }
Damien George438c88d2014-02-22 19:25:23 +00001064 n->len = mpn_shr(n->dig, n->dig, n->len, 1);
Damien George5bf565e2014-04-04 00:16:32 +01001065 if (n->len == 0) {
1066 break;
1067 }
1068 mpz_mul_inpl(x, x, x);
Damien George438c88d2014-02-22 19:25:23 +00001069 }
1070
1071 mpz_free(x);
1072 mpz_free(n);
1073}
1074
1075/* computes gcd(z1, z2)
1076 based on Knuth's modified gcd algorithm (I think?)
1077 gcd(z1, z2) >= 0
1078 gcd(0, 0) = 0
1079 gcd(z, 0) = abs(z)
1080*/
1081mpz_t *mpz_gcd(const mpz_t *z1, const mpz_t *z2) {
1082 if (z1->len == 0) {
1083 mpz_t *a = mpz_clone(z2);
1084 a->neg = 0;
1085 return a;
1086 } else if (z2->len == 0) {
1087 mpz_t *a = mpz_clone(z1);
1088 a->neg = 0;
1089 return a;
1090 }
1091
1092 mpz_t *a = mpz_clone(z1);
1093 mpz_t *b = mpz_clone(z2);
1094 mpz_t c; mpz_init_zero(&c);
1095 a->neg = 0;
1096 b->neg = 0;
1097
1098 for (;;) {
1099 if (mpz_cmp(a, b) < 0) {
1100 if (a->len == 0) {
1101 mpz_free(a);
1102 mpz_deinit(&c);
1103 return b;
1104 }
1105 mpz_t *t = a; a = b; b = t;
1106 }
1107 if (!(b->len >= 2 || (b->len == 1 && b->dig[0] > 1))) { // compute b > 0; could be mpz_cmp_small_int(b, 1) > 0
1108 break;
1109 }
1110 mpz_set(&c, b);
1111 do {
1112 mpz_add_inpl(&c, &c, &c);
1113 } while (mpz_cmp(&c, a) <= 0);
1114 c.len = mpn_shr(c.dig, c.dig, c.len, 1);
1115 mpz_sub_inpl(a, a, &c);
1116 }
1117
1118 mpz_deinit(&c);
1119
1120 if (b->len == 1 && b->dig[0] == 1) { // compute b == 1; could be mpz_cmp_small_int(b, 1) == 0
1121 mpz_free(a);
1122 return b;
1123 } else {
1124 mpz_free(b);
1125 return a;
1126 }
1127}
1128
1129/* computes lcm(z1, z2)
1130 = abs(z1) / gcd(z1, z2) * abs(z2)
1131 lcm(z1, z1) >= 0
1132 lcm(0, 0) = 0
1133 lcm(z, 0) = 0
1134*/
Damien George5d9b8162014-08-07 14:27:48 +00001135mpz_t *mpz_lcm(const mpz_t *z1, const mpz_t *z2) {
1136 if (z1->len == 0 || z2->len == 0) {
1137 return mpz_zero();
stijn01d6be42014-05-05 12:18:27 +02001138 }
Damien George438c88d2014-02-22 19:25:23 +00001139
1140 mpz_t *gcd = mpz_gcd(z1, z2);
1141 mpz_t *quo = mpz_zero();
1142 mpz_t *rem = mpz_zero();
1143 mpz_divmod_inpl(quo, rem, z1, gcd);
1144 mpz_mul_inpl(rem, quo, z2);
1145 mpz_free(gcd);
1146 mpz_free(quo);
1147 rem->neg = 0;
1148 return rem;
1149}
1150
1151/* computes new integers in quo and rem such that:
1152 quo * rhs + rem = lhs
1153 0 <= rem < rhs
1154 can have lhs, rhs the same
1155*/
1156void mpz_divmod(const mpz_t *lhs, const mpz_t *rhs, mpz_t **quo, mpz_t **rem) {
1157 *quo = mpz_zero();
1158 *rem = mpz_zero();
1159 mpz_divmod_inpl(*quo, *rem, lhs, rhs);
1160}
1161
1162/* computes new integers in quo and rem such that:
1163 quo * rhs + rem = lhs
1164 0 <= rem < rhs
1165 can have lhs, rhs the same
1166*/
1167void mpz_divmod_inpl(mpz_t *dest_quo, mpz_t *dest_rem, const mpz_t *lhs, const mpz_t *rhs) {
1168 if (rhs->len == 0) {
1169 mpz_set_from_int(dest_quo, 0);
1170 mpz_set_from_int(dest_rem, 0);
1171 return;
1172 }
1173
1174 mpz_need_dig(dest_quo, lhs->len + 1); // +1 necessary?
1175 memset(dest_quo->dig, 0, (lhs->len + 1) * sizeof(mpz_dig_t));
1176 dest_quo->len = 0;
1177 mpz_need_dig(dest_rem, lhs->len + 1); // +1 necessary?
1178 mpz_set(dest_rem, lhs);
1179 //rhs->dig[rhs->len] = 0;
1180 mpn_div(dest_rem->dig, &dest_rem->len, rhs->dig, rhs->len, dest_quo->dig, &dest_quo->len);
1181
1182 if (lhs->neg != rhs->neg) {
1183 dest_quo->neg = 1;
1184 }
1185}
1186
1187#if 0
1188these functions are unused
1189
1190/* computes floor(lhs / rhs)
1191 can have lhs, rhs the same
1192*/
1193mpz_t *mpz_div(const mpz_t *lhs, const mpz_t *rhs) {
1194 mpz_t *quo = mpz_zero();
1195 mpz_t rem; mpz_init_zero(&rem);
1196 mpz_divmod_inpl(quo, &rem, lhs, rhs);
1197 mpz_deinit(&rem);
1198 return quo;
1199}
1200
1201/* computes lhs % rhs ( >= 0)
1202 can have lhs, rhs the same
1203*/
1204mpz_t *mpz_mod(const mpz_t *lhs, const mpz_t *rhs) {
1205 mpz_t quo; mpz_init_zero(&quo);
1206 mpz_t *rem = mpz_zero();
1207 mpz_divmod_inpl(&quo, rem, lhs, rhs);
1208 mpz_deinit(&quo);
1209 return rem;
1210}
1211#endif
1212
Damien Georgeffe911d2014-07-24 14:21:37 +01001213// must return actual int value if it fits in mp_int_t
1214mp_int_t mpz_hash(const mpz_t *z) {
1215 mp_int_t val = 0;
1216 mpz_dig_t *d = z->dig + z->len;
1217
1218 while (--d >= z->dig) {
1219 val = (val << DIG_SIZE) | *d;
1220 }
1221
1222 if (z->neg != 0) {
1223 val = -val;
1224 }
1225
1226 return val;
1227}
1228
Damien George40f3c022014-07-03 13:25:24 +01001229bool mpz_as_int_checked(const mpz_t *i, mp_int_t *value) {
1230 mp_int_t val = 0;
Damien George8270e382014-04-03 11:00:54 +00001231 mpz_dig_t *d = i->dig + i->len;
1232
1233 while (--d >= i->dig) {
Damien Georgec9aa58e2014-07-31 13:41:43 +00001234 if (val > (~(WORD_MSBIT_HIGH) >> DIG_SIZE)) {
1235 // will overflow
Damien George8270e382014-04-03 11:00:54 +00001236 return false;
1237 }
Damien Georgec9aa58e2014-07-31 13:41:43 +00001238 val = (val << DIG_SIZE) | *d;
Damien George8270e382014-04-03 11:00:54 +00001239 }
1240
1241 if (i->neg != 0) {
1242 val = -val;
1243 }
1244
1245 *value = val;
1246 return true;
1247}
1248
Damien Georgec9aa58e2014-07-31 13:41:43 +00001249bool mpz_as_uint_checked(const mpz_t *i, mp_uint_t *value) {
1250 if (i->neg != 0) {
1251 // can't represent signed values
1252 return false;
1253 }
1254
1255 mp_uint_t val = 0;
1256 mpz_dig_t *d = i->dig + i->len;
1257
1258 while (--d >= i->dig) {
1259 if (val > ((~0) >> DIG_SIZE)) {
1260 // will overflow
1261 return false;
1262 }
1263 val = (val << DIG_SIZE) | *d;
1264 }
1265
1266 *value = val;
1267 return true;
1268}
1269
Damien Georgefb510b32014-06-01 13:32:54 +01001270#if MICROPY_PY_BUILTINS_FLOAT
Damien George52608102014-03-08 15:04:54 +00001271mp_float_t mpz_as_float(const mpz_t *i) {
1272 mp_float_t val = 0;
Damien George438c88d2014-02-22 19:25:23 +00001273 mpz_dig_t *d = i->dig + i->len;
1274
1275 while (--d >= i->dig) {
1276 val = val * (1 << DIG_SIZE) + *d;
1277 }
1278
1279 if (i->neg != 0) {
1280 val = -val;
1281 }
1282
1283 return val;
1284}
Damien George52608102014-03-08 15:04:54 +00001285#endif
Damien George438c88d2014-02-22 19:25:23 +00001286
Damien Georgeafb1cf72014-09-05 20:37:06 +01001287mp_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 +00001288 if (base < 2 || base > 32) {
1289 return 0;
1290 }
1291
Damien Georgeafb1cf72014-09-05 20:37:06 +01001292 mp_uint_t num_digits = i->len * DIG_SIZE / log_base2_floor[base] + 1;
1293 mp_uint_t num_commas = comma ? num_digits / 3: 0;
1294 mp_uint_t prefix_len = prefix ? strlen(prefix) : 0;
Dave Hylandsc4029e52014-04-07 11:19:51 -07001295
1296 return num_digits + num_commas + prefix_len + 2; // +1 for sign, +1 for null byte
1297}
1298
Damien Georgeafb1cf72014-09-05 20:37:06 +01001299#if 0
1300this function is unused
1301char *mpz_as_str(const mpz_t *i, mp_uint_t base) {
1302 char *s = m_new(char, mpz_as_str_size(i, base, NULL, '\0'));
1303 mpz_as_str_inpl(i, base, NULL, 'a', '\0', s);
Damien George438c88d2014-02-22 19:25:23 +00001304 return s;
1305}
Damien Georgeafb1cf72014-09-05 20:37:06 +01001306#endif
Damien George438c88d2014-02-22 19:25:23 +00001307
1308// assumes enough space as calculated by mpz_as_str_size
1309// returns length of string, not including null byte
Damien Georgeafb1cf72014-09-05 20:37:06 +01001310mp_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 +00001311 if (str == NULL || base < 2 || base > 32) {
1312 str[0] = 0;
1313 return 0;
1314 }
1315
Damien Georgeafb1cf72014-09-05 20:37:06 +01001316 mp_uint_t ilen = i->len;
Damien George438c88d2014-02-22 19:25:23 +00001317
Dave Hylandsc4029e52014-04-07 11:19:51 -07001318 char *s = str;
Damien George438c88d2014-02-22 19:25:23 +00001319 if (ilen == 0) {
Dave Hylandsc4029e52014-04-07 11:19:51 -07001320 if (prefix) {
1321 while (*prefix)
1322 *s++ = *prefix++;
1323 }
1324 *s++ = '0';
1325 *s = '\0';
1326 return s - str;
Damien George438c88d2014-02-22 19:25:23 +00001327 }
1328
Damien Georgeeec91052014-04-08 23:11:00 +01001329 // make a copy of mpz digits, so we can do the div/mod calculation
Damien George438c88d2014-02-22 19:25:23 +00001330 mpz_dig_t *dig = m_new(mpz_dig_t, ilen);
1331 memcpy(dig, i->dig, ilen * sizeof(mpz_dig_t));
1332
1333 // convert
Dave Hylandsc4029e52014-04-07 11:19:51 -07001334 char *last_comma = str;
Damien George438c88d2014-02-22 19:25:23 +00001335 bool done;
1336 do {
1337 mpz_dig_t *d = dig + ilen;
1338 mpz_dbl_dig_t a = 0;
1339
1340 // compute next remainder
1341 while (--d >= dig) {
1342 a = (a << DIG_SIZE) | *d;
1343 *d = a / base;
1344 a %= base;
1345 }
1346
1347 // convert to character
1348 a += '0';
1349 if (a > '9') {
Dave Hylandsc4029e52014-04-07 11:19:51 -07001350 a += base_char - '9' - 1;
Damien George438c88d2014-02-22 19:25:23 +00001351 }
1352 *s++ = a;
1353
1354 // check if number is zero
1355 done = true;
1356 for (d = dig; d < dig + ilen; ++d) {
1357 if (*d != 0) {
1358 done = false;
1359 break;
1360 }
1361 }
Dave Hylandsc4029e52014-04-07 11:19:51 -07001362 if (comma && (s - last_comma) == 3) {
1363 *s++ = comma;
1364 last_comma = s;
1365 }
1366 }
1367 while (!done);
Damien George438c88d2014-02-22 19:25:23 +00001368
Damien Georgeeec91052014-04-08 23:11:00 +01001369 // free the copy of the digits array
1370 m_del(mpz_dig_t, dig, ilen);
1371
Dave Hylandsc4029e52014-04-07 11:19:51 -07001372 if (prefix) {
1373 const char *p = &prefix[strlen(prefix)];
1374 while (p > prefix) {
1375 *s++ = *--p;
1376 }
1377 }
Damien George438c88d2014-02-22 19:25:23 +00001378 if (i->neg != 0) {
1379 *s++ = '-';
1380 }
1381
1382 // reverse string
1383 for (char *u = str, *v = s - 1; u < v; ++u, --v) {
1384 char temp = *u;
1385 *u = *v;
1386 *v = temp;
1387 }
1388
Dave Hylandsc4029e52014-04-07 11:19:51 -07001389 *s = '\0'; // null termination
Damien George438c88d2014-02-22 19:25:23 +00001390
1391 return s - str;
1392}
1393
1394#endif // MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_MPZ