#include "arb.h"
static void
arb_root_arf(arb_t z, const arf_t x, ulong k, slong prec)
{
int inexact = arf_root(arb_midref(z), x, k, prec, ARB_RND);
if (inexact)
arf_mag_set_ulp(arb_radref(z), arb_midref(z), prec);
else
mag_zero(arb_radref(z));
}
static void
arb_root_ui_algebraic(arb_t res, const arb_t x, ulong k, slong prec)
{
mag_t r, msubr, m1k, t;
if (arb_is_exact(x))
{
arb_root_arf(res, arb_midref(x), k, prec);
return;
}
if (!arb_is_nonnegative(x))
{
arb_indeterminate(res);
return;
}
mag_init(r);
mag_init(msubr);
mag_init(m1k);
mag_init(t);
mag_set(r, arb_radref(x));
arb_get_mag_lower(msubr, x);
arb_root_arf(res, arb_midref(x), k, prec);
arb_get_mag(m1k, res);
mag_div(t, r, msubr);
mag_log1p(t, t);
mag_div_ui(t, t, k);
if (mag_cmp_2exp_si(t, 0) > 0)
mag_one(t);
mag_mul(t, m1k, t);
mag_add(arb_radref(res), arb_radref(res), t);
mag_clear(r);
mag_clear(msubr);
mag_clear(m1k);
mag_clear(t);
}
static void
arb_root_ui_exp(arb_t res, const arb_t x, ulong k, slong prec)
{
arb_log(res, x, prec + 4);
arb_div_ui(res, res, k, prec + 4);
arb_exp(res, res, prec);
}
void
arb_root_ui(arb_t res, const arb_t x, ulong k, slong prec)
{
if (k == 0)
{
arb_indeterminate(res);
}
else if (k == 1)
{
arb_set_round(res, x, prec);
}
else if (k == 2)
{
arb_sqrt(res, x, prec);
}
else if (k == 4)
{
arb_sqrt(res, x, prec + 2);
arb_sqrt(res, res, prec);
}
else
{
if (k > 50 || prec < (WORD(1) << ((k / 8) + 8)))
arb_root_ui_exp(res, x, k, prec);
else
arb_root_ui_algebraic(res, x, k, prec);
}
}
void
arb_root(arb_t res, const arb_t x, ulong k, slong prec)
{
arb_root_ui(res, x, k, prec);
}