#include <math.h>
#include "double_extras.h"
#include "fmpzi.h"
void
fmpzi_divrem_approx(fmpzi_t q, fmpzi_t r, const fmpzi_t x, const fmpzi_t y)
{
slong xbits, ybits;
xbits = fmpzi_bits(x);
ybits = fmpzi_bits(y);
if (ybits == 0)
{
flint_throw(FLINT_DIVZERO, "fmpzi_divrem_approx: division by zero\n");
}
if (xbits == 0)
{
fmpzi_zero(q);
if (r != NULL)
fmpzi_zero(r);
return;
}
if (xbits < ybits - 2)
{
if (r != NULL)
fmpzi_set(r, x);
fmpzi_zero(q);
return;
}
if (xbits < ybits + 45)
{
double a, b, c, d, t, u, v, w, qa, qb;
slong aexp, bexp, cexp, dexp;
if (xbits < 500)
{
a = fmpz_get_d(fmpzi_realref(x));
b = fmpz_get_d(fmpzi_imagref(x));
c = fmpz_get_d(fmpzi_realref(y));
d = fmpz_get_d(fmpzi_imagref(y));
}
else
{
a = fmpz_get_d_2exp(&aexp, fmpzi_realref(x));
b = fmpz_get_d_2exp(&bexp, fmpzi_imagref(x));
c = fmpz_get_d_2exp(&cexp, fmpzi_realref(y));
d = fmpz_get_d_2exp(&dexp, fmpzi_imagref(y));
a = d_mul_2exp(a, FLINT_MAX(aexp - xbits, -1024));
b = d_mul_2exp(b, FLINT_MAX(bexp - xbits, -1024));
c = d_mul_2exp(c, FLINT_MAX(cexp - xbits, -1024));
d = d_mul_2exp(d, FLINT_MAX(dexp - xbits, -1024));
}
t = a * c + b * d;
u = b * c - a * d;
v = c * c + d * d;
w = 0.5 / v;
t = (2.0 * t + v) * w;
u = (2.0 * u + v) * w;
qa = floor(t);
qb = floor(u);
if (r != NULL)
{
fmpzi_t t, u;
fmpzi_init(t);
fmpzi_init(u);
fmpz_set_d(fmpzi_realref(u), qa);
fmpz_set_d(fmpzi_imagref(u), qb);
fmpzi_mul(t, u, y);
fmpzi_sub(r, x, t);
fmpzi_swap(q, u);
fmpzi_clear(t);
fmpzi_clear(u);
}
else
{
fmpz_set_d(fmpzi_realref(q), qa);
fmpz_set_d(fmpzi_imagref(q), qb);
}
return;
}
fmpzi_divrem(q, r, x, y);
}