#include "test_helpers.h"
#include <float.h>
#include <mpfr.h>
#include "ulong_extras.h"
#include "double_extras.h"
#define ONE_OVER_E ldexp(6627126856707895.0, -54)
TEST_FUNCTION_START(d_lambertw, state)
{
double x, w, tol;
slong iter, prec = 70;
mpfr_t xx, ww, wnew, t, u, v, p, q, max_err;
mpfr_init2(xx, prec);
mpfr_init2(ww, prec);
mpfr_init2(wnew, prec);
mpfr_init2(t, prec);
mpfr_init2(u, prec);
mpfr_init2(v, prec);
mpfr_init2(p, prec);
mpfr_init2(q, prec);
mpfr_init2(max_err, prec);
mpfr_set_ui(max_err, 0, MPFR_RNDN);
for (iter = 0; iter < 10000 * flint_test_multiplier(); iter++)
{
x = d_randtest(state);
switch (n_randint(state, 3))
{
case 0:
x = ldexp(x, -n_randint(state, -DBL_MIN_EXP+1));
x = -ONE_OVER_E + x;
tol = 50 * DBL_EPSILON;
break;
case 1:
x = d_randtest(state);
x = ldexp(x, -n_randint(state, -DBL_MIN_EXP+1));
x = x * -(1./4);
tol = 2 * DBL_EPSILON;
break;
default:
x = d_randtest(state);
x = ldexp(x, (int) n_randint(state, DBL_MAX_EXP-DBL_MIN_EXP-1)
+ DBL_MIN_EXP);
tol = 2 * DBL_EPSILON;
break;
}
w = d_lambertw(x);
mpfr_set_d(xx, x, MPFR_RNDN);
mpfr_set_d(ww, w, MPFR_RNDN);
mpfr_exp(t, ww, MPFR_RNDN);
mpfr_mul_ui(u, ww, 2, MPFR_RNDN);
mpfr_add_ui(u, u, 2, MPFR_RNDN);
mpfr_mul(v, t, ww, MPFR_RNDN);
mpfr_sub(v, v, xx, MPFR_RNDN);
mpfr_mul(p, u, v, MPFR_RNDN);
mpfr_mul(q, u, t, MPFR_RNDN);
mpfr_add_ui(t, ww, 1, MPFR_RNDN);
mpfr_mul(q, q, t, MPFR_RNDN);
mpfr_add_ui(t, ww, 2, MPFR_RNDN);
mpfr_mul(t, t, v, MPFR_RNDN);
mpfr_sub(q, q, t, MPFR_RNDN);
mpfr_div(p, p, q, MPFR_RNDN);
mpfr_sub(wnew, ww, p, MPFR_RNDN);
mpfr_sub(t, ww, wnew, MPFR_RNDA);
mpfr_div(t, t, wnew, MPFR_RNDA);
mpfr_abs(t, t, MPFR_RNDA);
if (mpfr_get_d(t, MPFR_RNDA) > tol)
TEST_FUNCTION_FAIL("x = %.17g, w = %.17g, error = %g\n", x, w, mpfr_get_d(t, MPFR_RNDA));
#if 0#endif
}
mpfr_clear(xx);
mpfr_clear(ww);
mpfr_clear(wnew);
mpfr_clear(t);
mpfr_clear(u);
mpfr_clear(v);
mpfr_clear(p);
mpfr_clear(q);
mpfr_clear(max_err);
mpfr_free_cache();
TEST_FUNCTION_END(state);
}