blob: 8dc6b37b9bbe16c8250bd4c519fed11c179e7847 [file] [log] [blame]
Damien George438c88d2014-02-22 19:25:23 +00001#include <stdint.h>
2#include <stdbool.h>
3#include <stdlib.h>
4#include <string.h>
5#include <assert.h>
6
7#include "misc.h"
8#include "mpconfig.h"
9#include "mpz.h"
10
11#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_MPZ
12
13#define DIG_SIZE (15)
14#define DIG_MASK ((1 << DIG_SIZE) - 1)
15
16/*
17 definition of normalise:
18 ?
19*/
20
21/* compares i with j
22 returns sign(i - j)
23 assumes i, j are normalised
24*/
25int mpn_cmp(const mpz_dig_t *idig, uint ilen, const mpz_dig_t *jdig, uint jlen) {
26 if (ilen < jlen) { return -1; }
27 if (ilen > jlen) { return 1; }
28
29 for (idig += ilen, jdig += ilen; ilen > 0; --ilen) {
30 int cmp = *(--idig) - *(--jdig);
31 if (cmp < 0) { return -1; }
32 if (cmp > 0) { return 1; }
33 }
34
35 return 0;
36}
37
Damien Georgec5ac2ac2014-02-26 16:56:30 +000038/* computes i = j << n
39 returns number of digits in i
40 assumes enough memory in i; assumes normalised j
41 can have i, j pointing to same memory
42*/
43/* unfinished
44uint mpn_shl(mpz_dig_t *idig, mpz_dig_t *jdig, uint jlen, uint n) {
45 uint n_whole = n / DIG_SIZE;
46 uint n_part = n % DIG_SIZE;
47
48 idig += jlen + n_whole + 1;
49
50 for (uint i = jlen; i > 0; --i, ++idig, ++jdig) {
51 mpz_dbl_dig_t d = *jdig;
52 if (i > 1) {
53 d |= jdig[1] << DIG_SIZE;
54 }
55 d <<= n_part;
56 *idig = d & DIG_MASK;
57 }
58
59 if (idig[-1] == 0) {
60 --jlen;
61 }
62
63 return jlen;
64}
65*/
66
Damien George438c88d2014-02-22 19:25:23 +000067/* computes i = j >> n
68 returns number of digits in i
69 assumes enough memory in i; assumes normalised j
70 can have i, j pointing to same memory
71*/
72uint mpn_shr(mpz_dig_t *idig, mpz_dig_t *jdig, uint jlen, uint n) {
73 uint n_whole = n / DIG_SIZE;
74 uint n_part = n % DIG_SIZE;
75
76 if (n_whole >= jlen) {
77 return 0;
78 }
79
80 jdig += n_whole;
81 jlen -= n_whole;
82
83 for (uint i = jlen; i > 0; --i, ++idig, ++jdig) {
84 mpz_dbl_dig_t d = *jdig;
Damien Georgec5ac2ac2014-02-26 16:56:30 +000085 if (i > 1) {
Damien George438c88d2014-02-22 19:25:23 +000086 d |= jdig[1] << DIG_SIZE;
Damien Georgec5ac2ac2014-02-26 16:56:30 +000087 }
Damien George438c88d2014-02-22 19:25:23 +000088 d >>= n_part;
89 *idig = d & DIG_MASK;
90 }
91
92 if (idig[-1] == 0) {
93 --jlen;
94 }
95
96 return jlen;
97}
98
99/* computes i = j + k
100 returns number of digits in i
101 assumes enough memory in i; assumes normalised j, k; assumes jlen >= klen
102 can have i, j, k pointing to same memory
103*/
104uint mpn_add(mpz_dig_t *idig, const mpz_dig_t *jdig, uint jlen, const mpz_dig_t *kdig, uint klen) {
105 mpz_dig_t *oidig = idig;
106 mpz_dbl_dig_t carry = 0;
107
108 jlen -= klen;
109
110 for (; klen > 0; --klen, ++idig, ++jdig, ++kdig) {
111 carry += *jdig + *kdig;
112 *idig = carry & DIG_MASK;
113 carry >>= DIG_SIZE;
114 }
115
116 for (; jlen > 0; --jlen, ++idig, ++jdig) {
117 carry += *jdig;
118 *idig = carry & DIG_MASK;
119 carry >>= DIG_SIZE;
120 }
121
122 if (carry != 0) {
123 *idig++ = carry;
124 }
125
126 return idig - oidig;
127}
128
129/* computes i = j - k
130 returns number of digits in i
131 assumes enough memory in i; assumes normalised j, k; assumes j >= k
132 can have i, j, k pointing to same memory
133*/
134uint mpn_sub(mpz_dig_t *idig, const mpz_dig_t *jdig, uint jlen, const mpz_dig_t *kdig, uint klen) {
135 mpz_dig_t *oidig = idig;
136 mpz_dbl_dig_signed_t borrow = 0;
137
138 jlen -= klen;
139
140 for (; klen > 0; --klen, ++idig, ++jdig, ++kdig) {
141 borrow += *jdig - *kdig;
142 *idig = borrow & DIG_MASK;
143 borrow >>= DIG_SIZE;
144 }
145
Damien Georgeaca14122014-02-24 21:32:52 +0000146 for (; jlen > 0; --jlen, ++idig, ++jdig) {
Damien George438c88d2014-02-22 19:25:23 +0000147 borrow += *jdig;
148 *idig = borrow & DIG_MASK;
149 borrow >>= DIG_SIZE;
150 }
151
152 for (--idig; idig >= oidig && *idig == 0; --idig) {
153 }
154
155 return idig + 1 - oidig;
156}
157
158/* computes i = i * d1 + d2
159 returns number of digits in i
160 assumes enough memory in i; assumes normalised i; assumes dmul != 0
161*/
162uint mpn_mul_dig_add_dig(mpz_dig_t *idig, uint ilen, mpz_dig_t dmul, mpz_dig_t dadd) {
163 mpz_dig_t *oidig = idig;
164 mpz_dbl_dig_t carry = dadd;
165
166 for (; ilen > 0; --ilen, ++idig) {
167 carry += *idig * dmul; // will never overflow so long as DIG_SIZE <= WORD_SIZE / 2
168 *idig = carry & DIG_MASK;
169 carry >>= DIG_SIZE;
170 }
171
172 if (carry != 0) {
173 *idig++ = carry;
174 }
175
176 return idig - oidig;
177}
178
179/* computes i = j * k
180 returns number of digits in i
181 assumes enough memory in i; assumes i is zeroed; assumes normalised j, k
182 can have j, k point to same memory
183*/
184uint mpn_mul(mpz_dig_t *idig, mpz_dig_t *jdig, uint jlen, mpz_dig_t *kdig, uint klen) {
185 mpz_dig_t *oidig = idig;
186 uint ilen = 0;
187
188 for (; klen > 0; --klen, ++idig, ++kdig) {
189 mpz_dig_t *id = idig;
190 mpz_dbl_dig_t carry = 0;
191
192 uint jl = jlen;
193 for (mpz_dig_t *jd = jdig; jl > 0; --jl, ++jd, ++id) {
194 carry += *id + *jd * *kdig; // will never overflow so long as DIG_SIZE <= WORD_SIZE / 2
195 *id = carry & DIG_MASK;
196 carry >>= DIG_SIZE;
197 }
198
199 if (carry != 0) {
200 *id++ = carry;
201 }
202
203 ilen = id - oidig;
204 }
205
206 return ilen;
207}
208
209/* natural_div - quo * den + new_num = old_num (ie num is replaced with rem)
210 assumes den != 0
211 assumes num_dig has enough memory to be extended by 1 digit
212 assumes quo_dig has enough memory (as many digits as num)
213 assumes quo_dig is filled with zeros
214 modifies den_dig memory, but restors it to original state at end
215*/
216
217void mpn_div(mpz_dig_t *num_dig, machine_uint_t *num_len, mpz_dig_t *den_dig, machine_uint_t den_len, mpz_dig_t *quo_dig, machine_uint_t *quo_len) {
218 mpz_dig_t *orig_num_dig = num_dig;
219 mpz_dig_t *orig_quo_dig = quo_dig;
220 mpz_dig_t norm_shift = 0;
221 mpz_dbl_dig_t lead_den_digit;
222
223 // handle simple cases
224 {
225 int cmp = mpn_cmp(num_dig, *num_len, den_dig, den_len);
226 if (cmp == 0) {
227 *num_len = 0;
228 quo_dig[0] = 1;
229 *quo_len = 1;
230 return;
231 } else if (cmp < 0) {
232 // numerator remains the same
233 *quo_len = 0;
234 return;
235 }
236 }
237
238 // count number of leading zeros in leading digit of denominator
239 {
240 mpz_dig_t d = den_dig[den_len - 1];
241 while ((d & (1 << (DIG_SIZE - 1))) == 0) {
242 d <<= 1;
243 ++norm_shift;
244 }
245 }
246
247 // normalise denomenator (leading bit of leading digit is 1)
248 for (mpz_dig_t *den = den_dig, carry = 0; den < den_dig + den_len; ++den) {
249 mpz_dig_t d = *den;
250 *den = ((d << norm_shift) | carry) & DIG_MASK;
251 carry = d >> (DIG_SIZE - norm_shift);
252 }
253
254 // now need to shift numerator by same amount as denominator
255 // first, increase length of numerator in case we need more room to shift
256 num_dig[*num_len] = 0;
257 ++(*num_len);
258 for (mpz_dig_t *num = num_dig, carry = 0; num < num_dig + *num_len; ++num) {
259 mpz_dig_t n = *num;
260 *num = ((n << norm_shift) | carry) & DIG_MASK;
261 carry = n >> (DIG_SIZE - norm_shift);
262 }
263
264 // cache the leading digit of the denominator
265 lead_den_digit = den_dig[den_len - 1];
266
267 // point num_dig to last digit in numerator
268 num_dig += *num_len - 1;
269
270 // calculate number of digits in quotient
271 *quo_len = *num_len - den_len;
272
273 // point to last digit to store for quotient
274 quo_dig += *quo_len - 1;
275
276 // keep going while we have enough digits to divide
277 while (*num_len > den_len) {
278 mpz_dbl_dig_t quo = (*num_dig << DIG_SIZE) | num_dig[-1];
279
280 // get approximate quotient
281 quo /= lead_den_digit;
282
283 // multiply quo by den and subtract from num get remainder
284 {
285 mpz_dbl_dig_signed_t borrow = 0;
286
287 for (mpz_dig_t *n = num_dig - den_len, *d = den_dig; n < num_dig; ++n, ++d) {
288 borrow += *n - quo * *d; // will overflow if DIG_SIZE >= 16
289 *n = borrow & DIG_MASK;
290 borrow >>= DIG_SIZE;
291 }
292 borrow += *num_dig; // will overflow if DIG_SIZE >= 16
293 *num_dig = borrow & DIG_MASK;
294 borrow >>= DIG_SIZE;
295
296 // adjust quotient if it is too big
297 for (; borrow != 0; --quo) {
298 mpz_dbl_dig_t carry = 0;
299 for (mpz_dig_t *n = num_dig - den_len, *d = den_dig; n < num_dig; ++n, ++d) {
300 carry += *n + *d;
301 *n = carry & DIG_MASK;
302 carry >>= DIG_SIZE;
303 }
304 carry += *num_dig;
305 *num_dig = carry & DIG_MASK;
306 carry >>= DIG_SIZE;
307
308 borrow += carry;
309 }
310 }
311
312 // store this digit of the quotient
313 *quo_dig = quo & DIG_MASK;
314 --quo_dig;
315
316 // move down to next digit of numerator
317 --num_dig;
318 --(*num_len);
319 }
320
321 // unnormalise denomenator
322 for (mpz_dig_t *den = den_dig + den_len - 1, carry = 0; den >= den_dig; --den) {
323 mpz_dig_t d = *den;
324 *den = ((d >> norm_shift) | carry) & DIG_MASK;
325 carry = d << (DIG_SIZE - norm_shift);
326 }
327
328 // unnormalise numerator (remainder now)
329 for (mpz_dig_t *num = orig_num_dig + *num_len - 1, carry = 0; num >= orig_num_dig; --num) {
330 mpz_dig_t n = *num;
331 *num = ((n >> norm_shift) | carry) & DIG_MASK;
332 carry = n << (DIG_SIZE - norm_shift);
333 }
334
335 // strip trailing zeros
336
337 while (*quo_len > 0 && orig_quo_dig[*quo_len - 1] == 0) {
338 --(*quo_len);
339 }
340
341 while (*num_len > 0 && orig_num_dig[*num_len - 1] == 0) {
342 --(*num_len);
343 }
344}
345
346#define MIN_ALLOC (4)
347#define ALIGN_ALLOC (2)
Damien Georgeaca14122014-02-24 21:32:52 +0000348#define NUM_DIG_FOR_INT (sizeof(machine_int_t) * 8 / DIG_SIZE + 1)
Damien George438c88d2014-02-22 19:25:23 +0000349
350static const uint log_base2_floor[] = {
351 0,
352 0, 1, 1, 2,
353 2, 2, 2, 3,
354 3, 3, 3, 3,
355 3, 3, 3, 4,
356 4, 4, 4, 4,
357 4, 4, 4, 4,
358 4, 4, 4, 4,
359 4, 4, 4, 5
360};
361
Damien Georgeaca14122014-02-24 21:32:52 +0000362bool mpz_int_is_sml_int(machine_int_t i) {
Damien George438c88d2014-02-22 19:25:23 +0000363 return -(1 << DIG_SIZE) < i && i < (1 << DIG_SIZE);
364}
365
366void mpz_init_zero(mpz_t *z) {
367 z->alloc = 0;
368 z->neg = 0;
369 z->len = 0;
370 z->dig = NULL;
371}
372
373void mpz_init_from_int(mpz_t *z, machine_int_t val) {
374 mpz_init_zero(z);
375 mpz_set_from_int(z, val);
376}
377
378void mpz_deinit(mpz_t *z) {
379 if (z != NULL) {
380 m_del(mpz_dig_t, z->dig, z->alloc);
381 }
382}
383
384mpz_t *mpz_zero(void) {
385 mpz_t *z = m_new_obj(mpz_t);
386 mpz_init_zero(z);
387 return z;
388}
389
390mpz_t *mpz_from_int(machine_int_t val) {
391 mpz_t *z = mpz_zero();
392 mpz_set_from_int(z, val);
393 return z;
394}
395
396mpz_t *mpz_from_str(const char *str, uint len, bool neg, uint base) {
397 mpz_t *z = mpz_zero();
398 mpz_set_from_str(z, str, len, neg, base);
399 return z;
400}
401
402void mpz_free(mpz_t *z) {
403 if (z != NULL) {
404 m_del(mpz_dig_t, z->dig, z->alloc);
405 m_del_obj(mpz_t, z);
406 }
407}
408
409STATIC void mpz_need_dig(mpz_t *z, uint need) {
410 uint alloc;
411 if (need < MIN_ALLOC) {
412 alloc = MIN_ALLOC;
413 } else {
414 alloc = (need + ALIGN_ALLOC) & (~(ALIGN_ALLOC - 1));
415 }
416
417 if (z->dig == NULL || z->alloc < alloc) {
418 z->dig = m_renew(mpz_dig_t, z->dig, z->alloc, alloc);
419 z->alloc = alloc;
420 }
421}
422
423mpz_t *mpz_clone(const mpz_t *src) {
424 mpz_t *z = m_new_obj(mpz_t);
425 z->alloc = src->alloc;
426 z->neg = src->neg;
427 z->len = src->len;
428 if (src->dig == NULL) {
429 z->dig = NULL;
430 } else {
431 z->dig = m_new(mpz_dig_t, z->alloc);
432 memcpy(z->dig, src->dig, src->alloc * sizeof(mpz_dig_t));
433 }
434 return z;
435}
436
437void mpz_set(mpz_t *dest, const mpz_t *src) {
438 mpz_need_dig(dest, src->len);
439 dest->neg = src->neg;
440 dest->len = src->len;
441 memcpy(dest->dig, src->dig, src->len * sizeof(mpz_dig_t));
442}
443
444void mpz_set_from_int(mpz_t *z, machine_int_t val) {
445 mpz_need_dig(z, NUM_DIG_FOR_INT);
446
447 if (val < 0) {
448 z->neg = 1;
449 val = -val;
450 } else {
451 z->neg = 0;
452 }
453
454 z->len = 0;
455 while (val > 0) {
456 z->dig[z->len++] = val & DIG_MASK;
457 val >>= DIG_SIZE;
458 }
459}
460
461// returns number of bytes from str that were processed
462uint mpz_set_from_str(mpz_t *z, const char *str, uint len, bool neg, uint base) {
463 assert(base < 36);
464
465 const char *cur = str;
466 const char *top = str + len;
467
468 mpz_need_dig(z, len * 8 / DIG_SIZE + 1);
469
470 if (neg) {
471 z->neg = 1;
472 } else {
473 z->neg = 0;
474 }
475
476 z->len = 0;
477 for (; cur < top; ++cur) { // XXX UTF8 next char
478 //uint v = char_to_numeric(cur#); // XXX UTF8 get char
479 uint v = *cur;
480 if ('0' <= v && v <= '9') {
481 v -= '0';
482 } else if ('A' <= v && v <= 'Z') {
483 v -= 'A' - 10;
484 } else if ('a' <= v && v <= 'z') {
485 v -= 'a' - 10;
486 } else {
487 break;
488 }
489 if (v >= base) {
490 break;
491 }
492 z->len = mpn_mul_dig_add_dig(z->dig, z->len, base, v);
493 }
494
495 return cur - str;
496}
497
498bool mpz_is_zero(const mpz_t *z) {
499 return z->len == 0;
500}
501
502bool mpz_is_pos(const mpz_t *z) {
503 return z->len > 0 && z->neg == 0;
504}
505
506bool mpz_is_neg(const mpz_t *z) {
507 return z->len > 0 && z->neg != 0;
508}
509
510bool mpz_is_odd(const mpz_t *z) {
511 return z->len > 0 && (z->dig[0] & 1) != 0;
512}
513
514bool mpz_is_even(const mpz_t *z) {
515 return z->len == 0 || (z->dig[0] & 1) == 0;
516}
517
518int mpz_cmp(const mpz_t *z1, const mpz_t *z2) {
519 int cmp = z2->neg - z1->neg;
520 if (cmp != 0) {
521 return cmp;
522 }
523 cmp = mpn_cmp(z1->dig, z1->len, z2->dig, z2->len);
524 if (z1->neg != 0) {
525 cmp = -cmp;
526 }
527 return cmp;
528}
529
Damien Georgeaca14122014-02-24 21:32:52 +0000530int mpz_cmp_sml_int(const mpz_t *z, machine_int_t sml_int) {
Damien George438c88d2014-02-22 19:25:23 +0000531 int cmp;
532 if (z->neg == 0) {
533 if (sml_int < 0) return 1;
534 if (sml_int == 0) {
535 if (z->len == 0) return 0;
536 return 1;
537 }
538 if (z->len == 0) return -1;
539 assert(sml_int < (1 << DIG_SIZE));
540 if (z->len != 1) return 1;
541 cmp = z->dig[0] - sml_int;
542 } else {
543 if (sml_int > 0) return -1;
544 if (sml_int == 0) {
545 if (z->len == 0) return 0;
546 return -1;
547 }
548 if (z->len == 0) return 1;
549 assert(sml_int > -(1 << DIG_SIZE));
550 if (z->len != 1) return -1;
551 cmp = -z->dig[0] - sml_int;
552 }
553 if (cmp < 0) return -1;
554 if (cmp > 0) return 1;
555 return 0;
556}
557
Damien George438c88d2014-02-22 19:25:23 +0000558#if 0
559these functions are unused
560
561/* returns abs(z)
562*/
563mpz_t *mpz_abs(const mpz_t *z) {
564 mpz_t *z2 = mpz_clone(z);
565 z2->neg = 0;
566 return z2;
567}
568
569/* returns -z
570*/
571mpz_t *mpz_neg(const mpz_t *z) {
572 mpz_t *z2 = mpz_clone(z);
573 z2->neg = 1 - z2->neg;
574 return z2;
575}
576
577/* returns lhs + rhs
578 can have lhs, rhs the same
579*/
580mpz_t *mpz_add(const mpz_t *lhs, const mpz_t *rhs) {
581 mpz_t *z = mpz_zero();
582 mpz_add_inpl(z, lhs, rhs);
583 return z;
584}
585
586/* returns lhs - rhs
587 can have lhs, rhs the same
588*/
589mpz_t *mpz_sub(const mpz_t *lhs, const mpz_t *rhs) {
590 mpz_t *z = mpz_zero();
591 mpz_sub_inpl(z, lhs, rhs);
592 return z;
593}
594
595/* returns lhs * rhs
596 can have lhs, rhs the same
597*/
598mpz_t *mpz_mul(const mpz_t *lhs, const mpz_t *rhs) {
599 mpz_t *z = mpz_zero();
600 mpz_mul_inpl(z, lhs, rhs);
601 return z;
602}
603
604/* returns lhs ** rhs
605 can have lhs, rhs the same
606*/
607mpz_t *mpz_pow(const mpz_t *lhs, const mpz_t *rhs) {
608 mpz_t *z = mpz_zero();
609 mpz_pow_inpl(z, lhs, rhs);
610 return z;
611}
612#endif
613
614/* computes dest = abs(z)
615 can have dest, z the same
616*/
617void mpz_abs_inpl(mpz_t *dest, const mpz_t *z) {
618 if (dest != z) {
619 mpz_set(dest, z);
620 }
621 dest->neg = 0;
622}
623
624/* computes dest = -z
625 can have dest, z the same
626*/
627void mpz_neg_inpl(mpz_t *dest, const mpz_t *z) {
628 if (dest != z) {
629 mpz_set(dest, z);
630 }
631 dest->neg = 1 - dest->neg;
632}
633
Damien Georgec5ac2ac2014-02-26 16:56:30 +0000634#if 0
635not finished
636/* computes dest = lhs << rhs
637 can have dest, lhs the same
638*/
639void mpz_shl_inpl(mpz_t *dest, const mpz_t *lhs, machine_int_t rhs) {
640 if (dest != lhs) {
641 mpz_set(dest, lhs);
642 }
643
644 if (dest.len == 0 || rhs == 0) {
645 return dest;
646 }
647
648 if (rhs < 0) {
649 dest->len = mpn_shr(dest->len, dest->dig, -rhs);
650 } else {
651 dest->len = mpn_shl(dest->len, dest->dig, rhs);
652 }
653
654 return dest;
655}
656
657/* computes dest = lhs >> rhs
658 can have dest, lhs the same
659*/
660void mpz_shr_inpl(mpz_t *dest, const mpz_t *lhs, machine_int_t rhs) {
661 if (dest != lhs) {
662 mpz_set(dest, lhs);
663 }
664
665 if (dest.len == 0 || rhs == 0) {
666 return dest;
667 }
668
669 if (rhs < 0) {
670 dest->len = mpn_shl(dest->len, dest->dig, -rhs);
671 } else {
672 dest->len = mpn_shr(dest->len, dest->dig, rhs);
673 }
674
675 return dest;
676}
677#endif
678
Damien George438c88d2014-02-22 19:25:23 +0000679/* computes dest = lhs + rhs
680 can have dest, lhs, rhs the same
681*/
682void mpz_add_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
683 if (mpn_cmp(lhs->dig, lhs->len, rhs->dig, rhs->len) < 0) {
684 const mpz_t *temp = lhs;
685 lhs = rhs;
686 rhs = temp;
687 }
688
689 if (lhs->neg == rhs->neg) {
690 mpz_need_dig(dest, lhs->len + 1);
691 dest->len = mpn_add(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
692 } else {
693 mpz_need_dig(dest, lhs->len);
694 dest->len = mpn_sub(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
695 }
696
697 dest->neg = lhs->neg;
698}
699
700/* computes dest = lhs - rhs
701 can have dest, lhs, rhs the same
702*/
703void mpz_sub_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
704 bool neg = false;
705
706 if (mpn_cmp(lhs->dig, lhs->len, rhs->dig, rhs->len) < 0) {
707 const mpz_t *temp = lhs;
708 lhs = rhs;
709 rhs = temp;
710 neg = true;
711 }
712
713 if (lhs->neg != rhs->neg) {
714 mpz_need_dig(dest, lhs->len + 1);
715 dest->len = mpn_add(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
716 } else {
717 mpz_need_dig(dest, lhs->len);
718 dest->len = mpn_sub(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
719 }
720
721 if (neg) {
722 dest->neg = 1 - lhs->neg;
723 } else {
724 dest->neg = lhs->neg;
725 }
726}
727
728/* computes dest = lhs * rhs
729 can have dest, lhs, rhs the same
730*/
731void mpz_mul_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs)
732{
733 if (lhs->len == 0 || rhs->len == 0) {
Damien Georgec5ac2ac2014-02-26 16:56:30 +0000734 mpz_set_from_int(dest, 0);
735 return;
Damien George438c88d2014-02-22 19:25:23 +0000736 }
737
738 mpz_t *temp = NULL;
739 if (lhs == dest) {
740 lhs = temp = mpz_clone(lhs);
741 if (rhs == dest) {
742 rhs = lhs;
743 }
744 } else if (rhs == dest) {
745 rhs = temp = mpz_clone(rhs);
746 }
747
748 mpz_need_dig(dest, lhs->len + rhs->len); // min mem l+r-1, max mem l+r
749 memset(dest->dig, 0, dest->alloc * sizeof(mpz_dig_t));
750 dest->len = mpn_mul(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
751
752 if (lhs->neg == rhs->neg) {
753 dest->neg = 0;
754 } else {
755 dest->neg = 1;
756 }
757
758 mpz_free(temp);
759}
760
761/* computes dest = lhs ** rhs
762 can have dest, lhs, rhs the same
763*/
764void mpz_pow_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
765 if (lhs->len == 0 || rhs->neg != 0) {
Damien Georgec5ac2ac2014-02-26 16:56:30 +0000766 mpz_set_from_int(dest, 0);
767 return;
Damien George438c88d2014-02-22 19:25:23 +0000768 }
769
770 if (rhs->len == 0) {
Damien Georgec5ac2ac2014-02-26 16:56:30 +0000771 mpz_set_from_int(dest, 1);
772 return;
Damien George438c88d2014-02-22 19:25:23 +0000773 }
774
775 mpz_t *x = mpz_clone(lhs);
776 mpz_t *n = mpz_clone(rhs);
777
778 mpz_set_from_int(dest, 1);
779
780 while (n->len > 0) {
781 if (mpz_is_odd(n)) {
782 mpz_mul_inpl(dest, dest, x);
783 }
784 mpz_mul_inpl(x, x, x);
785 n->len = mpn_shr(n->dig, n->dig, n->len, 1);
786 }
787
788 mpz_free(x);
789 mpz_free(n);
790}
791
792/* computes gcd(z1, z2)
793 based on Knuth's modified gcd algorithm (I think?)
794 gcd(z1, z2) >= 0
795 gcd(0, 0) = 0
796 gcd(z, 0) = abs(z)
797*/
798mpz_t *mpz_gcd(const mpz_t *z1, const mpz_t *z2) {
799 if (z1->len == 0) {
800 mpz_t *a = mpz_clone(z2);
801 a->neg = 0;
802 return a;
803 } else if (z2->len == 0) {
804 mpz_t *a = mpz_clone(z1);
805 a->neg = 0;
806 return a;
807 }
808
809 mpz_t *a = mpz_clone(z1);
810 mpz_t *b = mpz_clone(z2);
811 mpz_t c; mpz_init_zero(&c);
812 a->neg = 0;
813 b->neg = 0;
814
815 for (;;) {
816 if (mpz_cmp(a, b) < 0) {
817 if (a->len == 0) {
818 mpz_free(a);
819 mpz_deinit(&c);
820 return b;
821 }
822 mpz_t *t = a; a = b; b = t;
823 }
824 if (!(b->len >= 2 || (b->len == 1 && b->dig[0] > 1))) { // compute b > 0; could be mpz_cmp_small_int(b, 1) > 0
825 break;
826 }
827 mpz_set(&c, b);
828 do {
829 mpz_add_inpl(&c, &c, &c);
830 } while (mpz_cmp(&c, a) <= 0);
831 c.len = mpn_shr(c.dig, c.dig, c.len, 1);
832 mpz_sub_inpl(a, a, &c);
833 }
834
835 mpz_deinit(&c);
836
837 if (b->len == 1 && b->dig[0] == 1) { // compute b == 1; could be mpz_cmp_small_int(b, 1) == 0
838 mpz_free(a);
839 return b;
840 } else {
841 mpz_free(b);
842 return a;
843 }
844}
845
846/* computes lcm(z1, z2)
847 = abs(z1) / gcd(z1, z2) * abs(z2)
848 lcm(z1, z1) >= 0
849 lcm(0, 0) = 0
850 lcm(z, 0) = 0
851*/
852mpz_t *mpz_lcm(const mpz_t *z1, const mpz_t *z2)
853{
854 if (z1->len == 0 || z2->len == 0)
855 return mpz_zero();
856
857 mpz_t *gcd = mpz_gcd(z1, z2);
858 mpz_t *quo = mpz_zero();
859 mpz_t *rem = mpz_zero();
860 mpz_divmod_inpl(quo, rem, z1, gcd);
861 mpz_mul_inpl(rem, quo, z2);
862 mpz_free(gcd);
863 mpz_free(quo);
864 rem->neg = 0;
865 return rem;
866}
867
868/* computes new integers in quo and rem such that:
869 quo * rhs + rem = lhs
870 0 <= rem < rhs
871 can have lhs, rhs the same
872*/
873void mpz_divmod(const mpz_t *lhs, const mpz_t *rhs, mpz_t **quo, mpz_t **rem) {
874 *quo = mpz_zero();
875 *rem = mpz_zero();
876 mpz_divmod_inpl(*quo, *rem, lhs, rhs);
877}
878
879/* computes new integers in quo and rem such that:
880 quo * rhs + rem = lhs
881 0 <= rem < rhs
882 can have lhs, rhs the same
883*/
884void mpz_divmod_inpl(mpz_t *dest_quo, mpz_t *dest_rem, const mpz_t *lhs, const mpz_t *rhs) {
885 if (rhs->len == 0) {
886 mpz_set_from_int(dest_quo, 0);
887 mpz_set_from_int(dest_rem, 0);
888 return;
889 }
890
891 mpz_need_dig(dest_quo, lhs->len + 1); // +1 necessary?
892 memset(dest_quo->dig, 0, (lhs->len + 1) * sizeof(mpz_dig_t));
893 dest_quo->len = 0;
894 mpz_need_dig(dest_rem, lhs->len + 1); // +1 necessary?
895 mpz_set(dest_rem, lhs);
896 //rhs->dig[rhs->len] = 0;
897 mpn_div(dest_rem->dig, &dest_rem->len, rhs->dig, rhs->len, dest_quo->dig, &dest_quo->len);
898
899 if (lhs->neg != rhs->neg) {
900 dest_quo->neg = 1;
901 }
902}
903
904#if 0
905these functions are unused
906
907/* computes floor(lhs / rhs)
908 can have lhs, rhs the same
909*/
910mpz_t *mpz_div(const mpz_t *lhs, const mpz_t *rhs) {
911 mpz_t *quo = mpz_zero();
912 mpz_t rem; mpz_init_zero(&rem);
913 mpz_divmod_inpl(quo, &rem, lhs, rhs);
914 mpz_deinit(&rem);
915 return quo;
916}
917
918/* computes lhs % rhs ( >= 0)
919 can have lhs, rhs the same
920*/
921mpz_t *mpz_mod(const mpz_t *lhs, const mpz_t *rhs) {
922 mpz_t quo; mpz_init_zero(&quo);
923 mpz_t *rem = mpz_zero();
924 mpz_divmod_inpl(&quo, rem, lhs, rhs);
925 mpz_deinit(&quo);
926 return rem;
927}
928#endif
929
Damien Georgeaca14122014-02-24 21:32:52 +0000930machine_int_t mpz_as_int(const mpz_t *i) {
931 machine_int_t val = 0;
Damien George438c88d2014-02-22 19:25:23 +0000932 mpz_dig_t *d = i->dig + i->len;
933
934 while (--d >= i->dig)
935 {
Damien Georgeaca14122014-02-24 21:32:52 +0000936 machine_int_t oldval = val;
Damien George438c88d2014-02-22 19:25:23 +0000937 val = (val << DIG_SIZE) | *d;
938 if (val < oldval)
939 {
940 if (i->neg == 0) {
941 return 0x7fffffff;
942 } else {
943 return 0x80000000;
944 }
945 }
946 }
947
948 if (i->neg != 0) {
949 val = -val;
950 }
951
952 return val;
953}
954
955machine_float_t mpz_as_float(const mpz_t *i) {
956 machine_float_t val = 0;
957 mpz_dig_t *d = i->dig + i->len;
958
959 while (--d >= i->dig) {
960 val = val * (1 << DIG_SIZE) + *d;
961 }
962
963 if (i->neg != 0) {
964 val = -val;
965 }
966
967 return val;
968}
969
970uint mpz_as_str_size(const mpz_t *i, uint base) {
971 if (base < 2 || base > 32) {
972 return 0;
973 }
974
975 return i->len * DIG_SIZE / log_base2_floor[base] + 2 + 1; // +1 for null byte termination
976}
977
978char *mpz_as_str(const mpz_t *i, uint base) {
979 char *s = m_new(char, mpz_as_str_size(i, base));
980 mpz_as_str_inpl(i, base, s);
981 return s;
982}
983
984// assumes enough space as calculated by mpz_as_str_size
985// returns length of string, not including null byte
986uint mpz_as_str_inpl(const mpz_t *i, uint base, char *str) {
987 if (str == NULL || base < 2 || base > 32) {
988 str[0] = 0;
989 return 0;
990 }
991
992 uint ilen = i->len;
993
994 if (ilen == 0) {
995 str[0] = '0';
996 str[1] = 0;
997 return 1;
998 }
999
1000 // make a copy of mpz digits
1001 mpz_dig_t *dig = m_new(mpz_dig_t, ilen);
1002 memcpy(dig, i->dig, ilen * sizeof(mpz_dig_t));
1003
1004 // convert
1005 char *s = str;
1006 bool done;
1007 do {
1008 mpz_dig_t *d = dig + ilen;
1009 mpz_dbl_dig_t a = 0;
1010
1011 // compute next remainder
1012 while (--d >= dig) {
1013 a = (a << DIG_SIZE) | *d;
1014 *d = a / base;
1015 a %= base;
1016 }
1017
1018 // convert to character
1019 a += '0';
1020 if (a > '9') {
1021 a += 'a' - '9' - 1;
1022 }
1023 *s++ = a;
1024
1025 // check if number is zero
1026 done = true;
1027 for (d = dig; d < dig + ilen; ++d) {
1028 if (*d != 0) {
1029 done = false;
1030 break;
1031 }
1032 }
1033 } while (!done);
1034
1035 if (i->neg != 0) {
1036 *s++ = '-';
1037 }
1038
1039 // reverse string
1040 for (char *u = str, *v = s - 1; u < v; ++u, --v) {
1041 char temp = *u;
1042 *u = *v;
1043 *v = temp;
1044 }
1045
1046 s[0] = 0; // null termination
1047
1048 return s - str;
1049}
1050
1051#endif // MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_MPZ