blob: 4e768499c17262d07ecbb4619a45ac0525e3ed72 [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;
100 if (idig[jlen - 1] == 0) {
101 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
Paul Sokolovsky57207b82014-03-23 01:52:36 +0200199/* computes i = j & k
200 returns number of digits in i
201 assumes enough memory in i; assumes normalised j, k; assumes jlen >= klen
202 can have i, j, k pointing to same memory
203*/
Damien Georgeafb1cf72014-09-05 20:37:06 +0100204STATIC 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 +0200205 mpz_dig_t *oidig = idig;
206
Paul Sokolovsky57207b82014-03-23 01:52:36 +0200207 for (; klen > 0; --klen, ++idig, ++jdig, ++kdig) {
208 *idig = *jdig & *kdig;
209 }
210
Damien George561e4252014-05-12 23:27:29 +0100211 // remove trailing zeros
Damien George51fab282014-05-13 22:58:00 +0100212 for (--idig; idig >= oidig && *idig == 0; --idig) {
Paul Sokolovsky57207b82014-03-23 01:52:36 +0200213 }
214
Damien George51fab282014-05-13 22:58:00 +0100215 return idig + 1 - oidig;
Paul Sokolovsky57207b82014-03-23 01:52:36 +0200216}
217
Damien Georgef55cf102014-05-29 15:01:49 +0100218/* computes i = j & -k = j & (~k + 1)
219 returns number of digits in i
220 assumes enough memory in i; assumes normalised j, k
221 can have i, j, k pointing to same memory
222*/
Damien Georgeafb1cf72014-09-05 20:37:06 +0100223STATIC 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 +0100224 mpz_dig_t *oidig = idig;
225 mpz_dbl_dig_t carry = 1;
226
227 for (; jlen > 0 && klen > 0; --jlen, --klen, ++idig, ++jdig, ++kdig) {
228 carry += *kdig ^ DIG_MASK;
229 *idig = (*jdig & carry) & DIG_MASK;
230 carry >>= DIG_SIZE;
231 }
232
233 for (; jlen > 0; --jlen, ++idig, ++jdig) {
234 carry += DIG_MASK;
235 *idig = (*jdig & carry) & DIG_MASK;
236 carry >>= DIG_SIZE;
237 }
238
239 if (carry != 0) {
240 *idig = carry;
241 } else {
242 // remove trailing zeros
243 for (--idig; idig >= oidig && *idig == 0; --idig) {
244 }
245 }
246
247 return idig + 1 - oidig;
248}
249
Paul Sokolovsky57207b82014-03-23 01:52:36 +0200250/* computes i = j | k
251 returns number of digits in i
252 assumes enough memory in i; assumes normalised j, k; assumes jlen >= klen
253 can have i, j, k pointing to same memory
254*/
Damien Georgeafb1cf72014-09-05 20:37:06 +0100255STATIC 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 +0200256 mpz_dig_t *oidig = idig;
257
258 jlen -= klen;
259
260 for (; klen > 0; --klen, ++idig, ++jdig, ++kdig) {
261 *idig = *jdig | *kdig;
262 }
263
264 for (; jlen > 0; --jlen, ++idig, ++jdig) {
265 *idig = *jdig;
266 }
267
268 return idig - oidig;
269}
270
271/* computes i = j ^ k
272 returns number of digits in i
273 assumes enough memory in i; assumes normalised j, k; assumes jlen >= klen
274 can have i, j, k pointing to same memory
275*/
Damien Georgeafb1cf72014-09-05 20:37:06 +0100276STATIC 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 +0200277 mpz_dig_t *oidig = idig;
278
279 jlen -= klen;
280
281 for (; klen > 0; --klen, ++idig, ++jdig, ++kdig) {
282 *idig = *jdig ^ *kdig;
283 }
284
285 for (; jlen > 0; --jlen, ++idig, ++jdig) {
286 *idig = *jdig;
287 }
288
289 return idig - oidig;
290}
291
Damien George438c88d2014-02-22 19:25:23 +0000292/* computes i = i * d1 + d2
293 returns number of digits in i
294 assumes enough memory in i; assumes normalised i; assumes dmul != 0
295*/
Damien Georgeafb1cf72014-09-05 20:37:06 +0100296STATIC 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 +0000297 mpz_dig_t *oidig = idig;
298 mpz_dbl_dig_t carry = dadd;
299
300 for (; ilen > 0; --ilen, ++idig) {
Damien George9a21d2e2014-09-06 17:15:34 +0100301 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 +0000302 *idig = carry & DIG_MASK;
303 carry >>= DIG_SIZE;
304 }
305
306 if (carry != 0) {
307 *idig++ = carry;
308 }
309
310 return idig - oidig;
311}
312
313/* computes i = j * k
314 returns number of digits in i
315 assumes enough memory in i; assumes i is zeroed; assumes normalised j, k
316 can have j, k point to same memory
317*/
Damien Georgeafb1cf72014-09-05 20:37:06 +0100318STATIC 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 +0000319 mpz_dig_t *oidig = idig;
Damien Georgeafb1cf72014-09-05 20:37:06 +0100320 mp_uint_t ilen = 0;
Damien George438c88d2014-02-22 19:25:23 +0000321
322 for (; klen > 0; --klen, ++idig, ++kdig) {
323 mpz_dig_t *id = idig;
324 mpz_dbl_dig_t carry = 0;
325
Damien Georgeafb1cf72014-09-05 20:37:06 +0100326 mp_uint_t jl = jlen;
Damien George438c88d2014-02-22 19:25:23 +0000327 for (mpz_dig_t *jd = jdig; jl > 0; --jl, ++jd, ++id) {
Damien George9a21d2e2014-09-06 17:15:34 +0100328 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 +0000329 *id = carry & DIG_MASK;
330 carry >>= DIG_SIZE;
331 }
332
333 if (carry != 0) {
334 *id++ = carry;
335 }
336
337 ilen = id - oidig;
338 }
339
340 return ilen;
341}
342
343/* natural_div - quo * den + new_num = old_num (ie num is replaced with rem)
344 assumes den != 0
345 assumes num_dig has enough memory to be extended by 1 digit
346 assumes quo_dig has enough memory (as many digits as num)
347 assumes quo_dig is filled with zeros
348 modifies den_dig memory, but restors it to original state at end
349*/
350
Damien George40f3c022014-07-03 13:25:24 +0100351STATIC 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 +0000352 mpz_dig_t *orig_num_dig = num_dig;
353 mpz_dig_t *orig_quo_dig = quo_dig;
354 mpz_dig_t norm_shift = 0;
355 mpz_dbl_dig_t lead_den_digit;
356
357 // handle simple cases
358 {
Damien George42f3de92014-10-03 17:44:14 +0000359 int cmp = mpn_cmp(num_dig, *num_len, den_dig, den_len);
Damien George438c88d2014-02-22 19:25:23 +0000360 if (cmp == 0) {
361 *num_len = 0;
362 quo_dig[0] = 1;
363 *quo_len = 1;
364 return;
365 } else if (cmp < 0) {
366 // numerator remains the same
367 *quo_len = 0;
368 return;
369 }
370 }
371
372 // count number of leading zeros in leading digit of denominator
373 {
374 mpz_dig_t d = den_dig[den_len - 1];
Damien George9a21d2e2014-09-06 17:15:34 +0100375 while ((d & DIG_MSB) == 0) {
Damien George438c88d2014-02-22 19:25:23 +0000376 d <<= 1;
377 ++norm_shift;
378 }
379 }
380
381 // normalise denomenator (leading bit of leading digit is 1)
382 for (mpz_dig_t *den = den_dig, carry = 0; den < den_dig + den_len; ++den) {
383 mpz_dig_t d = *den;
384 *den = ((d << norm_shift) | carry) & DIG_MASK;
385 carry = d >> (DIG_SIZE - norm_shift);
386 }
387
388 // now need to shift numerator by same amount as denominator
389 // first, increase length of numerator in case we need more room to shift
390 num_dig[*num_len] = 0;
391 ++(*num_len);
392 for (mpz_dig_t *num = num_dig, carry = 0; num < num_dig + *num_len; ++num) {
393 mpz_dig_t n = *num;
394 *num = ((n << norm_shift) | carry) & DIG_MASK;
395 carry = n >> (DIG_SIZE - norm_shift);
396 }
397
398 // cache the leading digit of the denominator
399 lead_den_digit = den_dig[den_len - 1];
400
401 // point num_dig to last digit in numerator
402 num_dig += *num_len - 1;
403
404 // calculate number of digits in quotient
405 *quo_len = *num_len - den_len;
406
407 // point to last digit to store for quotient
408 quo_dig += *quo_len - 1;
409
410 // keep going while we have enough digits to divide
411 while (*num_len > den_len) {
Damien George9a21d2e2014-09-06 17:15:34 +0100412 mpz_dbl_dig_t quo = ((mpz_dbl_dig_t)*num_dig << DIG_SIZE) | num_dig[-1];
Damien George438c88d2014-02-22 19:25:23 +0000413
414 // get approximate quotient
415 quo /= lead_den_digit;
416
Damien George9a21d2e2014-09-06 17:15:34 +0100417 // Multiply quo by den and subtract from num to get remainder.
418 // We have different code here to handle different compile-time
419 // configurations of mpz:
420 //
421 // 1. DIG_SIZE is stricly less than half the number of bits
422 // available in mpz_dbl_dig_t. In this case we can use a
423 // slightly more optimal (in time and space) routine that
424 // uses the extra bits in mpz_dbl_dig_signed_t to store a
425 // sign bit.
426 //
427 // 2. DIG_SIZE is exactly half the number of bits available in
428 // mpz_dbl_dig_t. In this (common) case we need to be careful
429 // not to overflow the borrow variable. And the shifting of
430 // borrow needs some special logic (it's a shift right with
431 // round up).
432
433 if (DIG_SIZE < 8 * sizeof(mpz_dbl_dig_t) / 2) {
Damien George438c88d2014-02-22 19:25:23 +0000434 mpz_dbl_dig_signed_t borrow = 0;
435
436 for (mpz_dig_t *n = num_dig - den_len, *d = den_dig; n < num_dig; ++n, ++d) {
Damien George9a21d2e2014-09-06 17:15:34 +0100437 borrow += (mpz_dbl_dig_t)*n - (mpz_dbl_dig_t)quo * (mpz_dbl_dig_t)*d; // will overflow if DIG_SIZE >= 8*sizeof(mpz_dbl_dig_t)/2
Damien George438c88d2014-02-22 19:25:23 +0000438 *n = borrow & DIG_MASK;
439 borrow >>= DIG_SIZE;
440 }
Damien George9a21d2e2014-09-06 17:15:34 +0100441 borrow += *num_dig; // will overflow if DIG_SIZE >= 8*sizeof(mpz_dbl_dig_t)/2
Damien George438c88d2014-02-22 19:25:23 +0000442 *num_dig = borrow & DIG_MASK;
443 borrow >>= DIG_SIZE;
444
445 // adjust quotient if it is too big
446 for (; borrow != 0; --quo) {
447 mpz_dbl_dig_t carry = 0;
448 for (mpz_dig_t *n = num_dig - den_len, *d = den_dig; n < num_dig; ++n, ++d) {
Damien George9a21d2e2014-09-06 17:15:34 +0100449 carry += (mpz_dbl_dig_t)*n + (mpz_dbl_dig_t)*d;
Damien George438c88d2014-02-22 19:25:23 +0000450 *n = carry & DIG_MASK;
451 carry >>= DIG_SIZE;
452 }
453 carry += *num_dig;
454 *num_dig = carry & DIG_MASK;
455 carry >>= DIG_SIZE;
456
457 borrow += carry;
458 }
Damien George9a21d2e2014-09-06 17:15:34 +0100459 } else { // DIG_SIZE == 8 * sizeof(mpz_dbl_dig_t) / 2
460 mpz_dbl_dig_t borrow = 0;
461
462 for (mpz_dig_t *n = num_dig - den_len, *d = den_dig; n < num_dig; ++n, ++d) {
463 mpz_dbl_dig_t x = (mpz_dbl_dig_t)quo * (mpz_dbl_dig_t)(*d);
464 if (x >= *n || *n - x <= borrow) {
465 borrow += (mpz_dbl_dig_t)x - (mpz_dbl_dig_t)*n;
466 *n = (-borrow) & DIG_MASK;
467 borrow = (borrow >> DIG_SIZE) + ((borrow & DIG_MASK) == 0 ? 0 : 1); // shift-right with round-up
468 } else {
469 *n = ((mpz_dbl_dig_t)*n - (mpz_dbl_dig_t)x - (mpz_dbl_dig_t)borrow) & DIG_MASK;
470 borrow = 0;
471 }
472 }
473 if (borrow >= *num_dig) {
474 borrow -= (mpz_dbl_dig_t)*num_dig;
475 *num_dig = (-borrow) & DIG_MASK;
476 borrow = (borrow >> DIG_SIZE) + ((borrow & DIG_MASK) == 0 ? 0 : 1); // shift-right with round-up
477 } else {
478 *num_dig = (*num_dig - borrow) & DIG_MASK;
479 borrow = 0;
480 }
481
482 // adjust quotient if it is too big
483 for (; borrow != 0; --quo) {
484 mpz_dbl_dig_t carry = 0;
485 for (mpz_dig_t *n = num_dig - den_len, *d = den_dig; n < num_dig; ++n, ++d) {
486 carry += (mpz_dbl_dig_t)*n + (mpz_dbl_dig_t)*d;
487 *n = carry & DIG_MASK;
488 carry >>= DIG_SIZE;
489 }
490 carry += (mpz_dbl_dig_t)*num_dig;
491 *num_dig = carry & DIG_MASK;
492 carry >>= DIG_SIZE;
493
494 //assert(borrow >= carry); // enable this to check the logic
495 borrow -= carry;
496 }
Damien George438c88d2014-02-22 19:25:23 +0000497 }
498
499 // store this digit of the quotient
500 *quo_dig = quo & DIG_MASK;
501 --quo_dig;
502
503 // move down to next digit of numerator
504 --num_dig;
505 --(*num_len);
506 }
507
508 // unnormalise denomenator
509 for (mpz_dig_t *den = den_dig + den_len - 1, carry = 0; den >= den_dig; --den) {
510 mpz_dig_t d = *den;
511 *den = ((d >> norm_shift) | carry) & DIG_MASK;
512 carry = d << (DIG_SIZE - norm_shift);
513 }
514
515 // unnormalise numerator (remainder now)
516 for (mpz_dig_t *num = orig_num_dig + *num_len - 1, carry = 0; num >= orig_num_dig; --num) {
517 mpz_dig_t n = *num;
518 *num = ((n >> norm_shift) | carry) & DIG_MASK;
519 carry = n << (DIG_SIZE - norm_shift);
520 }
521
522 // strip trailing zeros
523
524 while (*quo_len > 0 && orig_quo_dig[*quo_len - 1] == 0) {
525 --(*quo_len);
526 }
527
528 while (*num_len > 0 && orig_num_dig[*num_len - 1] == 0) {
529 --(*num_len);
530 }
531}
532
Damien George06201ff2014-03-01 19:50:50 +0000533#define MIN_ALLOC (2)
Damien George438c88d2014-02-22 19:25:23 +0000534
Damien George1c70cbf2014-08-30 00:38:16 +0100535STATIC const uint8_t log_base2_floor[] = {
Damien George438c88d2014-02-22 19:25:23 +0000536 0,
537 0, 1, 1, 2,
538 2, 2, 2, 3,
539 3, 3, 3, 3,
540 3, 3, 3, 4,
541 4, 4, 4, 4,
542 4, 4, 4, 4,
543 4, 4, 4, 4,
544 4, 4, 4, 5
545};
546
Damien George438c88d2014-02-22 19:25:23 +0000547void mpz_init_zero(mpz_t *z) {
Damien George438c88d2014-02-22 19:25:23 +0000548 z->neg = 0;
Damien George06201ff2014-03-01 19:50:50 +0000549 z->fixed_dig = 0;
550 z->alloc = 0;
Damien George438c88d2014-02-22 19:25:23 +0000551 z->len = 0;
552 z->dig = NULL;
553}
554
Damien George40f3c022014-07-03 13:25:24 +0100555void mpz_init_from_int(mpz_t *z, mp_int_t val) {
Damien George438c88d2014-02-22 19:25:23 +0000556 mpz_init_zero(z);
557 mpz_set_from_int(z, val);
558}
559
Damien Georgeafb1cf72014-09-05 20:37:06 +0100560void 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 +0000561 z->neg = 0;
562 z->fixed_dig = 1;
563 z->alloc = alloc;
564 z->len = 0;
565 z->dig = dig;
566 mpz_set_from_int(z, val);
567}
568
Damien George438c88d2014-02-22 19:25:23 +0000569void mpz_deinit(mpz_t *z) {
Damien George06201ff2014-03-01 19:50:50 +0000570 if (z != NULL && !z->fixed_dig) {
Damien George438c88d2014-02-22 19:25:23 +0000571 m_del(mpz_dig_t, z->dig, z->alloc);
572 }
573}
574
575mpz_t *mpz_zero(void) {
576 mpz_t *z = m_new_obj(mpz_t);
577 mpz_init_zero(z);
578 return z;
579}
580
Damien George40f3c022014-07-03 13:25:24 +0100581mpz_t *mpz_from_int(mp_int_t val) {
Damien George438c88d2014-02-22 19:25:23 +0000582 mpz_t *z = mpz_zero();
583 mpz_set_from_int(z, val);
584 return z;
585}
586
Damien George95307432014-09-10 22:10:33 +0100587mpz_t *mpz_from_ll(long long val, bool is_signed) {
Damien Georgebb4a43f2014-03-12 15:36:06 +0000588 mpz_t *z = mpz_zero();
Damien George95307432014-09-10 22:10:33 +0100589 mpz_set_from_ll(z, val, is_signed);
Damien Georgebb4a43f2014-03-12 15:36:06 +0000590 return z;
591}
592
David Steinberg6e0b6d02015-01-02 12:39:22 +0000593#if MICROPY_PY_BUILTINS_FLOAT
594mpz_t *mpz_from_float(mp_float_t val) {
595 mpz_t *z = mpz_zero();
596 mpz_set_from_float(z, val);
597 return z;
598}
599#endif
600
Damien Georgeafb1cf72014-09-05 20:37:06 +0100601mpz_t *mpz_from_str(const char *str, mp_uint_t len, bool neg, mp_uint_t base) {
Damien George438c88d2014-02-22 19:25:23 +0000602 mpz_t *z = mpz_zero();
603 mpz_set_from_str(z, str, len, neg, base);
604 return z;
605}
606
607void mpz_free(mpz_t *z) {
608 if (z != NULL) {
609 m_del(mpz_dig_t, z->dig, z->alloc);
610 m_del_obj(mpz_t, z);
611 }
612}
613
Damien Georgeafb1cf72014-09-05 20:37:06 +0100614STATIC void mpz_need_dig(mpz_t *z, mp_uint_t need) {
Damien George438c88d2014-02-22 19:25:23 +0000615 if (need < MIN_ALLOC) {
Damien George06201ff2014-03-01 19:50:50 +0000616 need = MIN_ALLOC;
Damien George438c88d2014-02-22 19:25:23 +0000617 }
618
Damien George06201ff2014-03-01 19:50:50 +0000619 if (z->dig == NULL || z->alloc < need) {
620 if (z->fixed_dig) {
621 // cannot reallocate fixed buffers
622 assert(0);
623 return;
624 }
625 z->dig = m_renew(mpz_dig_t, z->dig, z->alloc, need);
626 z->alloc = need;
Damien George438c88d2014-02-22 19:25:23 +0000627 }
628}
629
630mpz_t *mpz_clone(const mpz_t *src) {
631 mpz_t *z = m_new_obj(mpz_t);
Damien George438c88d2014-02-22 19:25:23 +0000632 z->neg = src->neg;
Damien George06201ff2014-03-01 19:50:50 +0000633 z->fixed_dig = 0;
634 z->alloc = src->alloc;
Damien George438c88d2014-02-22 19:25:23 +0000635 z->len = src->len;
636 if (src->dig == NULL) {
637 z->dig = NULL;
638 } else {
639 z->dig = m_new(mpz_dig_t, z->alloc);
640 memcpy(z->dig, src->dig, src->alloc * sizeof(mpz_dig_t));
641 }
642 return z;
643}
644
Damien George06201ff2014-03-01 19:50:50 +0000645/* sets dest = src
646 can have dest, src the same
647*/
Damien George438c88d2014-02-22 19:25:23 +0000648void mpz_set(mpz_t *dest, const mpz_t *src) {
649 mpz_need_dig(dest, src->len);
650 dest->neg = src->neg;
651 dest->len = src->len;
652 memcpy(dest->dig, src->dig, src->len * sizeof(mpz_dig_t));
653}
654
Damien George40f3c022014-07-03 13:25:24 +0100655void mpz_set_from_int(mpz_t *z, mp_int_t val) {
Damien George58056b02015-01-09 20:58:58 +0000656 if (val == 0) {
657 z->len = 0;
658 return;
659 }
660
Damien George06201ff2014-03-01 19:50:50 +0000661 mpz_need_dig(z, MPZ_NUM_DIG_FOR_INT);
Damien George438c88d2014-02-22 19:25:23 +0000662
Damien George40f3c022014-07-03 13:25:24 +0100663 mp_uint_t uval;
Damien George438c88d2014-02-22 19:25:23 +0000664 if (val < 0) {
665 z->neg = 1;
Damien Georgebb4a43f2014-03-12 15:36:06 +0000666 uval = -val;
Damien George438c88d2014-02-22 19:25:23 +0000667 } else {
668 z->neg = 0;
Damien Georgebb4a43f2014-03-12 15:36:06 +0000669 uval = val;
Damien George438c88d2014-02-22 19:25:23 +0000670 }
671
672 z->len = 0;
Damien Georgebb4a43f2014-03-12 15:36:06 +0000673 while (uval > 0) {
674 z->dig[z->len++] = uval & DIG_MASK;
675 uval >>= DIG_SIZE;
676 }
677}
678
Damien George95307432014-09-10 22:10:33 +0100679void mpz_set_from_ll(mpz_t *z, long long val, bool is_signed) {
Damien Georgebb4a43f2014-03-12 15:36:06 +0000680 mpz_need_dig(z, MPZ_NUM_DIG_FOR_LL);
681
682 unsigned long long uval;
Damien George95307432014-09-10 22:10:33 +0100683 if (is_signed && val < 0) {
Damien Georgebb4a43f2014-03-12 15:36:06 +0000684 z->neg = 1;
685 uval = -val;
686 } else {
687 z->neg = 0;
688 uval = val;
689 }
690
691 z->len = 0;
692 while (uval > 0) {
693 z->dig[z->len++] = uval & DIG_MASK;
694 uval >>= DIG_SIZE;
Damien George438c88d2014-02-22 19:25:23 +0000695 }
696}
697
David Steinberg6e0b6d02015-01-02 12:39:22 +0000698#if MICROPY_PY_BUILTINS_FLOAT
699void mpz_set_from_float(mpz_t *z, mp_float_t src) {
700#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE
701#define EXP_SZ 11
702#define FRC_SZ 52
703typedef uint64_t mp_float_int_t;
704#else
705#define EXP_SZ 8
706#define FRC_SZ 23
707typedef uint32_t mp_float_int_t;
708#endif
709 union {
710 mp_float_t f;
711 struct { mp_float_int_t frc:FRC_SZ, exp:EXP_SZ, sgn:1; } p;
712 } u = {src};
713
714 z->neg = u.p.sgn;
715 if (u.p.exp == 0) {
716 // value == 0 || value < 1
Damien George58056b02015-01-09 20:58:58 +0000717 mpz_set_from_int(z, 0);
David Steinberg6e0b6d02015-01-02 12:39:22 +0000718 } else if (u.p.exp == ((1 << EXP_SZ) - 1)) {
Damien George6fd4b362015-01-02 23:04:09 +0000719 // u.p.frc == 0 indicates inf, else NaN
720 // should be handled by caller
Damien George58056b02015-01-09 20:58:58 +0000721 mpz_set_from_int(z, 0);
David Steinberg6e0b6d02015-01-02 12:39:22 +0000722 } else {
723 const int adj_exp = (int)u.p.exp - ((1 << (EXP_SZ - 1)) - 1);
724 if (adj_exp < 0) {
725 // value < 1 , truncates to 0
Damien George58056b02015-01-09 20:58:58 +0000726 mpz_set_from_int(z, 0);
David Steinberg6e0b6d02015-01-02 12:39:22 +0000727 } else if (adj_exp == 0) {
728 // 1 <= value < 2 , so truncates to 1
Damien George58056b02015-01-09 20:58:58 +0000729 mpz_set_from_int(z, 1);
David Steinberg6e0b6d02015-01-02 12:39:22 +0000730 } else {
731 // 2 <= value
732 const int dig_cnt = (adj_exp + 1 + (DIG_SIZE - 1)) / DIG_SIZE;
733 const unsigned int rem = adj_exp % DIG_SIZE;
734 int dig_ind, shft;
735 mp_float_int_t frc = u.p.frc | ((mp_float_int_t)1 << FRC_SZ);
736
737 if (adj_exp < FRC_SZ) {
738 shft = 0;
739 dig_ind = 0;
740 frc >>= FRC_SZ - adj_exp;
741 } else {
742 shft = (rem - FRC_SZ) % DIG_SIZE;
743 dig_ind = (adj_exp - FRC_SZ) / DIG_SIZE;
744 }
745 mpz_need_dig(z, dig_cnt);
746 z->len = dig_cnt;
747 if (dig_ind != 0) {
748 memset(z->dig, 0, dig_ind * sizeof(mpz_dig_t));
749 }
750 if (shft != 0) {
751 z->dig[dig_ind++] = (frc << shft) & DIG_MASK;
752 frc >>= DIG_SIZE - shft;
753 }
754 while (dig_ind != dig_cnt) {
755 z->dig[dig_ind++] = frc & DIG_MASK;
756 frc >>= DIG_SIZE;
757 }
758 }
759 }
760}
761#undef EXP_SZ
762#undef FRC_SZ
763#endif
764
Damien George438c88d2014-02-22 19:25:23 +0000765// returns number of bytes from str that were processed
Damien Georgeafb1cf72014-09-05 20:37:06 +0100766mp_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 +0000767 assert(base < 36);
768
769 const char *cur = str;
770 const char *top = str + len;
771
772 mpz_need_dig(z, len * 8 / DIG_SIZE + 1);
773
774 if (neg) {
775 z->neg = 1;
776 } else {
777 z->neg = 0;
778 }
779
780 z->len = 0;
781 for (; cur < top; ++cur) { // XXX UTF8 next char
Damien Georgeafb1cf72014-09-05 20:37:06 +0100782 //mp_uint_t v = char_to_numeric(cur#); // XXX UTF8 get char
783 mp_uint_t v = *cur;
Damien George438c88d2014-02-22 19:25:23 +0000784 if ('0' <= v && v <= '9') {
785 v -= '0';
786 } else if ('A' <= v && v <= 'Z') {
787 v -= 'A' - 10;
788 } else if ('a' <= v && v <= 'z') {
789 v -= 'a' - 10;
790 } else {
791 break;
792 }
793 if (v >= base) {
794 break;
795 }
796 z->len = mpn_mul_dig_add_dig(z->dig, z->len, base, v);
797 }
798
799 return cur - str;
800}
801
802bool mpz_is_zero(const mpz_t *z) {
803 return z->len == 0;
804}
805
806bool mpz_is_pos(const mpz_t *z) {
807 return z->len > 0 && z->neg == 0;
808}
809
810bool mpz_is_neg(const mpz_t *z) {
811 return z->len > 0 && z->neg != 0;
812}
813
814bool mpz_is_odd(const mpz_t *z) {
815 return z->len > 0 && (z->dig[0] & 1) != 0;
816}
817
818bool mpz_is_even(const mpz_t *z) {
819 return z->len == 0 || (z->dig[0] & 1) == 0;
820}
821
Damien George42f3de92014-10-03 17:44:14 +0000822int mpz_cmp(const mpz_t *z1, const mpz_t *z2) {
823 int cmp = (int)z2->neg - (int)z1->neg;
Damien George438c88d2014-02-22 19:25:23 +0000824 if (cmp != 0) {
825 return cmp;
826 }
827 cmp = mpn_cmp(z1->dig, z1->len, z2->dig, z2->len);
828 if (z1->neg != 0) {
829 cmp = -cmp;
830 }
831 return cmp;
832}
833
Damien George06201ff2014-03-01 19:50:50 +0000834#if 0
835// obsolete
836// compares mpz with an integer that fits within DIG_SIZE bits
Damien Georgeafb1cf72014-09-05 20:37:06 +0100837mp_int_t mpz_cmp_sml_int(const mpz_t *z, mp_int_t sml_int) {
838 mp_int_t cmp;
Damien George438c88d2014-02-22 19:25:23 +0000839 if (z->neg == 0) {
840 if (sml_int < 0) return 1;
841 if (sml_int == 0) {
842 if (z->len == 0) return 0;
843 return 1;
844 }
845 if (z->len == 0) return -1;
846 assert(sml_int < (1 << DIG_SIZE));
847 if (z->len != 1) return 1;
848 cmp = z->dig[0] - sml_int;
849 } else {
850 if (sml_int > 0) return -1;
851 if (sml_int == 0) {
852 if (z->len == 0) return 0;
853 return -1;
854 }
855 if (z->len == 0) return 1;
856 assert(sml_int > -(1 << DIG_SIZE));
857 if (z->len != 1) return -1;
858 cmp = -z->dig[0] - sml_int;
859 }
860 if (cmp < 0) return -1;
861 if (cmp > 0) return 1;
862 return 0;
863}
Damien George06201ff2014-03-01 19:50:50 +0000864#endif
Damien George438c88d2014-02-22 19:25:23 +0000865
Damien George438c88d2014-02-22 19:25:23 +0000866#if 0
867these functions are unused
868
869/* returns abs(z)
870*/
871mpz_t *mpz_abs(const mpz_t *z) {
872 mpz_t *z2 = mpz_clone(z);
873 z2->neg = 0;
874 return z2;
875}
876
877/* returns -z
878*/
879mpz_t *mpz_neg(const mpz_t *z) {
880 mpz_t *z2 = mpz_clone(z);
881 z2->neg = 1 - z2->neg;
882 return z2;
883}
884
885/* returns lhs + rhs
886 can have lhs, rhs the same
887*/
888mpz_t *mpz_add(const mpz_t *lhs, const mpz_t *rhs) {
889 mpz_t *z = mpz_zero();
890 mpz_add_inpl(z, lhs, rhs);
891 return z;
892}
893
894/* returns lhs - rhs
895 can have lhs, rhs the same
896*/
897mpz_t *mpz_sub(const mpz_t *lhs, const mpz_t *rhs) {
898 mpz_t *z = mpz_zero();
899 mpz_sub_inpl(z, lhs, rhs);
900 return z;
901}
902
903/* returns lhs * rhs
904 can have lhs, rhs the same
905*/
906mpz_t *mpz_mul(const mpz_t *lhs, const mpz_t *rhs) {
907 mpz_t *z = mpz_zero();
908 mpz_mul_inpl(z, lhs, rhs);
909 return z;
910}
911
912/* returns lhs ** rhs
913 can have lhs, rhs the same
914*/
915mpz_t *mpz_pow(const mpz_t *lhs, const mpz_t *rhs) {
916 mpz_t *z = mpz_zero();
917 mpz_pow_inpl(z, lhs, rhs);
918 return z;
919}
920#endif
921
922/* computes dest = abs(z)
923 can have dest, z the same
924*/
925void mpz_abs_inpl(mpz_t *dest, const mpz_t *z) {
926 if (dest != z) {
927 mpz_set(dest, z);
928 }
929 dest->neg = 0;
930}
931
932/* computes dest = -z
933 can have dest, z the same
934*/
935void mpz_neg_inpl(mpz_t *dest, const mpz_t *z) {
936 if (dest != z) {
937 mpz_set(dest, z);
938 }
939 dest->neg = 1 - dest->neg;
940}
941
Damien George06201ff2014-03-01 19:50:50 +0000942/* computes dest = ~z (= -z - 1)
943 can have dest, z the same
944*/
945void mpz_not_inpl(mpz_t *dest, const mpz_t *z) {
946 if (dest != z) {
947 mpz_set(dest, z);
948 }
Damien Georgee0ac1942014-12-31 19:35:01 +0000949 if (dest->len == 0) {
950 mpz_need_dig(dest, 1);
951 dest->dig[0] = 1;
952 dest->len = 1;
953 dest->neg = 1;
954 } else if (dest->neg) {
Damien George06201ff2014-03-01 19:50:50 +0000955 dest->neg = 0;
956 mpz_dig_t k = 1;
957 dest->len = mpn_sub(dest->dig, dest->dig, dest->len, &k, 1);
958 } else {
Damien Georgee0ac1942014-12-31 19:35:01 +0000959 mpz_need_dig(dest, dest->len + 1);
Damien George06201ff2014-03-01 19:50:50 +0000960 mpz_dig_t k = 1;
961 dest->len = mpn_add(dest->dig, dest->dig, dest->len, &k, 1);
962 dest->neg = 1;
963 }
964}
965
Damien Georgec5ac2ac2014-02-26 16:56:30 +0000966/* computes dest = lhs << rhs
967 can have dest, lhs the same
968*/
Damien George40f3c022014-07-03 13:25:24 +0100969void mpz_shl_inpl(mpz_t *dest, const mpz_t *lhs, mp_int_t rhs) {
Damien George06201ff2014-03-01 19:50:50 +0000970 if (lhs->len == 0 || rhs == 0) {
Damien Georgec5ac2ac2014-02-26 16:56:30 +0000971 mpz_set(dest, lhs);
Damien George06201ff2014-03-01 19:50:50 +0000972 } else if (rhs < 0) {
973 mpz_shr_inpl(dest, lhs, -rhs);
Damien Georgec5ac2ac2014-02-26 16:56:30 +0000974 } else {
Damien George06201ff2014-03-01 19:50:50 +0000975 mpz_need_dig(dest, lhs->len + (rhs + DIG_SIZE - 1) / DIG_SIZE);
976 dest->len = mpn_shl(dest->dig, lhs->dig, lhs->len, rhs);
977 dest->neg = lhs->neg;
Damien Georgec5ac2ac2014-02-26 16:56:30 +0000978 }
Damien Georgec5ac2ac2014-02-26 16:56:30 +0000979}
980
981/* computes dest = lhs >> rhs
982 can have dest, lhs the same
983*/
Damien George40f3c022014-07-03 13:25:24 +0100984void mpz_shr_inpl(mpz_t *dest, const mpz_t *lhs, mp_int_t rhs) {
Damien George06201ff2014-03-01 19:50:50 +0000985 if (lhs->len == 0 || rhs == 0) {
Damien Georgec5ac2ac2014-02-26 16:56:30 +0000986 mpz_set(dest, lhs);
Damien George06201ff2014-03-01 19:50:50 +0000987 } else if (rhs < 0) {
988 mpz_shl_inpl(dest, lhs, -rhs);
Damien Georgec5ac2ac2014-02-26 16:56:30 +0000989 } else {
Damien George06201ff2014-03-01 19:50:50 +0000990 mpz_need_dig(dest, lhs->len);
991 dest->len = mpn_shr(dest->dig, lhs->dig, lhs->len, rhs);
992 dest->neg = lhs->neg;
993 if (dest->neg) {
994 // arithmetic shift right, rounding to negative infinity
Damien Georgeafb1cf72014-09-05 20:37:06 +0100995 mp_uint_t n_whole = rhs / DIG_SIZE;
996 mp_uint_t n_part = rhs % DIG_SIZE;
Damien George06201ff2014-03-01 19:50:50 +0000997 mpz_dig_t round_up = 0;
Damien Georgeafb1cf72014-09-05 20:37:06 +0100998 for (mp_uint_t i = 0; i < lhs->len && i < n_whole; i++) {
Damien George06201ff2014-03-01 19:50:50 +0000999 if (lhs->dig[i] != 0) {
1000 round_up = 1;
1001 break;
1002 }
1003 }
1004 if (n_whole < lhs->len && (lhs->dig[n_whole] & ((1 << n_part) - 1)) != 0) {
1005 round_up = 1;
1006 }
1007 if (round_up) {
Damien Georgee0ac1942014-12-31 19:35:01 +00001008 if (dest->len == 0) {
1009 // dest == 0, so need to add 1 by hand (answer will be -1)
1010 dest->dig[0] = 1;
1011 dest->len = 1;
1012 } else {
1013 // dest > 0, so can use mpn_add to add 1
1014 dest->len = mpn_add(dest->dig, dest->dig, dest->len, &round_up, 1);
1015 }
Damien George06201ff2014-03-01 19:50:50 +00001016 }
1017 }
Damien Georgec5ac2ac2014-02-26 16:56:30 +00001018 }
Damien Georgec5ac2ac2014-02-26 16:56:30 +00001019}
Damien Georgec5ac2ac2014-02-26 16:56:30 +00001020
Damien George438c88d2014-02-22 19:25:23 +00001021/* computes dest = lhs + rhs
1022 can have dest, lhs, rhs the same
1023*/
1024void mpz_add_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
1025 if (mpn_cmp(lhs->dig, lhs->len, rhs->dig, rhs->len) < 0) {
1026 const mpz_t *temp = lhs;
1027 lhs = rhs;
1028 rhs = temp;
1029 }
1030
1031 if (lhs->neg == rhs->neg) {
1032 mpz_need_dig(dest, lhs->len + 1);
1033 dest->len = mpn_add(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
1034 } else {
1035 mpz_need_dig(dest, lhs->len);
1036 dest->len = mpn_sub(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
1037 }
1038
1039 dest->neg = lhs->neg;
1040}
1041
1042/* computes dest = lhs - rhs
1043 can have dest, lhs, rhs the same
1044*/
1045void mpz_sub_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
1046 bool neg = false;
1047
1048 if (mpn_cmp(lhs->dig, lhs->len, rhs->dig, rhs->len) < 0) {
1049 const mpz_t *temp = lhs;
1050 lhs = rhs;
1051 rhs = temp;
1052 neg = true;
1053 }
1054
1055 if (lhs->neg != rhs->neg) {
1056 mpz_need_dig(dest, lhs->len + 1);
1057 dest->len = mpn_add(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
1058 } else {
1059 mpz_need_dig(dest, lhs->len);
1060 dest->len = mpn_sub(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
1061 }
1062
1063 if (neg) {
1064 dest->neg = 1 - lhs->neg;
1065 } else {
1066 dest->neg = lhs->neg;
1067 }
1068}
1069
Paul Sokolovsky57207b82014-03-23 01:52:36 +02001070/* computes dest = lhs & rhs
1071 can have dest, lhs, rhs the same
1072*/
1073void mpz_and_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
Paul Sokolovsky57207b82014-03-23 01:52:36 +02001074 if (lhs->neg == rhs->neg) {
Damien Georgef55cf102014-05-29 15:01:49 +01001075 if (lhs->neg == 0) {
1076 // make sure lhs has the most digits
1077 if (lhs->len < rhs->len) {
1078 const mpz_t *temp = lhs;
1079 lhs = rhs;
1080 rhs = temp;
1081 }
1082 // do the and'ing
1083 mpz_need_dig(dest, rhs->len);
1084 dest->len = mpn_and(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
1085 dest->neg = 0;
1086 } else {
1087 // TODO both args are negative
1088 assert(0);
1089 }
Paul Sokolovsky57207b82014-03-23 01:52:36 +02001090 } else {
Damien Georgef55cf102014-05-29 15:01:49 +01001091 // args have different sign
1092 // make sure lhs is the positive arg
1093 if (rhs->neg == 0) {
1094 const mpz_t *temp = lhs;
1095 lhs = rhs;
1096 rhs = temp;
1097 }
1098 mpz_need_dig(dest, lhs->len + 1);
1099 dest->len = mpn_and_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
1100 assert(dest->len <= dest->alloc);
1101 dest->neg = 0;
Paul Sokolovsky57207b82014-03-23 01:52:36 +02001102 }
Paul Sokolovsky57207b82014-03-23 01:52:36 +02001103}
1104
1105/* computes dest = lhs | rhs
1106 can have dest, lhs, rhs the same
1107*/
1108void mpz_or_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
1109 if (mpn_cmp(lhs->dig, lhs->len, rhs->dig, rhs->len) < 0) {
1110 const mpz_t *temp = lhs;
1111 lhs = rhs;
1112 rhs = temp;
1113 }
1114
1115 if (lhs->neg == rhs->neg) {
1116 mpz_need_dig(dest, lhs->len);
1117 dest->len = mpn_or(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
1118 } else {
1119 mpz_need_dig(dest, lhs->len);
1120 // TODO
1121 assert(0);
1122// dest->len = mpn_or_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
1123 }
1124
1125 dest->neg = lhs->neg;
1126}
1127
1128/* computes dest = lhs ^ rhs
1129 can have dest, lhs, rhs the same
1130*/
1131void mpz_xor_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
1132 if (mpn_cmp(lhs->dig, lhs->len, rhs->dig, rhs->len) < 0) {
1133 const mpz_t *temp = lhs;
1134 lhs = rhs;
1135 rhs = temp;
1136 }
1137
1138 if (lhs->neg == rhs->neg) {
1139 mpz_need_dig(dest, lhs->len);
1140 dest->len = mpn_xor(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
1141 } else {
1142 mpz_need_dig(dest, lhs->len);
1143 // TODO
1144 assert(0);
1145// dest->len = mpn_xor_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
1146 }
1147
1148 dest->neg = 0;
1149}
1150
Damien George438c88d2014-02-22 19:25:23 +00001151/* computes dest = lhs * rhs
1152 can have dest, lhs, rhs the same
1153*/
1154void mpz_mul_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs)
1155{
1156 if (lhs->len == 0 || rhs->len == 0) {
Damien Georgec5ac2ac2014-02-26 16:56:30 +00001157 mpz_set_from_int(dest, 0);
1158 return;
Damien George438c88d2014-02-22 19:25:23 +00001159 }
1160
1161 mpz_t *temp = NULL;
1162 if (lhs == dest) {
1163 lhs = temp = mpz_clone(lhs);
1164 if (rhs == dest) {
1165 rhs = lhs;
1166 }
1167 } else if (rhs == dest) {
1168 rhs = temp = mpz_clone(rhs);
1169 }
1170
1171 mpz_need_dig(dest, lhs->len + rhs->len); // min mem l+r-1, max mem l+r
1172 memset(dest->dig, 0, dest->alloc * sizeof(mpz_dig_t));
1173 dest->len = mpn_mul(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
1174
1175 if (lhs->neg == rhs->neg) {
1176 dest->neg = 0;
1177 } else {
1178 dest->neg = 1;
1179 }
1180
1181 mpz_free(temp);
1182}
1183
1184/* computes dest = lhs ** rhs
1185 can have dest, lhs, rhs the same
1186*/
1187void mpz_pow_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
1188 if (lhs->len == 0 || rhs->neg != 0) {
Damien Georgec5ac2ac2014-02-26 16:56:30 +00001189 mpz_set_from_int(dest, 0);
1190 return;
Damien George438c88d2014-02-22 19:25:23 +00001191 }
1192
1193 if (rhs->len == 0) {
Damien Georgec5ac2ac2014-02-26 16:56:30 +00001194 mpz_set_from_int(dest, 1);
1195 return;
Damien George438c88d2014-02-22 19:25:23 +00001196 }
1197
1198 mpz_t *x = mpz_clone(lhs);
1199 mpz_t *n = mpz_clone(rhs);
1200
1201 mpz_set_from_int(dest, 1);
1202
1203 while (n->len > 0) {
1204 if (mpz_is_odd(n)) {
1205 mpz_mul_inpl(dest, dest, x);
1206 }
Damien George438c88d2014-02-22 19:25:23 +00001207 n->len = mpn_shr(n->dig, n->dig, n->len, 1);
Damien George5bf565e2014-04-04 00:16:32 +01001208 if (n->len == 0) {
1209 break;
1210 }
1211 mpz_mul_inpl(x, x, x);
Damien George438c88d2014-02-22 19:25:23 +00001212 }
1213
1214 mpz_free(x);
1215 mpz_free(n);
1216}
1217
1218/* computes gcd(z1, z2)
1219 based on Knuth's modified gcd algorithm (I think?)
1220 gcd(z1, z2) >= 0
1221 gcd(0, 0) = 0
1222 gcd(z, 0) = abs(z)
1223*/
1224mpz_t *mpz_gcd(const mpz_t *z1, const mpz_t *z2) {
1225 if (z1->len == 0) {
1226 mpz_t *a = mpz_clone(z2);
1227 a->neg = 0;
1228 return a;
1229 } else if (z2->len == 0) {
1230 mpz_t *a = mpz_clone(z1);
1231 a->neg = 0;
1232 return a;
1233 }
1234
1235 mpz_t *a = mpz_clone(z1);
1236 mpz_t *b = mpz_clone(z2);
1237 mpz_t c; mpz_init_zero(&c);
1238 a->neg = 0;
1239 b->neg = 0;
1240
1241 for (;;) {
1242 if (mpz_cmp(a, b) < 0) {
1243 if (a->len == 0) {
1244 mpz_free(a);
1245 mpz_deinit(&c);
1246 return b;
1247 }
1248 mpz_t *t = a; a = b; b = t;
1249 }
1250 if (!(b->len >= 2 || (b->len == 1 && b->dig[0] > 1))) { // compute b > 0; could be mpz_cmp_small_int(b, 1) > 0
1251 break;
1252 }
1253 mpz_set(&c, b);
1254 do {
1255 mpz_add_inpl(&c, &c, &c);
1256 } while (mpz_cmp(&c, a) <= 0);
1257 c.len = mpn_shr(c.dig, c.dig, c.len, 1);
1258 mpz_sub_inpl(a, a, &c);
1259 }
1260
1261 mpz_deinit(&c);
1262
1263 if (b->len == 1 && b->dig[0] == 1) { // compute b == 1; could be mpz_cmp_small_int(b, 1) == 0
1264 mpz_free(a);
1265 return b;
1266 } else {
1267 mpz_free(b);
1268 return a;
1269 }
1270}
1271
1272/* computes lcm(z1, z2)
1273 = abs(z1) / gcd(z1, z2) * abs(z2)
1274 lcm(z1, z1) >= 0
1275 lcm(0, 0) = 0
1276 lcm(z, 0) = 0
1277*/
Damien George5d9b8162014-08-07 14:27:48 +00001278mpz_t *mpz_lcm(const mpz_t *z1, const mpz_t *z2) {
1279 if (z1->len == 0 || z2->len == 0) {
1280 return mpz_zero();
stijn01d6be42014-05-05 12:18:27 +02001281 }
Damien George438c88d2014-02-22 19:25:23 +00001282
1283 mpz_t *gcd = mpz_gcd(z1, z2);
1284 mpz_t *quo = mpz_zero();
1285 mpz_t *rem = mpz_zero();
1286 mpz_divmod_inpl(quo, rem, z1, gcd);
1287 mpz_mul_inpl(rem, quo, z2);
1288 mpz_free(gcd);
1289 mpz_free(quo);
1290 rem->neg = 0;
1291 return rem;
1292}
1293
1294/* computes new integers in quo and rem such that:
1295 quo * rhs + rem = lhs
1296 0 <= rem < rhs
1297 can have lhs, rhs the same
1298*/
1299void mpz_divmod(const mpz_t *lhs, const mpz_t *rhs, mpz_t **quo, mpz_t **rem) {
1300 *quo = mpz_zero();
1301 *rem = mpz_zero();
1302 mpz_divmod_inpl(*quo, *rem, lhs, rhs);
1303}
1304
1305/* computes new integers in quo and rem such that:
1306 quo * rhs + rem = lhs
1307 0 <= rem < rhs
1308 can have lhs, rhs the same
1309*/
1310void mpz_divmod_inpl(mpz_t *dest_quo, mpz_t *dest_rem, const mpz_t *lhs, const mpz_t *rhs) {
1311 if (rhs->len == 0) {
1312 mpz_set_from_int(dest_quo, 0);
1313 mpz_set_from_int(dest_rem, 0);
1314 return;
1315 }
1316
1317 mpz_need_dig(dest_quo, lhs->len + 1); // +1 necessary?
1318 memset(dest_quo->dig, 0, (lhs->len + 1) * sizeof(mpz_dig_t));
1319 dest_quo->len = 0;
1320 mpz_need_dig(dest_rem, lhs->len + 1); // +1 necessary?
1321 mpz_set(dest_rem, lhs);
1322 //rhs->dig[rhs->len] = 0;
1323 mpn_div(dest_rem->dig, &dest_rem->len, rhs->dig, rhs->len, dest_quo->dig, &dest_quo->len);
1324
1325 if (lhs->neg != rhs->neg) {
1326 dest_quo->neg = 1;
1327 }
1328}
1329
1330#if 0
1331these functions are unused
1332
1333/* computes floor(lhs / rhs)
1334 can have lhs, rhs the same
1335*/
1336mpz_t *mpz_div(const mpz_t *lhs, const mpz_t *rhs) {
1337 mpz_t *quo = mpz_zero();
1338 mpz_t rem; mpz_init_zero(&rem);
1339 mpz_divmod_inpl(quo, &rem, lhs, rhs);
1340 mpz_deinit(&rem);
1341 return quo;
1342}
1343
1344/* computes lhs % rhs ( >= 0)
1345 can have lhs, rhs the same
1346*/
1347mpz_t *mpz_mod(const mpz_t *lhs, const mpz_t *rhs) {
1348 mpz_t quo; mpz_init_zero(&quo);
1349 mpz_t *rem = mpz_zero();
1350 mpz_divmod_inpl(&quo, rem, lhs, rhs);
1351 mpz_deinit(&quo);
1352 return rem;
1353}
1354#endif
1355
Damien Georgeffe911d2014-07-24 14:21:37 +01001356// must return actual int value if it fits in mp_int_t
1357mp_int_t mpz_hash(const mpz_t *z) {
1358 mp_int_t val = 0;
1359 mpz_dig_t *d = z->dig + z->len;
1360
Damien George58056b02015-01-09 20:58:58 +00001361 while (d-- > z->dig) {
Damien Georgeffe911d2014-07-24 14:21:37 +01001362 val = (val << DIG_SIZE) | *d;
1363 }
1364
1365 if (z->neg != 0) {
1366 val = -val;
1367 }
1368
1369 return val;
1370}
1371
Damien George40f3c022014-07-03 13:25:24 +01001372bool mpz_as_int_checked(const mpz_t *i, mp_int_t *value) {
1373 mp_int_t val = 0;
Damien George8270e382014-04-03 11:00:54 +00001374 mpz_dig_t *d = i->dig + i->len;
1375
Damien George58056b02015-01-09 20:58:58 +00001376 while (d-- > i->dig) {
Damien Georgec9aa58e2014-07-31 13:41:43 +00001377 if (val > (~(WORD_MSBIT_HIGH) >> DIG_SIZE)) {
1378 // will overflow
Damien George8270e382014-04-03 11:00:54 +00001379 return false;
1380 }
Damien Georgec9aa58e2014-07-31 13:41:43 +00001381 val = (val << DIG_SIZE) | *d;
Damien George8270e382014-04-03 11:00:54 +00001382 }
1383
1384 if (i->neg != 0) {
1385 val = -val;
1386 }
1387
1388 *value = val;
1389 return true;
1390}
1391
Damien Georgec9aa58e2014-07-31 13:41:43 +00001392bool mpz_as_uint_checked(const mpz_t *i, mp_uint_t *value) {
1393 if (i->neg != 0) {
1394 // can't represent signed values
1395 return false;
1396 }
1397
1398 mp_uint_t val = 0;
1399 mpz_dig_t *d = i->dig + i->len;
1400
Damien George58056b02015-01-09 20:58:58 +00001401 while (d-- > i->dig) {
Damien George9a21d2e2014-09-06 17:15:34 +01001402 if (val > (~(WORD_MSBIT_HIGH) >> (DIG_SIZE - 1))) {
Damien Georgec9aa58e2014-07-31 13:41:43 +00001403 // will overflow
1404 return false;
1405 }
1406 val = (val << DIG_SIZE) | *d;
1407 }
1408
1409 *value = val;
1410 return true;
1411}
1412
Damien Georgefb510b32014-06-01 13:32:54 +01001413#if MICROPY_PY_BUILTINS_FLOAT
Damien George52608102014-03-08 15:04:54 +00001414mp_float_t mpz_as_float(const mpz_t *i) {
1415 mp_float_t val = 0;
Damien George438c88d2014-02-22 19:25:23 +00001416 mpz_dig_t *d = i->dig + i->len;
1417
Damien George58056b02015-01-09 20:58:58 +00001418 while (d-- > i->dig) {
Damien George9a21d2e2014-09-06 17:15:34 +01001419 val = val * DIG_BASE + *d;
Damien George438c88d2014-02-22 19:25:23 +00001420 }
1421
1422 if (i->neg != 0) {
1423 val = -val;
1424 }
1425
1426 return val;
1427}
Damien George52608102014-03-08 15:04:54 +00001428#endif
Damien George438c88d2014-02-22 19:25:23 +00001429
Damien Georgeafb1cf72014-09-05 20:37:06 +01001430mp_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 +00001431 if (base < 2 || base > 32) {
1432 return 0;
1433 }
1434
Damien Georgeafb1cf72014-09-05 20:37:06 +01001435 mp_uint_t num_digits = i->len * DIG_SIZE / log_base2_floor[base] + 1;
1436 mp_uint_t num_commas = comma ? num_digits / 3: 0;
1437 mp_uint_t prefix_len = prefix ? strlen(prefix) : 0;
Dave Hylandsc4029e52014-04-07 11:19:51 -07001438
1439 return num_digits + num_commas + prefix_len + 2; // +1 for sign, +1 for null byte
1440}
1441
Damien Georgeafb1cf72014-09-05 20:37:06 +01001442#if 0
1443this function is unused
1444char *mpz_as_str(const mpz_t *i, mp_uint_t base) {
1445 char *s = m_new(char, mpz_as_str_size(i, base, NULL, '\0'));
1446 mpz_as_str_inpl(i, base, NULL, 'a', '\0', s);
Damien George438c88d2014-02-22 19:25:23 +00001447 return s;
1448}
Damien Georgeafb1cf72014-09-05 20:37:06 +01001449#endif
Damien George438c88d2014-02-22 19:25:23 +00001450
1451// assumes enough space as calculated by mpz_as_str_size
1452// returns length of string, not including null byte
Damien Georgeafb1cf72014-09-05 20:37:06 +01001453mp_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 +00001454 if (str == NULL || base < 2 || base > 32) {
1455 str[0] = 0;
1456 return 0;
1457 }
1458
Damien Georgeafb1cf72014-09-05 20:37:06 +01001459 mp_uint_t ilen = i->len;
Damien George438c88d2014-02-22 19:25:23 +00001460
Dave Hylandsc4029e52014-04-07 11:19:51 -07001461 char *s = str;
Damien George438c88d2014-02-22 19:25:23 +00001462 if (ilen == 0) {
Dave Hylandsc4029e52014-04-07 11:19:51 -07001463 if (prefix) {
1464 while (*prefix)
1465 *s++ = *prefix++;
1466 }
1467 *s++ = '0';
1468 *s = '\0';
1469 return s - str;
Damien George438c88d2014-02-22 19:25:23 +00001470 }
1471
Damien Georgeeec91052014-04-08 23:11:00 +01001472 // make a copy of mpz digits, so we can do the div/mod calculation
Damien George438c88d2014-02-22 19:25:23 +00001473 mpz_dig_t *dig = m_new(mpz_dig_t, ilen);
1474 memcpy(dig, i->dig, ilen * sizeof(mpz_dig_t));
1475
1476 // convert
Dave Hylandsc4029e52014-04-07 11:19:51 -07001477 char *last_comma = str;
Damien George438c88d2014-02-22 19:25:23 +00001478 bool done;
1479 do {
1480 mpz_dig_t *d = dig + ilen;
1481 mpz_dbl_dig_t a = 0;
1482
1483 // compute next remainder
1484 while (--d >= dig) {
1485 a = (a << DIG_SIZE) | *d;
1486 *d = a / base;
1487 a %= base;
1488 }
1489
1490 // convert to character
1491 a += '0';
1492 if (a > '9') {
Dave Hylandsc4029e52014-04-07 11:19:51 -07001493 a += base_char - '9' - 1;
Damien George438c88d2014-02-22 19:25:23 +00001494 }
1495 *s++ = a;
1496
1497 // check if number is zero
1498 done = true;
1499 for (d = dig; d < dig + ilen; ++d) {
1500 if (*d != 0) {
1501 done = false;
1502 break;
1503 }
1504 }
Dave Hylandsc4029e52014-04-07 11:19:51 -07001505 if (comma && (s - last_comma) == 3) {
1506 *s++ = comma;
1507 last_comma = s;
1508 }
1509 }
1510 while (!done);
Damien George438c88d2014-02-22 19:25:23 +00001511
Damien Georgeeec91052014-04-08 23:11:00 +01001512 // free the copy of the digits array
1513 m_del(mpz_dig_t, dig, ilen);
1514
Dave Hylandsc4029e52014-04-07 11:19:51 -07001515 if (prefix) {
1516 const char *p = &prefix[strlen(prefix)];
1517 while (p > prefix) {
1518 *s++ = *--p;
1519 }
1520 }
Damien George438c88d2014-02-22 19:25:23 +00001521 if (i->neg != 0) {
1522 *s++ = '-';
1523 }
1524
1525 // reverse string
1526 for (char *u = str, *v = s - 1; u < v; ++u, --v) {
1527 char temp = *u;
1528 *u = *v;
1529 *v = temp;
1530 }
1531
Dave Hylandsc4029e52014-04-07 11:19:51 -07001532 *s = '\0'; // null termination
Damien George438c88d2014-02-22 19:25:23 +00001533
1534 return s - str;
1535}
1536
1537#endif // MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_MPZ