#include <math.h>
#include "mpn_extras.h"
#include "double_extras.h"
#include "gmpcompat.h"
#include "fmpz.h"
void
fmpz_set(fmpz_t f, const fmpz_t g)
{
if (f == g)
return;
if (!COEFF_IS_MPZ(*g))
{
_fmpz_demote(f);
*f = *g;
}
else
{
mpz_ptr mf = _fmpz_promote(f);
mpz_set(mf, COEFF_TO_PTR(*g));
}
}
#if FLINT64
#define DOUBLE_MAX 9007199254740992.0
#define DOUBLE_MIN -9007199254740992.0
#else
#define DOUBLE_MAX COEFF_MAX
#define DOUBLE_MIN COEFF_MIN
#endif
void
fmpz_set_d(fmpz_t f, double c)
{
if (c >= DOUBLE_MIN && c <= DOUBLE_MAX)
{
_fmpz_demote(f);
*f = (slong) c;
}
else
{
mpz_ptr z = _fmpz_promote(f);
mpz_set_d(z, c);
_fmpz_demote_val(f);
}
}
void fmpz_set_d_2exp(fmpz_t f, double m, slong exp)
{
int exp2;
m = frexp(m, &exp2);
exp += exp2;
if (exp >= 53)
{
fmpz_set_d(f, m * ldexp(1.0, 53));
fmpz_mul_2exp(f, f, exp - 53);
} else if (exp < 0)
fmpz_set_ui(f, 0);
else
fmpz_set_d(f, d_mul_2exp_inrange(m, exp));
}
void
fmpz_set_mpf(fmpz_t f, const mpf_t x)
{
int check;
check = flint_mpf_fits_slong_p(x);
if (check)
{
slong cx = flint_mpf_get_si(x);
fmpz_set_si(f, cx);
}
else
{
mpz_ptr z = _fmpz_promote(f);
mpz_set_f(z, x);
}
}
void
fmpz_set_mpz(fmpz_t f, const mpz_t x)
{
int size = (slong) x->_mp_size;
if (size == 0)
fmpz_zero(f);
else if (size == 1)
fmpz_set_ui(f, flint_mpz_get_ui(x));
else if (size == -1)
fmpz_neg_ui(f, flint_mpz_get_ui(x));
else
mpz_set(_fmpz_promote(f), x);
}
void fmpz_set_signed_ui_array(fmpz_t f, const ulong * c, slong n)
{
ulong csign;
FLINT_ASSERT(n > 0);
csign = FLINT_SIGN_EXT(c[n - 1]);
while (n > 0 && c[n - 1] == csign)
n--;
if (n < 2)
{
if (csign == 0)
fmpz_set_ui(f, c[0]);
else if (c[0] != 0)
fmpz_neg_ui(f, -c[0]);
else
fmpz_neg_uiui(f, 1, 0);
}
else
{
mpz_ptr z = _fmpz_promote(f);
ulong * zd = FLINT_MPZ_REALLOC(z, n);
if (csign == 0)
{
flint_mpn_copyi(zd, c, n);
z->_mp_size = n;
}
else
{
if (mpn_neg(zd, c, n))
{
FLINT_ASSERT(zd[n - 1] != 0);
z->_mp_size = -n;
}
else
{
zd = FLINT_MPZ_REALLOC(z, n + 1);
zd[n] = 1;
z->_mp_size = -(n + 1);
}
}
}
}
void
fmpz_set_signed_uiuiui(fmpz_t r, ulong hi, ulong mid, ulong lo)
{
int negate = 0;
if ((slong) hi < 0)
{
hi = -hi - ((lo != 0) || (mid != 0));
mid = -mid - (lo != 0);
lo = -lo;
negate = 1;
}
if (hi == 0)
{
if (negate)
fmpz_neg_uiui(r, mid, lo);
else
fmpz_set_uiui(r, mid, lo);
}
else
{
mpz_ptr z = _fmpz_promote(r);
mp_ptr zp = FLINT_MPZ_REALLOC(z, 3);
zp[0] = lo;
zp[1] = mid;
zp[2] = hi;
z->_mp_size = negate ? -3 : 3;
}
}
void fmpz_set_ui_array(fmpz_t out, const ulong * in, slong in_len)
{
slong size = in_len;
FLINT_ASSERT(in_len > 0);
while (size > WORD(1) && in[size - 1] == UWORD(0))
size--;
if (size == WORD(1))
{
fmpz_set_ui(out, in[0]);
}
else
{
mpz_ptr mpz = _fmpz_promote(out);
mp_ptr mp = FLINT_MPZ_REALLOC(mpz, size);
mpz->_mp_size = size;
flint_mpn_copyi(mp, in, size);
}
}
void fmpz_set_mpn_large(fmpz_t z, nn_srcptr src, slong n, int negative)
{
mpz_ptr zz;
mp_ptr zp;
slong i;
zz = _fmpz_promote(z);
zp = FLINT_MPZ_REALLOC(zz, n);
for (i = 0; i < n; i++)
zp[i] = src[i];
zz->_mp_size = negative ? -n : n;
}