| /* dumbmp mini GMP compatible library. |
| |
| Copyright 2001, 2002, 2004 Free Software Foundation, Inc. |
| |
| This file is part of the GNU MP Library. |
| |
| The GNU MP Library is free software; you can redistribute it and/or modify |
| it under the terms of the GNU Lesser General Public License as published by |
| the Free Software Foundation; either version 3 of the License, or (at your |
| option) any later version. |
| |
| The GNU MP Library is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
| or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public |
| License for more details. |
| |
| You should have received a copy of the GNU Lesser General Public License |
| along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */ |
| |
| |
| /* The code here implements a subset (a very limited subset) of the main GMP |
| functions. It's designed for use in a few build-time calculations and |
| will be slow, but highly portable. |
| |
| None of the normal GMP configure things are used, nor any of the normal |
| gmp.h or gmp-impl.h. To use this file in a program just #include |
| "dumbmp.c". |
| |
| ANSI function definitions can be used here, since ansi2knr is run if |
| necessary. But other ANSI-isms like "const" should be avoided. |
| |
| mp_limb_t here is an unsigned long, since that's a sensible type |
| everywhere we know of, with 8*sizeof(unsigned long) giving the number of |
| bits in the type (that not being true for instance with int or short on |
| Cray vector systems.) |
| |
| Only the low half of each mp_limb_t is used, so as to make carry handling |
| and limb multiplies easy. GMP_LIMB_BITS is the number of bits used. */ |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| |
| |
| typedef unsigned long mp_limb_t; |
| |
| typedef struct { |
| int _mp_alloc; |
| int _mp_size; |
| mp_limb_t *_mp_d; |
| } mpz_t[1]; |
| |
| #define GMP_LIMB_BITS (sizeof (mp_limb_t) * 8 / 2) |
| |
| #define ABS(x) ((x) >= 0 ? (x) : -(x)) |
| #define MIN(l,o) ((l) < (o) ? (l) : (o)) |
| #define MAX(h,i) ((h) > (i) ? (h) : (i)) |
| |
| #define ALLOC(x) ((x)->_mp_alloc) |
| #define PTR(x) ((x)->_mp_d) |
| #define SIZ(x) ((x)->_mp_size) |
| #define ABSIZ(x) ABS (SIZ (x)) |
| #define LOMASK ((1L << GMP_LIMB_BITS) - 1) |
| #define LO(x) ((x) & LOMASK) |
| #define HI(x) ((x) >> GMP_LIMB_BITS) |
| |
| #define ASSERT(cond) \ |
| do { \ |
| if (! (cond)) \ |
| { \ |
| fprintf (stderr, "Assertion failure\n"); \ |
| abort (); \ |
| } \ |
| } while (0) |
| |
| |
| char * |
| xmalloc (int n) |
| { |
| char *p; |
| p = malloc (n); |
| if (p == NULL) |
| { |
| fprintf (stderr, "Out of memory (alloc %d bytes)\n", n); |
| abort (); |
| } |
| return p; |
| } |
| |
| mp_limb_t * |
| xmalloc_limbs (int n) |
| { |
| return (mp_limb_t *) xmalloc (n * sizeof (mp_limb_t)); |
| } |
| |
| void |
| mem_copyi (char *dst, char *src, int size) |
| { |
| int i; |
| for (i = 0; i < size; i++) |
| dst[i] = src[i]; |
| } |
| |
| int |
| isprime (int n) |
| { |
| int i; |
| if (n < 2) |
| return 0; |
| for (i = 2; i < n; i++) |
| if ((n % i) == 0) |
| return 0; |
| return 1; |
| } |
| |
| int |
| log2_ceil (int n) |
| { |
| int e; |
| ASSERT (n >= 1); |
| for (e = 0; ; e++) |
| if ((1 << e) >= n) |
| break; |
| return e; |
| } |
| |
| void |
| mpz_realloc (mpz_t r, int n) |
| { |
| if (n <= ALLOC(r)) |
| return; |
| |
| ALLOC(r) = n; |
| PTR(r) = (mp_limb_t *) realloc (PTR(r), n * sizeof (mp_limb_t)); |
| if (PTR(r) == NULL) |
| { |
| fprintf (stderr, "Out of memory (realloc to %d)\n", n); |
| abort (); |
| } |
| } |
| |
| void |
| mpn_normalize (mp_limb_t *rp, int *rnp) |
| { |
| int rn = *rnp; |
| while (rn > 0 && rp[rn-1] == 0) |
| rn--; |
| *rnp = rn; |
| } |
| |
| void |
| mpn_copyi (mp_limb_t *dst, mp_limb_t *src, int n) |
| { |
| int i; |
| for (i = 0; i < n; i++) |
| dst[i] = src[i]; |
| } |
| |
| void |
| mpn_zero (mp_limb_t *rp, int rn) |
| { |
| int i; |
| for (i = 0; i < rn; i++) |
| rp[i] = 0; |
| } |
| |
| void |
| mpz_init (mpz_t r) |
| { |
| ALLOC(r) = 1; |
| PTR(r) = xmalloc_limbs (ALLOC(r)); |
| PTR(r)[0] = 0; |
| SIZ(r) = 0; |
| } |
| |
| void |
| mpz_clear (mpz_t r) |
| { |
| free (PTR (r)); |
| ALLOC(r) = -1; |
| SIZ (r) = 0xbadcafeL; |
| PTR (r) = (mp_limb_t *) 0xdeadbeefL; |
| } |
| |
| int |
| mpz_sgn (mpz_t a) |
| { |
| return (SIZ(a) > 0 ? 1 : SIZ(a) == 0 ? 0 : -1); |
| } |
| |
| int |
| mpz_odd_p (mpz_t a) |
| { |
| if (SIZ(a) == 0) |
| return 0; |
| else |
| return (PTR(a)[0] & 1) != 0; |
| } |
| |
| int |
| mpz_even_p (mpz_t a) |
| { |
| if (SIZ(a) == 0) |
| return 1; |
| else |
| return (PTR(a)[0] & 1) == 0; |
| } |
| |
| size_t |
| mpz_sizeinbase (mpz_t a, int base) |
| { |
| int an = ABSIZ (a); |
| mp_limb_t *ap = PTR (a); |
| int cnt; |
| mp_limb_t hi; |
| |
| if (base != 2) |
| abort (); |
| |
| if (an == 0) |
| return 1; |
| |
| cnt = 0; |
| for (hi = ap[an - 1]; hi != 0; hi >>= 1) |
| cnt += 1; |
| return (an - 1) * GMP_LIMB_BITS + cnt; |
| } |
| |
| void |
| mpz_set (mpz_t r, mpz_t a) |
| { |
| mpz_realloc (r, ABSIZ (a)); |
| SIZ(r) = SIZ(a); |
| mpn_copyi (PTR(r), PTR(a), ABSIZ (a)); |
| } |
| |
| void |
| mpz_init_set (mpz_t r, mpz_t a) |
| { |
| mpz_init (r); |
| mpz_set (r, a); |
| } |
| |
| void |
| mpz_set_ui (mpz_t r, unsigned long ui) |
| { |
| int rn; |
| mpz_realloc (r, 2); |
| PTR(r)[0] = LO(ui); |
| PTR(r)[1] = HI(ui); |
| rn = 2; |
| mpn_normalize (PTR(r), &rn); |
| SIZ(r) = rn; |
| } |
| |
| void |
| mpz_init_set_ui (mpz_t r, unsigned long ui) |
| { |
| mpz_init (r); |
| mpz_set_ui (r, ui); |
| } |
| |
| void |
| mpz_setbit (mpz_t r, unsigned long bit) |
| { |
| int limb, rn, extend; |
| mp_limb_t *rp; |
| |
| rn = SIZ(r); |
| if (rn < 0) |
| abort (); /* only r>=0 */ |
| |
| limb = bit / GMP_LIMB_BITS; |
| bit %= GMP_LIMB_BITS; |
| |
| mpz_realloc (r, limb+1); |
| rp = PTR(r); |
| extend = (limb+1) - rn; |
| if (extend > 0) |
| mpn_zero (rp + rn, extend); |
| |
| rp[limb] |= (mp_limb_t) 1 << bit; |
| SIZ(r) = MAX (rn, limb+1); |
| } |
| |
| int |
| mpz_tstbit (mpz_t r, unsigned long bit) |
| { |
| int limb; |
| |
| if (SIZ(r) < 0) |
| abort (); /* only r>=0 */ |
| |
| limb = bit / GMP_LIMB_BITS; |
| if (SIZ(r) <= limb) |
| return 0; |
| |
| bit %= GMP_LIMB_BITS; |
| return (PTR(r)[limb] >> bit) & 1; |
| } |
| |
| int |
| popc_limb (mp_limb_t a) |
| { |
| int ret = 0; |
| while (a != 0) |
| { |
| ret += (a & 1); |
| a >>= 1; |
| } |
| return ret; |
| } |
| |
| unsigned long |
| mpz_popcount (mpz_t a) |
| { |
| unsigned long ret; |
| int i; |
| |
| if (SIZ(a) < 0) |
| abort (); |
| |
| ret = 0; |
| for (i = 0; i < SIZ(a); i++) |
| ret += popc_limb (PTR(a)[i]); |
| return ret; |
| } |
| |
| void |
| mpz_add (mpz_t r, mpz_t a, mpz_t b) |
| { |
| int an = ABSIZ (a), bn = ABSIZ (b), rn; |
| mp_limb_t *rp, *ap, *bp; |
| int i; |
| mp_limb_t t, cy; |
| |
| if ((SIZ (a) ^ SIZ (b)) < 0) |
| abort (); /* really subtraction */ |
| if (SIZ (a) < 0) |
| abort (); |
| |
| mpz_realloc (r, MAX (an, bn) + 1); |
| ap = PTR (a); bp = PTR (b); rp = PTR (r); |
| if (an < bn) |
| { |
| mp_limb_t *tp; int tn; |
| tn = an; an = bn; bn = tn; |
| tp = ap; ap = bp; bp = tp; |
| } |
| |
| cy = 0; |
| for (i = 0; i < bn; i++) |
| { |
| t = ap[i] + bp[i] + cy; |
| rp[i] = LO (t); |
| cy = HI (t); |
| } |
| for (i = bn; i < an; i++) |
| { |
| t = ap[i] + cy; |
| rp[i] = LO (t); |
| cy = HI (t); |
| } |
| rp[an] = cy; |
| rn = an + 1; |
| |
| mpn_normalize (rp, &rn); |
| SIZ (r) = rn; |
| } |
| |
| void |
| mpz_add_ui (mpz_t r, mpz_t a, unsigned long int ui) |
| { |
| mpz_t b; |
| |
| mpz_init (b); |
| mpz_set_ui (b, ui); |
| mpz_add (r, a, b); |
| mpz_clear (b); |
| } |
| |
| void |
| mpz_sub (mpz_t r, mpz_t a, mpz_t b) |
| { |
| int an = ABSIZ (a), bn = ABSIZ (b), rn; |
| mp_limb_t *rp, *ap, *bp; |
| int i; |
| mp_limb_t t, cy; |
| |
| if ((SIZ (a) ^ SIZ (b)) < 0) |
| abort (); /* really addition */ |
| if (SIZ (a) < 0) |
| abort (); |
| |
| mpz_realloc (r, MAX (an, bn) + 1); |
| ap = PTR (a); bp = PTR (b); rp = PTR (r); |
| if (an < bn) |
| { |
| mp_limb_t *tp; int tn; |
| tn = an; an = bn; bn = tn; |
| tp = ap; ap = bp; bp = tp; |
| } |
| |
| cy = 0; |
| for (i = 0; i < bn; i++) |
| { |
| t = ap[i] - bp[i] - cy; |
| rp[i] = LO (t); |
| cy = LO (-HI (t)); |
| } |
| for (i = bn; i < an; i++) |
| { |
| t = ap[i] - cy; |
| rp[i] = LO (t); |
| cy = LO (-HI (t)); |
| } |
| rp[an] = cy; |
| rn = an + 1; |
| |
| if (cy != 0) |
| { |
| cy = 0; |
| for (i = 0; i < rn; i++) |
| { |
| t = -rp[i] - cy; |
| rp[i] = LO (t); |
| cy = LO (-HI (t)); |
| } |
| SIZ (r) = -rn; |
| return; |
| } |
| |
| mpn_normalize (rp, &rn); |
| SIZ (r) = rn; |
| } |
| |
| void |
| mpz_sub_ui (mpz_t r, mpz_t a, unsigned long int ui) |
| { |
| mpz_t b; |
| |
| mpz_init (b); |
| mpz_set_ui (b, ui); |
| mpz_sub (r, a, b); |
| mpz_clear (b); |
| } |
| |
| void |
| mpz_mul (mpz_t r, mpz_t a, mpz_t b) |
| { |
| int an = ABSIZ (a), bn = ABSIZ (b), rn; |
| mp_limb_t *scratch, *tmp, *ap = PTR (a), *bp = PTR (b); |
| int ai, bi; |
| mp_limb_t t, cy; |
| |
| scratch = xmalloc_limbs (an + bn); |
| tmp = scratch; |
| |
| for (bi = 0; bi < bn; bi++) |
| tmp[bi] = 0; |
| |
| for (ai = 0; ai < an; ai++) |
| { |
| tmp = scratch + ai; |
| cy = 0; |
| for (bi = 0; bi < bn; bi++) |
| { |
| t = ap[ai] * bp[bi] + tmp[bi] + cy; |
| tmp[bi] = LO (t); |
| cy = HI (t); |
| } |
| tmp[bn] = cy; |
| } |
| |
| rn = an + bn; |
| mpn_normalize (scratch, &rn); |
| free (PTR (r)); |
| PTR (r) = scratch; |
| SIZ (r) = (SIZ (a) ^ SIZ (b)) >= 0 ? rn : -rn; |
| ALLOC (r) = an + bn; |
| } |
| |
| void |
| mpz_mul_ui (mpz_t r, mpz_t a, unsigned long int ui) |
| { |
| mpz_t b; |
| |
| mpz_init (b); |
| mpz_set_ui (b, ui); |
| mpz_mul (r, a, b); |
| mpz_clear (b); |
| } |
| |
| void |
| mpz_mul_2exp (mpz_t r, mpz_t a, unsigned long int bcnt) |
| { |
| mpz_set (r, a); |
| while (bcnt) |
| { |
| mpz_add (r, r, r); |
| bcnt -= 1; |
| } |
| } |
| |
| void |
| mpz_ui_pow_ui (mpz_t r, unsigned long b, unsigned long e) |
| { |
| unsigned long i; |
| mpz_t bz; |
| |
| mpz_init (bz); |
| mpz_set_ui (bz, b); |
| |
| mpz_set_ui (r, 1L); |
| for (i = 0; i < e; i++) |
| mpz_mul (r, r, bz); |
| |
| mpz_clear (bz); |
| } |
| |
| void |
| mpz_tdiv_q_2exp (mpz_t r, mpz_t a, unsigned long int bcnt) |
| { |
| int as, rn; |
| int cnt, tnc; |
| int lcnt; |
| mp_limb_t high_limb, low_limb; |
| int i; |
| |
| as = SIZ (a); |
| lcnt = bcnt / GMP_LIMB_BITS; |
| rn = ABS (as) - lcnt; |
| if (rn <= 0) |
| SIZ (r) = 0; |
| else |
| { |
| mp_limb_t *rp, *ap; |
| |
| mpz_realloc (r, rn); |
| |
| rp = PTR (r); |
| ap = PTR (a); |
| |
| cnt = bcnt % GMP_LIMB_BITS; |
| if (cnt != 0) |
| { |
| ap += lcnt; |
| tnc = GMP_LIMB_BITS - cnt; |
| high_limb = *ap++; |
| low_limb = high_limb >> cnt; |
| |
| for (i = rn - 1; i != 0; i--) |
| { |
| high_limb = *ap++; |
| *rp++ = low_limb | LO (high_limb << tnc); |
| low_limb = high_limb >> cnt; |
| } |
| *rp = low_limb; |
| rn -= low_limb == 0; |
| } |
| else |
| { |
| ap += lcnt; |
| mpn_copyi (rp, ap, rn); |
| } |
| |
| SIZ (r) = as >= 0 ? rn : -rn; |
| } |
| } |
| |
| void |
| mpz_tdiv_r_2exp (mpz_t r, mpz_t a, unsigned long int bcnt) |
| { |
| int rn, bwhole; |
| |
| mpz_set (r, a); |
| rn = ABSIZ(r); |
| |
| bwhole = bcnt / GMP_LIMB_BITS; |
| bcnt %= GMP_LIMB_BITS; |
| if (rn > bwhole) |
| { |
| rn = bwhole+1; |
| PTR(r)[rn-1] &= ((mp_limb_t) 1 << bcnt) - 1; |
| mpn_normalize (PTR(r), &rn); |
| SIZ(r) = (SIZ(r) >= 0 ? rn : -rn); |
| } |
| } |
| |
| int |
| mpz_cmp (mpz_t a, mpz_t b) |
| { |
| mp_limb_t *ap, *bp, al, bl; |
| int as = SIZ (a), bs = SIZ (b); |
| int i; |
| int sign; |
| |
| if (as != bs) |
| return as > bs ? 1 : -1; |
| |
| sign = as > 0 ? 1 : -1; |
| |
| ap = PTR (a); |
| bp = PTR (b); |
| for (i = ABS (as) - 1; i >= 0; i--) |
| { |
| al = ap[i]; |
| bl = bp[i]; |
| if (al != bl) |
| return al > bl ? sign : -sign; |
| } |
| return 0; |
| } |
| |
| int |
| mpz_cmp_ui (mpz_t a, unsigned long b) |
| { |
| mpz_t bz; |
| int ret; |
| mpz_init_set_ui (bz, b); |
| ret = mpz_cmp (a, bz); |
| mpz_clear (bz); |
| return ret; |
| } |
| |
| void |
| mpz_tdiv_qr (mpz_t q, mpz_t r, mpz_t a, mpz_t b) |
| { |
| mpz_t tmpr, tmpb; |
| unsigned long cnt; |
| |
| ASSERT (mpz_sgn(a) >= 0); |
| ASSERT (mpz_sgn(b) > 0); |
| |
| mpz_init_set (tmpr, a); |
| mpz_init_set (tmpb, b); |
| mpz_set_ui (q, 0L); |
| |
| if (mpz_cmp (tmpr, tmpb) > 0) |
| { |
| cnt = mpz_sizeinbase (tmpr, 2) - mpz_sizeinbase (tmpb, 2) + 1; |
| mpz_mul_2exp (tmpb, tmpb, cnt); |
| |
| for ( ; cnt > 0; cnt--) |
| { |
| mpz_mul_2exp (q, q, 1); |
| mpz_tdiv_q_2exp (tmpb, tmpb, 1L); |
| if (mpz_cmp (tmpr, tmpb) >= 0) |
| { |
| mpz_sub (tmpr, tmpr, tmpb); |
| mpz_add_ui (q, q, 1L); |
| ASSERT (mpz_cmp (tmpr, tmpb) < 0); |
| } |
| } |
| } |
| |
| mpz_set (r, tmpr); |
| mpz_clear (tmpr); |
| mpz_clear (tmpb); |
| } |
| |
| void |
| mpz_tdiv_qr_ui (mpz_t q, mpz_t r, mpz_t a, unsigned long b) |
| { |
| mpz_t bz; |
| mpz_init_set_ui (bz, b); |
| mpz_tdiv_qr (q, r, a, bz); |
| mpz_clear (bz); |
| } |
| |
| void |
| mpz_tdiv_q (mpz_t q, mpz_t a, mpz_t b) |
| { |
| mpz_t r; |
| |
| mpz_init (r); |
| mpz_tdiv_qr (q, r, a, b); |
| mpz_clear (r); |
| } |
| |
| void |
| mpz_tdiv_q_ui (mpz_t q, mpz_t n, unsigned long d) |
| { |
| mpz_t dz; |
| mpz_init_set_ui (dz, d); |
| mpz_tdiv_q (q, n, dz); |
| mpz_clear (dz); |
| } |
| |
| /* Set inv to the inverse of d, in the style of invert_limb, ie. for |
| udiv_qrnnd_preinv. */ |
| void |
| mpz_preinv_invert (mpz_t inv, mpz_t d, int numb_bits) |
| { |
| mpz_t t; |
| int norm; |
| ASSERT (SIZ(d) > 0); |
| |
| norm = numb_bits - mpz_sizeinbase (d, 2); |
| ASSERT (norm >= 0); |
| mpz_init_set_ui (t, 1L); |
| mpz_mul_2exp (t, t, 2*numb_bits - norm); |
| mpz_tdiv_q (inv, t, d); |
| mpz_set_ui (t, 1L); |
| mpz_mul_2exp (t, t, numb_bits); |
| mpz_sub (inv, inv, t); |
| |
| mpz_clear (t); |
| } |
| |
| /* Remove leading '0' characters from the start of a string, by copying the |
| remainder down. */ |
| void |
| strstrip_leading_zeros (char *s) |
| { |
| char c, *p; |
| |
| p = s; |
| while (*s == '0') |
| s++; |
| |
| do |
| { |
| c = *s++; |
| *p++ = c; |
| } |
| while (c != '\0'); |
| } |
| |
| char * |
| mpz_get_str (char *buf, int base, mpz_t a) |
| { |
| static char tohex[] = "0123456789abcdef"; |
| |
| mp_limb_t alimb, *ap; |
| int an, bn, i, j; |
| char *bp; |
| |
| if (base != 16) |
| abort (); |
| if (SIZ (a) < 0) |
| abort (); |
| |
| if (buf == 0) |
| buf = xmalloc (ABSIZ (a) * (GMP_LIMB_BITS / 4) + 3); |
| |
| an = ABSIZ (a); |
| if (an == 0) |
| { |
| buf[0] = '0'; |
| buf[1] = '\0'; |
| return buf; |
| } |
| |
| ap = PTR (a); |
| bn = an * (GMP_LIMB_BITS / 4); |
| bp = buf + bn; |
| |
| for (i = 0; i < an; i++) |
| { |
| alimb = ap[i]; |
| for (j = 0; j < GMP_LIMB_BITS / 4; j++) |
| { |
| bp--; |
| *bp = tohex [alimb & 0xF]; |
| alimb >>= 4; |
| } |
| ASSERT (alimb == 0); |
| } |
| ASSERT (bp == buf); |
| |
| buf[bn] = '\0'; |
| |
| strstrip_leading_zeros (buf); |
| return buf; |
| } |
| |
| void |
| mpz_out_str (FILE *file, int base, mpz_t a) |
| { |
| char *str; |
| |
| if (file == 0) |
| file = stdout; |
| |
| str = mpz_get_str (0, 16, a); |
| fputs (str, file); |
| free (str); |
| } |
| |
| /* Calculate r satisfying r*d == 1 mod 2^n. */ |
| void |
| mpz_invert_2exp (mpz_t r, mpz_t a, unsigned long n) |
| { |
| unsigned long i; |
| mpz_t inv, prod; |
| |
| ASSERT (mpz_odd_p (a)); |
| |
| mpz_init_set_ui (inv, 1L); |
| mpz_init (prod); |
| |
| for (i = 1; i < n; i++) |
| { |
| mpz_mul (prod, inv, a); |
| if (mpz_tstbit (prod, i) != 0) |
| mpz_setbit (inv, i); |
| } |
| |
| mpz_mul (prod, inv, a); |
| mpz_tdiv_r_2exp (prod, prod, n); |
| ASSERT (mpz_cmp_ui (prod, 1L) == 0); |
| |
| mpz_set (r, inv); |
| |
| mpz_clear (inv); |
| mpz_clear (prod); |
| } |
| |
| /* Calculate inv satisfying r*a == 1 mod 2^n. */ |
| void |
| mpz_invert_ui_2exp (mpz_t r, unsigned long a, unsigned long n) |
| { |
| mpz_t az; |
| mpz_init_set_ui (az, a); |
| mpz_invert_2exp (r, az, n); |
| mpz_clear (az); |
| } |
| |
| /* x=y^z */ |
| void |
| mpz_pow_ui (mpz_t x, mpz_t y, unsigned long z) |
| { |
| mpz_t t; |
| |
| mpz_init_set_ui (t, 1); |
| for (; z != 0; z--) |
| mpz_mul (t, t, y); |
| mpz_set (x, t); |
| mpz_clear (t); |
| } |
| |
| /* x=x+y*z */ |
| void |
| mpz_addmul_ui (mpz_t x, mpz_t y, unsigned long z) |
| { |
| mpz_t t; |
| |
| mpz_init (t); |
| mpz_mul_ui (t, y, z); |
| mpz_add (x, x, t); |
| mpz_clear (t); |
| } |
| |
| /* x=floor(y^(1/z)) */ |
| void |
| mpz_root (mpz_t x, mpz_t y, unsigned long z) |
| { |
| mpz_t t, u; |
| |
| if (mpz_sgn (y) < 0) |
| { |
| fprintf (stderr, "mpz_root does not accept negative values\n"); |
| abort (); |
| } |
| if (mpz_cmp_ui (y, 1) <= 0) |
| { |
| mpz_set (x, y); |
| return; |
| } |
| mpz_init (t); |
| mpz_init_set (u, y); |
| do |
| { |
| mpz_pow_ui (t, u, z - 1); |
| mpz_tdiv_q (t, y, t); |
| mpz_addmul_ui (t, u, z - 1); |
| mpz_tdiv_q_ui (t, t, z); |
| if (mpz_cmp (t, u) >= 0) |
| break; |
| mpz_set (u, t); |
| } |
| while (1); |
| mpz_set (x, u); |
| mpz_clear (t); |
| mpz_clear (u); |
| } |