/* mini-gmp, a minimalistic implementation of a GNU GMP subset.
Contributed to the GNU project by Niels Möller
Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1999, 2000, 2001,
2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
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/. */
/* NOTE: All functions in this file which are not declared in
mini-gmp.h are internal, and are not intended to be compatible
neither with GMP nor with future versions of mini-gmp. */
/* Much of the material copied from GMP files, including: gmp-impl.h,
longlong.h, mpn/generic/add_n.c, mpn/generic/addmul_1.c,
mpn/generic/lshift.c, mpn/generic/mul_1.c,
mpn/generic/mul_basecase.c, mpn/generic/rshift.c,
mpn/generic/sbpi1_div_qr.c, mpn/generic/sub_n.c,
mpn/generic/submul_1.c. */
#include <assert.h>
#include <ctype.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "mini-gmp.h"
/* Macros */
#define GMP_LIMB_BITS (sizeof(mp_limb_t) * CHAR_BIT)
#define GMP_LIMB_MAX (~ (mp_limb_t) 0)
#define GMP_LIMB_HIGHBIT ((mp_limb_t) 1 << (GMP_LIMB_BITS - 1))
#define GMP_HLIMB_BIT ((mp_limb_t) 1 << (GMP_LIMB_BITS / 2))
#define GMP_LLIMB_MASK (GMP_HLIMB_BIT - 1)
#define GMP_ULONG_BITS (sizeof(unsigned long) * CHAR_BIT)
#define GMP_ULONG_HIGHBIT ((unsigned long) 1 << (GMP_ULONG_BITS - 1))
#define GMP_ABS(x) ((x) >= 0 ? (x) : -(x))
#define GMP_NEG_CAST(T,x) (-((T)((x) + 1) - 1))
#define GMP_MIN(a, b) ((a) < (b) ? (a) : (b))
#define GMP_MAX(a, b) ((a) > (b) ? (a) : (b))
#define gmp_assert_nocarry(x) do { \
mp_limb_t __cy = x; \
assert (__cy == 0); \
} while (0)
#define gmp_clz(count, x) do { \
mp_limb_t __clz_x = (x); \
unsigned __clz_c; \
for (__clz_c = 0; \
(__clz_x & ((mp_limb_t) 0xff << (GMP_LIMB_BITS - 8))) == 0; \
__clz_c += 8) \
__clz_x <<= 8; \
for (; (__clz_x & GMP_LIMB_HIGHBIT) == 0; __clz_c++) \
__clz_x <<= 1; \
(count) = __clz_c; \
} while (0)
#define gmp_ctz(count, x) do { \
mp_limb_t __ctz_x = (x); \
unsigned __ctz_c = 0; \
gmp_clz (__ctz_c, __ctz_x & - __ctz_x); \
(count) = GMP_LIMB_BITS - 1 - __ctz_c; \
} while (0)
#define gmp_add_ssaaaa(sh, sl, ah, al, bh, bl) \
do { \
mp_limb_t __x; \
__x = (al) + (bl); \
(sh) = (ah) + (bh) + (__x < (al)); \
(sl) = __x; \
} while (0)
#define gmp_sub_ddmmss(sh, sl, ah, al, bh, bl) \
do { \
mp_limb_t __x; \
__x = (al) - (bl); \
(sh) = (ah) - (bh) - ((al) < (bl)); \
(sl) = __x; \
} while (0)
#define gmp_umul_ppmm(w1, w0, u, v) \
do { \
mp_limb_t __x0, __x1, __x2, __x3; \
unsigned __ul, __vl, __uh, __vh; \
mp_limb_t __u = (u), __v = (v); \
\
__ul = __u & GMP_LLIMB_MASK; \
__uh = __u >> (GMP_LIMB_BITS / 2); \
__vl = __v & GMP_LLIMB_MASK; \
__vh = __v >> (GMP_LIMB_BITS / 2); \
\
__x0 = (mp_limb_t) __ul * __vl; \
__x1 = (mp_limb_t) __ul * __vh; \
__x2 = (mp_limb_t) __uh * __vl; \
__x3 = (mp_limb_t) __uh * __vh; \
\
__x1 += __x0 >> (GMP_LIMB_BITS / 2);/* this can't give carry */ \
__x1 += __x2; /* but this indeed can */ \
if (__x1 < __x2) /* did we get it? */ \
__x3 += GMP_HLIMB_BIT; /* yes, add it in the proper pos. */ \
\
(w1) = __x3 + (__x1 >> (GMP_LIMB_BITS / 2)); \
(w0) = (__x1 << (GMP_LIMB_BITS / 2)) + (__x0 & GMP_LLIMB_MASK); \
} while (0)
#define gmp_udiv_qrnnd_preinv(q, r, nh, nl, d, di) \
do { \
mp_limb_t _qh, _ql, _r, _mask; \
gmp_umul_ppmm (_qh, _ql, (nh), (di)); \
gmp_add_ssaaaa (_qh, _ql, _qh, _ql, (nh) + 1, (nl)); \
_r = (nl) - _qh * (d); \
_mask = -(mp_limb_t) (_r > _ql); /* both > and >= are OK */ \
_qh += _mask; \
_r += _mask & (d); \
if (_r >= (d)) \
{ \
_r -= (d); \
_qh++; \
} \
\
(r) = _r; \
(q) = _qh; \
} while (0)
#define gmp_udiv_qr_3by2(q, r1, r0, n2, n1, n0, d1, d0, dinv) \
do { \
mp_limb_t _q0, _t1, _t0, _mask; \
gmp_umul_ppmm ((q), _q0, (n2), (dinv)); \
gmp_add_ssaaaa ((q), _q0, (q), _q0, (n2), (n1)); \
\
/* Compute the two most significant limbs of n - q'd */ \
(r1) = (n1) - (d1) * (q); \
gmp_sub_ddmmss ((r1), (r0), (r1), (n0), (d1), (d0)); \
gmp_umul_ppmm (_t1, _t0, (d0), (q)); \
gmp_sub_ddmmss ((r1), (r0), (r1), (r0), _t1, _t0); \
(q)++; \
\
/* Conditionally adjust q and the remainders */ \
_mask = - (mp_limb_t) ((r1) >= _q0); \
(q) += _mask; \
gmp_add_ssaaaa ((r1), (r0), (r1), (r0), _mask & (d1), _mask & (d0)); \
if ((r1) >= (d1)) \
{ \
if ((r1) > (d1) || (r0) >= (d0)) \
{ \
(q)++; \
gmp_sub_ddmmss ((r1), (r0), (r1), (r0), (d1), (d0)); \
} \
} \
} while (0)
/* Swap macros. */
#define MP_LIMB_T_SWAP(x, y) \
do { \
mp_limb_t __mp_limb_t_swap__tmp = (x); \
(x) = (y); \
(y) = __mp_limb_t_swap__tmp; \
} while (0)
#define MP_SIZE_T_SWAP(x, y) \
do { \
mp_size_t __mp_size_t_swap__tmp = (x); \
(x) = (y); \
(y) = __mp_size_t_swap__tmp; \
} while (0)
#define MP_BITCNT_T_SWAP(x,y) \
do { \
mp_bitcnt_t __mp_bitcnt_t_swap__tmp = (x); \
(x) = (y); \
(y) = __mp_bitcnt_t_swap__tmp; \
} while (0)
#define MP_PTR_SWAP(x, y) \
do { \
mp_ptr __mp_ptr_swap__tmp = (x); \
(x) = (y); \
(y) = __mp_ptr_swap__tmp; \
} while (0)
#define MP_SRCPTR_SWAP(x, y) \
do { \
mp_srcptr __mp_srcptr_swap__tmp = (x); \
(x) = (y); \
(y) = __mp_srcptr_swap__tmp; \
} while (0)
#define MPN_PTR_SWAP(xp,xs, yp,ys) \
do { \
MP_PTR_SWAP (xp, yp); \
MP_SIZE_T_SWAP (xs, ys); \
} while(0)
#define MPN_SRCPTR_SWAP(xp,xs, yp,ys) \
do { \
MP_SRCPTR_SWAP (xp, yp); \
MP_SIZE_T_SWAP (xs, ys); \
} while(0)
#define MPZ_PTR_SWAP(x, y) \
do { \
mpz_ptr __mpz_ptr_swap__tmp = (x); \
(x) = (y); \
(y) = __mpz_ptr_swap__tmp; \
} while (0)
#define MPZ_SRCPTR_SWAP(x, y) \
do { \
mpz_srcptr __mpz_srcptr_swap__tmp = (x); \
(x) = (y); \
(y) = __mpz_srcptr_swap__tmp; \
} while (0)
/* Memory allocation and other helper functions. */
static void
gmp_die (const char *msg)
{
fprintf (stderr, "%s\n", msg);
abort();
}
static void *
gmp_default_alloc (size_t size)
{
void *p;
assert (size > 0);
p = malloc (size);
if (!p)
gmp_die("gmp_default_alloc: Virtual memory exhausted.");
return p;
}
static void *
gmp_default_realloc (void *old, size_t old_size, size_t new_size)
{
mp_ptr p;
p = realloc (old, new_size);
if (!p)
gmp_die("gmp_default_realoc: Virtual memory exhausted.");
return p;
}
static void
gmp_default_free (void *p, size_t size)
{
free (p);
}
static void * (*gmp_allocate_func) (size_t) = gmp_default_alloc;
static void * (*gmp_reallocate_func) (void *, size_t, size_t) = gmp_default_realloc;
static void (*gmp_free_func) (void *, size_t) = gmp_default_free;
void
mp_get_memory_functions (void *(**alloc_func) (size_t),
void *(**realloc_func) (void *, size_t, size_t),
void (**free_func) (void *, size_t))
{
if (alloc_func)
*alloc_func = gmp_allocate_func;
if (realloc_func)
*realloc_func = gmp_reallocate_func;
if (free_func)
*free_func = gmp_free_func;
}
void
mp_set_memory_functions (void *(*alloc_func) (size_t),
void *(*realloc_func) (void *, size_t, size_t),
void (*free_func) (void *, size_t))
{
if (!alloc_func)
alloc_func = gmp_default_alloc;
if (!realloc_func)
realloc_func = gmp_default_realloc;
if (!free_func)
free_func = gmp_default_free;
gmp_allocate_func = alloc_func;
gmp_reallocate_func = realloc_func;
gmp_free_func = free_func;
}
#define gmp_xalloc(size) ((*gmp_allocate_func)((size)))
#define gmp_free(p) ((*gmp_free_func) ((p), 0))
static mp_ptr
gmp_xalloc_limbs (mp_size_t size)
{
return gmp_xalloc (size * sizeof (mp_limb_t));
}
static mp_ptr
gmp_xrealloc_limbs (mp_ptr old, mp_size_t size)
{
assert (size > 0);
return (*gmp_reallocate_func) (old, 0, size * sizeof (mp_limb_t));
}
/* MPN interface */
void
mpn_copyi (mp_ptr d, mp_srcptr s, mp_size_t n)
{
mp_size_t i;
for (i = 0; i < n; i++)
d[i] = s[i];
}
void
mpn_copyd (mp_ptr d, mp_srcptr s, mp_size_t n)
{
while (n-- > 0)
d[n] = s[n];
}
int
mpn_cmp (mp_srcptr ap, mp_srcptr bp, mp_size_t n)
{
for (; n > 0; n--)
{
if (ap[n-1] < bp[n-1])
return -1;
else if (ap[n-1] > bp[n-1])
return 1;
}
return 0;
}
static int
mpn_cmp4 (mp_srcptr ap, mp_size_t an, mp_srcptr bp, mp_size_t bn)
{
if (an > bn)
return 1;
else if (an < bn)
return -1;
else
return mpn_cmp (ap, bp, an);
}
static mp_size_t
mpn_normalized_size (mp_srcptr xp, mp_size_t n)
{
for (; n > 0 && xp[n-1] == 0; n--)
;
return n;
}
#define mpn_zero_p(xp, n) (mpn_normalized_size ((xp), (n)) == 0)
mp_limb_t
mpn_add_1 (mp_ptr rp, mp_srcptr ap, mp_size_t n, mp_limb_t b)
{
mp_size_t i;
assert (n > 0);
for (i = 0; i < n; i++)
{
mp_limb_t r = ap[i] + b;
/* Carry out */
b = (r < b);
rp[i] = r;
}
return b;
}
mp_limb_t
mpn_add_n (mp_ptr rp, mp_srcptr ap, mp_srcptr bp, mp_size_t n)
{
mp_size_t i;
mp_limb_t cy;
for (i = 0, cy = 0; i < n; i++)
{
mp_limb_t a, b, r;
a = ap[i]; b = bp[i];
r = a + cy;
cy = (r < cy);
r += b;
cy += (r < b);
rp[i] = r;
}
return cy;
}
mp_limb_t
mpn_add (mp_ptr rp, mp_srcptr ap, mp_size_t an, mp_srcptr bp, mp_size_t bn)
{
mp_limb_t cy;
assert (an >= bn);
cy = mpn_add_n (rp, ap, bp, bn);
if (an > bn)
cy = mpn_add_1 (rp + bn, ap + bn, an - bn, cy);
return cy;
}
mp_limb_t
mpn_sub_1 (mp_ptr rp, mp_srcptr ap, mp_size_t n, mp_limb_t b)
{
mp_size_t i;
assert (n > 0);
for (i = 0; i < n; i++)
{
mp_limb_t a = ap[i];
/* Carry out */
mp_limb_t cy = a < b;;
rp[i] = a - b;
b = cy;
}
return b;
}
mp_limb_t
mpn_sub_n (mp_ptr rp, mp_srcptr ap, mp_srcptr bp, mp_size_t n)
{
mp_size_t i;
mp_limb_t cy;
for (i = 0, cy = 0; i < n; i++)
{
mp_limb_t a, b;
a = ap[i]; b = bp[i];
b += cy;
cy = (b < cy);
cy += (a < b);
rp[i] = a - b;
}
return cy;
}
mp_limb_t
mpn_sub (mp_ptr rp, mp_srcptr ap, mp_size_t an, mp_srcptr bp, mp_size_t bn)
{
mp_limb_t cy;
assert (an >= bn);
cy = mpn_sub_n (rp, ap, bp, bn);
if (an > bn)
cy = mpn_sub_1 (rp + bn, ap + bn, an - bn, cy);
return cy;
}
mp_limb_t
mpn_mul_1 (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_limb_t vl)
{
mp_limb_t ul, cl, hpl, lpl;
assert (n >= 1);
cl = 0;
do
{
ul = *up++;
gmp_umul_ppmm (hpl, lpl, ul, vl);
lpl += cl;
cl = (lpl < cl) + hpl;
*rp++ = lpl;
}
while (--n != 0);
return cl;
}
mp_limb_t
mpn_addmul_1 (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_limb_t vl)
{
mp_limb_t ul, cl, hpl, lpl, rl;
assert (n >= 1);
cl = 0;
do
{
ul = *up++;
gmp_umul_ppmm (hpl, lpl, ul, vl);
lpl += cl;
cl = (lpl < cl) + hpl;
rl = *rp;
lpl = rl + lpl;
cl += lpl < rl;
*rp++ = lpl;
}
while (--n != 0);
return cl;
}
mp_limb_t
mpn_submul_1 (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_limb_t vl)
{
mp_limb_t ul, cl, hpl, lpl, rl;
assert (n >= 1);
cl = 0;
do
{
ul = *up++;
gmp_umul_ppmm (hpl, lpl, ul, vl);
lpl += cl;
cl = (lpl < cl) + hpl;
rl = *rp;
lpl = rl - lpl;
cl += lpl > rl;
*rp++ = lpl;
}
while (--n != 0);
return cl;
}
mp_limb_t
mpn_mul (mp_ptr rp, mp_srcptr up, mp_size_t un, mp_srcptr vp, mp_size_t vn)
{
assert (un >= vn);
assert (vn >= 1);
/* We first multiply by the low order limb. This result can be
stored, not added, to rp. We also avoid a loop for zeroing this
way. */
rp[un] = mpn_mul_1 (rp, up, un, vp[0]);
rp += 1, vp += 1, vn -= 1;
/* Now accumulate the product of up[] and the next higher limb from
vp[]. */
while (vn >= 1)
{
rp[un] = mpn_addmul_1 (rp, up, un, vp[0]);
rp += 1, vp += 1, vn -= 1;
}
return rp[un - 1];
}
void
mpn_mul_n (mp_ptr rp, mp_srcptr ap, mp_srcptr bp, mp_size_t n)
{
mpn_mul (rp, ap, n, bp, n);
}
void
mpn_sqr (mp_ptr rp, mp_srcptr ap, mp_size_t n)
{
mpn_mul (rp, ap, n, ap, n);
}
mp_limb_t
mpn_lshift (mp_ptr rp, mp_srcptr up, mp_size_t n, unsigned int cnt)
{
mp_limb_t high_limb, low_limb;
unsigned int tnc;
mp_size_t i;
mp_limb_t retval;
assert (n >= 1);
assert (cnt >= 1);
assert (cnt < GMP_LIMB_BITS);
up += n;
rp += n;
tnc = GMP_LIMB_BITS - cnt;
low_limb = *--up;
retval = low_limb >> tnc;
high_limb = (low_limb << cnt);
for (i = n - 1; i != 0; i--)
{
low_limb = *--up;
*--rp = high_limb | (low_limb >> tnc);
high_limb = (low_limb << cnt);
}
*--rp = high_limb;
return retval;
}
mp_limb_t
mpn_rshift (mp_ptr rp, mp_srcptr up, mp_size_t n, unsigned int cnt)
{
mp_limb_t high_limb, low_limb;
unsigned int tnc;
mp_size_t i;
mp_limb_t retval;
assert (n >= 1);
assert (cnt >= 1);
assert (cnt < GMP_LIMB_BITS);
tnc = GMP_LIMB_BITS - cnt;
high_limb = *up++;
retval = (high_limb << tnc);
low_limb = high_limb >> cnt;
for (i = n - 1; i != 0; i--)
{
high_limb = *up++;
*rp++ = low_limb | (high_limb << tnc);
low_limb = high_limb >> cnt;
}
*rp = low_limb;
return retval;
}
/* MPN division interface. */
mp_limb_t
mpn_invert_3by2 (mp_limb_t u1, mp_limb_t u0)
{
mp_limb_t r, p, m;
unsigned ul, uh;
unsigned ql, qh;
/* First, do a 2/1 inverse. */
/* The inverse m is defined as floor( (B^2 - 1 - u1)/u1 ), so that 0 <
* B^2 - (B + m) u1 <= u1 */
assert (u1 >= GMP_LIMB_HIGHBIT);
ul = u1 & GMP_LLIMB_MASK;
uh = u1 >> (GMP_LIMB_BITS / 2);
qh = ~u1 / uh;
r = ((~u1 - (mp_limb_t) qh * uh) << (GMP_LIMB_BITS / 2)) | GMP_LLIMB_MASK;
p = (mp_limb_t) qh * ul;
/* Adjustment steps taken from udiv_qrnnd_c */
if (r < p)
{
qh--;
r += u1;
if (r >= u1) /* i.e. we didn't get carry when adding to r */
if (r < p)
{
qh--;
r += u1;
}
}
r -= p;
/* Do a 3/2 division (with half limb size) */
p = (r >> (GMP_LIMB_BITS / 2)) * qh + r;
ql = (p >> (GMP_LIMB_BITS / 2)) + 1;
/* By the 3/2 method, we don't need the high half limb. */
r = (r << (GMP_LIMB_BITS / 2)) + GMP_LLIMB_MASK - ql * u1;
if (r >= (p << (GMP_LIMB_BITS / 2)))
{
ql--;
r += u1;
}
m = ((mp_limb_t) qh << (GMP_LIMB_BITS / 2)) + ql;
if (r >= u1)
{
m++;
r -= u1;
}
if (u0 > 0)
{
mp_limb_t th, tl;
r = ~r;
r += u0;
if (r < u0)
{
m--;
if (r >= u1)
{
m--;
r -= u1;
}
r -= u1;
}
gmp_umul_ppmm (th, tl, u0, m);
r += th;
if (r < th)
{
m--;
if (r > u1 || (r == u1 && tl > u0))
m--;
}
}
return m;
}
struct gmp_div_inverse
{
/* Normalization shift count. */
unsigned shift;
/* Normalized divisor (d0 unused for mpn_div_qr_1) */
mp_limb_t d1, d0;
/* Inverse, for 2/1 or 3/2. */
mp_limb_t di;
};
static void
mpn_div_qr_1_invert (struct gmp_div_inverse *inv, mp_limb_t d)
{
unsigned shift;
assert (d > 0);
gmp_clz (shift, d);
inv->shift = shift;
inv->d1 = d << shift;
inv->di = mpn_invert_limb (inv->d1);
}
static void
mpn_div_qr_2_invert (struct gmp_div_inverse *inv,
mp_limb_t d1, mp_limb_t d0)
{
unsigned shift;
assert (d1 > 0);
gmp_clz (shift, d1);
inv->shift = shift;
if (shift > 0)
{
d1 = (d1 << shift) | (d0 >> (GMP_LIMB_BITS - shift));
d0 <<= shift;
}
inv->d1 = d1;
inv->d0 = d0;
inv->di = mpn_invert_3by2 (d1, d0);
}
static void
mpn_div_qr_invert (struct gmp_div_inverse *inv,
mp_srcptr dp, mp_size_t dn)
{
assert (dn > 0);
if (dn == 1)
mpn_div_qr_1_invert (inv, dp[0]);
else if (dn == 2)
mpn_div_qr_2_invert (inv, dp[1], dp[0]);
else
{
unsigned shift;
mp_limb_t d1, d0;
d1 = dp[dn-1];
d0 = dp[dn-2];
assert (d1 > 0);
gmp_clz (shift, d1);
inv->shift = shift;
if (shift > 0)
{
d1 = (d1 << shift) | (d0 >> (GMP_LIMB_BITS - shift));
d0 = (d0 << shift) | (dp[dn-3] >> (GMP_LIMB_BITS - shift));
}
inv->d1 = d1;
inv->d0 = d0;
inv->di = mpn_invert_3by2 (d1, d0);
}
}
/* Not matching current public gmp interface, rather corresponding to
the sbpi1_div_* functions. */
static mp_limb_t
mpn_div_qr_1_preinv (mp_ptr qp, mp_srcptr np, mp_size_t nn,
const struct gmp_div_inverse *inv)
{
mp_limb_t d, di;
mp_limb_t r;
mp_ptr tp = NULL;
if (inv->shift > 0)
{
tp = gmp_xalloc_limbs (nn);
r = mpn_lshift (tp, np, nn, inv->shift);
np = tp;
}
else
r = 0;
d = inv->d1;
di = inv->di;
while (nn-- > 0)
{
mp_limb_t q;
gmp_udiv_qrnnd_preinv (q, r, r, np[nn], d, di);
if (qp)
qp[nn] = q;
}
if (inv->shift > 0)
gmp_free (tp);
return r >> inv->shift;
}
static mp_limb_t
mpn_div_qr_1 (mp_ptr qp, mp_srcptr np, mp_size_t nn, mp_limb_t d)
{
assert (d > 0);
/* Special case for powers of two. */
if (d > 1 && (d & (d-1)) == 0)
{
unsigned shift;
mp_limb_t r = np[0] & (d-1);
gmp_ctz (shift, d);
if (qp)
mpn_rshift (qp, np, nn, shift);
return r;
}
else
{
struct gmp_div_inverse inv;
mpn_div_qr_1_invert (&inv, d);
return mpn_div_qr_1_preinv (qp, np, nn, &inv);
}
}
static void
mpn_div_qr_2_preinv (mp_ptr qp, mp_ptr rp, mp_srcptr np, mp_size_t nn,
const struct gmp_div_inverse *inv)
{
unsigned shift;
mp_size_t i;
mp_limb_t d1, d0, di, r1, r0;
mp_ptr tp;
assert (nn >= 2);
shift = inv->shift;
d1 = inv->d1;
d0 = inv->d0;
di = inv->di;
if (shift > 0)
{
tp = gmp_xalloc_limbs (nn);
r1 = mpn_lshift (tp, np, nn, shift);
np = tp;
}
else
r1 = 0;
r0 = np[nn - 1];
for (i = nn - 2; i >= 0; i--)
{
mp_limb_t n0, q;
n0 = np[i];
gmp_udiv_qr_3by2 (q, r1, r0, r1, r0, n0, d1, d0, di);
if (qp)
qp[i] = q;
}
if (shift > 0)
{
assert ((r0 << (GMP_LIMB_BITS - shift)) == 0);
r0 = (r0 >> shift) | (r1 << (GMP_LIMB_BITS - shift));
r1 >>= shift;
gmp_free (tp);
}
rp[1] = r1;
rp[0] = r0;
}
#if 0
static void
mpn_div_qr_2 (mp_ptr qp, mp_ptr rp, mp_srcptr np, mp_size_t nn,
mp_limb_t d1, mp_limb_t d0)
{
struct gmp_div_inverse inv;
assert (nn >= 2);
mpn_div_qr_2_invert (&inv, d1, d0);
mpn_div_qr_2_preinv (qp, rp, np, nn, &inv);
}
#endif
static void
mpn_div_qr_pi1 (mp_ptr qp,
mp_ptr np, mp_size_t nn, mp_limb_t n1,
mp_srcptr dp, mp_size_t dn,
mp_limb_t dinv)
{
mp_size_t i;
mp_limb_t d1, d0;
mp_limb_t cy, cy1;
mp_limb_t q;
assert (dn > 2);
assert (nn >= dn);
d1 = dp[dn - 1];
d0 = dp[dn - 2];
assert ((d1 & GMP_LIMB_HIGHBIT) != 0);
/* Iteration variable is the index of the q limb.
*
* We divide <n1, np[dn-1+i], np[dn-2+i], np[dn-3+i],..., np[i]>
* by <d1, d0, dp[dn-3], ..., dp[0] >
*/
for (i = nn - dn; i >= 0; i--)
{
mp_limb_t n0 = np[dn-1+i];
if (n1 == d1 && n0 == d0)
{
q = GMP_LIMB_MAX;
mpn_submul_1 (np+i, dp, dn, q);
n1 = np[dn-1+i]; /* update n1, last loop's value will now be invalid */
}
else
{
gmp_udiv_qr_3by2 (q, n1, n0, n1, n0, np[dn-2+i], d1, d0, dinv);
cy = mpn_submul_1 (np + i, dp, dn-2, q);
cy1 = n0 < cy;
n0 = n0 - cy;
cy = n1 < cy1;
n1 = n1 - cy1;
np[dn-2+i] = n0;
if (cy != 0)
{
n1 += d1 + mpn_add_n (np + i, np + i, dp, dn - 1);
q--;
}
}
if (qp)
qp[i] = q;
}
np[dn - 1] = n1;
}
static void
mpn_div_qr_preinv (mp_ptr qp, mp_ptr np, mp_size_t nn,
mp_srcptr dp, mp_size_t dn,
const struct gmp_div_inverse *inv)
{
assert (dn > 0);
assert (nn >= dn);
if (dn == 1)
np[0] = mpn_div_qr_1_preinv (qp, np, nn, inv);
else if (dn == 2)
mpn_div_qr_2_preinv (qp, np, np, nn, inv);
else
{
mp_limb_t nh;
unsigned shift;
assert (inv->d1 == dp[dn-1]);
assert (inv->d0 == dp[dn-2]);
assert ((inv->d1 & GMP_LIMB_HIGHBIT) != 0);
shift = inv->shift;
if (shift > 0)
nh = mpn_lshift (np, np, nn, shift);
else
nh = 0;
mpn_div_qr_pi1 (qp, np, nn, nh, dp, dn, inv->di);
if (shift > 0)
gmp_assert_nocarry (mpn_rshift (np, np, dn, shift));
}
}
static void
mpn_div_qr (mp_ptr qp, mp_ptr np, mp_size_t nn, mp_srcptr dp, mp_size_t dn)
{
struct gmp_div_inverse inv;
mp_ptr tp = NULL;
assert (dn > 0);
assert (nn >= dn);
mpn_div_qr_invert (&inv, dp, dn);
if (dn > 2 && inv.shift > 0)
{
tp = gmp_xalloc_limbs (dn);
gmp_assert_nocarry (mpn_lshift (tp, dp, dn, inv.shift));
dp = tp;
}
mpn_div_qr_preinv (qp, np, nn, dp, dn, &inv);
if (tp)
gmp_free (tp);
}
/* MPN base conversion. */
static unsigned
mpn_base_power_of_two_p (unsigned b)
{
switch (b)
{
case 2: return 1;
case 4: return 2;
case 8: return 3;
case 16: return 4;
case 32: return 5;
case 64: return 6;
case 128: return 7;
case 256: return 8;
default: return 0;
}
}
struct mpn_base_info
{
/* bb is the largest power of the base which fits in one limb, and
exp is the corresponding exponent. */
unsigned exp;
mp_limb_t bb;
};
static void
mpn_get_base_info (struct mpn_base_info *info, mp_limb_t b)
{
mp_limb_t m;
mp_limb_t p;
unsigned exp;
m = GMP_LIMB_MAX / b;
for (exp = 1, p = b; p <= m; exp++)
p *= b;
info->exp = exp;
info->bb = p;
}
static mp_bitcnt_t
mpn_limb_size_in_base_2 (mp_limb_t u)
{
unsigned shift;
assert (u > 0);
gmp_clz (shift, u);
return GMP_LIMB_BITS - shift;
}
static size_t
mpn_get_str_bits (unsigned char *sp, unsigned bits, mp_srcptr up, mp_size_t un)
{
unsigned char mask;
size_t sn, j;
mp_size_t i;
int shift;
sn = ((un - 1) * GMP_LIMB_BITS + mpn_limb_size_in_base_2 (up[un-1])
+ bits - 1) / bits;
mask = (1U << bits) - 1;
for (i = 0, j = sn, shift = 0; j-- > 0;)
{
unsigned char digit = up[i] >> shift;
shift += bits;
if (shift >= GMP_LIMB_BITS && ++i < un)
{
shift -= GMP_LIMB_BITS;
digit |= up[i] << (bits - shift);
}
sp[j] = digit & mask;
}
return sn;
}
/* We generate digits from the least significant end, and reverse at
the end. */
static size_t
mpn_limb_get_str (unsigned char *sp, mp_limb_t w,
const struct gmp_div_inverse *binv)
{
mp_size_t i;
for (i = 0; w > 0; i++)
{
mp_limb_t h, l, r;
h = w >> (GMP_LIMB_BITS - binv->shift);
l = w << binv->shift;
gmp_udiv_qrnnd_preinv (w, r, h, l, binv->d1, binv->di);
assert ( (r << (GMP_LIMB_BITS - binv->shift)) == 0);
r >>= binv->shift;
sp[i] = r;
}
return i;
}
static size_t
mpn_get_str_other (unsigned char *sp,
int base, const struct mpn_base_info *info,
mp_ptr up, mp_size_t un)
{
struct gmp_div_inverse binv;
size_t sn;
size_t i;
mpn_div_qr_1_invert (&binv, base);
sn = 0;
if (un > 1)
{
struct gmp_div_inverse bbinv;
mpn_div_qr_1_invert (&bbinv, info->bb);
do
{
mp_limb_t w;
size_t done;
w = mpn_div_qr_1_preinv (up, up, un, &bbinv);
un -= (up[un-1] == 0);
done = mpn_limb_get_str (sp + sn, w, &binv);
for (sn += done; done < info->exp; done++)
sp[sn++] = 0;
}
while (un > 1);
}
sn += mpn_limb_get_str (sp + sn, up[0], &binv);
/* Reverse order */
for (i = 0; 2*i + 1 < sn; i++)
{
unsigned char t = sp[i];
sp[i] = sp[sn - i - 1];
sp[sn - i - 1] = t;
}
return sn;
}
size_t
mpn_get_str (unsigned char *sp, int base, mp_ptr up, mp_size_t un)
{
unsigned bits;
assert (un > 0);
assert (up[un-1] > 0);
bits = mpn_base_power_of_two_p (base);
if (bits)
return mpn_get_str_bits (sp, bits, up, un);
else
{
struct mpn_base_info info;
mpn_get_base_info (&info, base);
return mpn_get_str_other (sp, base, &info, up, un);
}
}
static mp_size_t
mpn_set_str_bits (mp_ptr rp, const unsigned char *sp, size_t sn,
unsigned bits)
{
mp_size_t rn;
size_t j;
unsigned shift;
for (j = sn, rn = 0, shift = 0; j-- > 0; )
{
if (shift == 0)
{
rp[rn++] = sp[j];
shift += bits;
}
else
{
rp[rn-1] |= (mp_limb_t) sp[j] << shift;
shift += bits;
if (shift >= GMP_LIMB_BITS)
{
shift -= GMP_LIMB_BITS;
if (shift > 0)
rp[rn++] = (mp_limb_t) sp[j] >> (bits - shift);
}
}
}
rn = mpn_normalized_size (rp, rn);
return rn;
}
static mp_size_t
mpn_set_str_other (mp_ptr rp, const unsigned char *sp, size_t sn,
mp_limb_t b, const struct mpn_base_info *info)
{
mp_size_t rn;
mp_limb_t w;
unsigned first;
unsigned k;
size_t j;
first = 1 + (sn - 1) % info->exp;
j = 0;
w = sp[j++];
for (k = 1; k < first; k++)
w = w * b + sp[j++];
rp[0] = w;
for (rn = (w > 0); j < sn;)
{
mp_limb_t cy;
w = sp[j++];
for (k = 1; k < info->exp; k++)
w = w * b + sp[j++];
cy = mpn_mul_1 (rp, rp, rn, info->bb);
cy += mpn_add_1 (rp, rp, rn, w);
if (cy > 0)
rp[rn++] = cy;
}
assert (j == sn);
return rn;
}
mp_size_t
mpn_set_str (mp_ptr rp, const unsigned char *sp, size_t sn, int base)
{
unsigned bits;
if (sn == 0)
return 0;
bits = mpn_base_power_of_two_p (base);
if (bits)
return mpn_set_str_bits (rp, sp, sn, bits);
else
{
struct mpn_base_info info;
mpn_get_base_info (&info, base);
return mpn_set_str_other (rp, sp, sn, base, &info);
}
}
/* MPZ interface */
void
mpz_init (mpz_t r)
{
r->_mp_alloc = 1;
r->_mp_size = 0;
r->_mp_d = gmp_xalloc_limbs (1);
}
/* The utility of this function is a bit limited, since many functions
assings the result variable using mpz_swap. */
void
mpz_init2 (mpz_t r, mp_bitcnt_t bits)
{
mp_size_t rn;
bits -= (bits != 0); /* Round down, except if 0 */
rn = 1 + bits / GMP_LIMB_BITS;
r->_mp_alloc = rn;
r->_mp_size = 0;
r->_mp_d = gmp_xalloc_limbs (rn);
}
void
mpz_clear (mpz_t r)
{
|