/* Computes the n-th root of the double-double number a. NOTE: n must be a positive integer. NOTE: If n is even, then a must not be negative. */ dd_real nroot(const dd_real &a, int n) { /* Strategy: Use Newton iteration for the function f(x) = x^(-n) - a to find its root a^{-1/n}. The iteration is thus x' = x + x * (1 - a * x^n) / n which converges quadratically. We can then find a^{1/n} by taking the reciprocal. */ if (n <= 0) { dd_real::abort("(dd_real::nroot): N must be positive."); return dd_real::_nan; } if (n%2 == 0 && a.is_negative()) { dd_real::abort("(dd_real::nroot): Negative argument."); return dd_real::_nan; } if (n == 1) { return a; } if (n == 2) { return sqrt(a); } if (a.is_zero()) return 0.0; /* Note a^{-1/n} = exp(-log(a)/n) */ dd_real r = abs(a); dd_real x = std::exp(-std::log(r.hi) / n); /* Perform Newton's iteration. */ x += x * (1.0 - r * npwr(x, n)) / static_cast<double>(n); if (a.hi < 0.0) x = -x; return 1.0/x; }
/* Computes the square root of the double-double number dd. NOTE: dd must be a non-negative number. */ QD_API dd_real sqrt(const dd_real &a) { /* Strategy: Use Karp's trick: if x is an approximation to sqrt(a), then sqrt(a) = a*x + [a - (a*x)^2] * x / 2 (approx) The approximation is accurate to twice the accuracy of x. Also, the multiplication (a*x) and [-]*x can be done with only half the precision. */ if (a.is_zero()) return 0.0; if (a.is_negative()) { dd_real::abort("(dd_real::sqrt): Negative argument."); return dd_real::_nan; } double x = 1.0 / std::sqrt(a.hi); double ax = a.hi * x; return dd_real::add(ax, (a - dd_real::sqr(ax)).hi * (x * 0.5)); }