#include "ulong_extras.h"
#include "padic_radix.h"
#include "gr.h"
slong
_padic_radix_log_bound(slong v, slong N, ulong p)
{
slong b, c;
c = N - (slong) n_flog((ulong) v, p);
c = FLINT_MAX(c, 1);
b = ((c + (slong) n_clog((ulong) c, p) + 1) + (v - 1)) / v;
while (--b >= 2)
{
slong t = b * v - (slong) n_clog((ulong) b, p);
if (t < N)
return b + 1;
}
return 2;
}
void
_padic_radix_log(radix_integer_t rop, const radix_integer_t y, slong N,
const radix_t radix)
{
slong cutoff;
ulong pbits = NMOD_BITS(radix->b);
if (pbits <= 5)
cutoff = 350;
else if (pbits <= 9)
cutoff = 280;
else if (pbits <= 21)
cutoff = 240;
else if (pbits <= 32)
cutoff = 160;
else if (pbits <= 46)
cutoff = 120;
else
cutoff = 80;
if (N < cutoff)
_padic_radix_log_rectangular(rop, y, N, radix);
else
_padic_radix_log_balanced(rop, y, N, radix);
}
static int
_padic_radix_log_wrapper(padic_radix_t res, const padic_radix_t x, int algorithm, gr_ctx_t ctx)
{
radix_struct * radix = PADIC_RADIX_CTX_RADIX(ctx);
ulong p = GR_PADIC_RADIX_CTX(ctx)->p;
slong thr = 1;
slong Nx = x->N;
slong prec_abs = PADIC_RADIX_CTX_PREC_ABS(ctx);
slong prec_rel = PADIC_RADIX_CTX_PREC_REL(ctx);
slong prec = FLINT_MIN(prec_rel, prec_abs);
radix_integer_t y, one;
slong vy;
if (radix_integer_is_zero(&x->u, radix))
{
if (Nx <= 0)
return GR_UNABLE;
return GR_DOMAIN;
}
if (x->v != 0)
return GR_DOMAIN;
if (radix_integer_is_one(&x->u, radix))
{
radix_integer_zero(&res->u, radix);
res->v = 0;
res->N = Nx;
return _padic_radix_finalize(res, ctx);
}
if (prec == PADIC_RADIX_PREC_INF)
{
if (Nx == PADIC_RADIX_EXACT)
return GR_UNABLE;
prec = Nx;
}
else if (Nx != PADIC_RADIX_EXACT)
{
prec = FLINT_MIN(prec, Nx);
}
if (prec > PADIC_RADIX_ERR_MAX)
prec = PADIC_RADIX_ERR_MAX;
if (prec <= 0)
{
radix_integer_zero(&res->u, radix);
res->v = 0;
res->N = prec;
return _padic_radix_finalize(res, ctx);
}
radix_integer_init(y, radix);
radix_integer_init(one, radix);
radix_integer_one(one, radix);
radix_integer_mod_digits(y, &x->u, prec, radix);
radix_integer_sub(y, one, y, radix);
radix_integer_mod_digits(y, y, prec, radix);
if (radix_integer_is_zero(y, radix))
{
radix_integer_zero(&res->u, radix);
res->v = 0;
res->N = prec;
radix_integer_clear(y, radix);
radix_integer_clear(one, radix);
return _padic_radix_finalize(res, ctx);
}
vy = radix_integer_valuation_digits(y, radix);
if (vy < thr)
{
radix_integer_clear(y, radix);
radix_integer_clear(one, radix);
return GR_DOMAIN;
}
if (vy >= prec)
{
radix_integer_zero(&res->u, radix);
res->v = 0;
res->N = prec;
radix_integer_clear(y, radix);
radix_integer_clear(one, radix);
return _padic_radix_finalize(res, ctx);
}
if (algorithm == 0)
_padic_radix_log(&res->u, y, prec, radix);
else if (algorithm == 1)
_padic_radix_log_rectangular(&res->u, y, prec, radix);
else
_padic_radix_log_balanced(&res->u, y, prec, radix);
radix_integer_clear(y, radix);
radix_integer_clear(one, radix);
res->v = 0;
res->N = prec;
return _padic_radix_finalize(res, ctx);
}
int
padic_radix_log(padic_radix_t res, const padic_radix_t x, gr_ctx_t ctx)
{
return _padic_radix_log_wrapper(res, x, 0, ctx);
}
int
padic_radix_log_balanced(padic_radix_t res, const padic_radix_t x, gr_ctx_t ctx)
{
return _padic_radix_log_wrapper(res, x, 2, ctx);
}
int
padic_radix_log_rectangular(padic_radix_t res, const padic_radix_t x, gr_ctx_t ctx)
{
return _padic_radix_log_wrapper(res, x, 1, ctx);
}