Proving and computing a root with the interval Newton method
This tutorial solves an equation rigorously from scratch, using nothing but ball arithmetic and one theorem. The equation is
whose unique real solution is the omega constant , the value of the Lambert function at 1. We will (1) prove that contains exactly one solution, locating it in a subinterval; (2) refine it to 1000 digits with quadratic convergence; (3) check the result against the library function arb_lambertw. The same program works for any function whose value and derivative can be evaluated in ball arithmetic.
The interval Newton operator#
Let be continuously differentiable on an interval , let (usually the midpoint) and let be an interval containing for all . The interval Newton operator is
the set of all with , assuming .
Theorem 1 (Interval Newton). Suppose that .
- Every root of in lies in .
- If , then has no root in .
- If , then has exactly one root in .
Proof. (1) If and , the mean value theorem gives with between and , so since . (2) follows from (1). (3) Since is continuous and does not vanish on , is strictly monotonic on , so it has at most one root there. For existence, assume on (the other case is symmetric). The mean value theorem gives for some . Since , we have , that is , so . In the same way , and the intermediate value theorem gives a root.
The theorem goes back to Moore [Moo1966]; see [Neu1990], [Tuc2011] or [Rum2010] for its many variants, including the multivariate Krawczyk operator. In ball arithmetic, we cannot compute exactly, but we can compute a ball that contains it: evaluate at the exact point (as a ball, since is rounded), on the ball , and the quotient and difference. Then implies , and implies , so both conclusions of the theorem can be drawn from the computed enclosure. Moreover, by (1), replacing by never loses the root, and repeating this converges quadratically: the width of is about , since near the root.
Wide balls#
The operator needs a reasonably narrow starting interval. Ball arithmetic represents as a midpoint and a radius, and operations on wide balls overestimate. For , the program below computes as the product of and an enclosure of ; a product of balls has radius , which gives about instead of . Then is about , which is not contained in , and the test fails although the root is there. The cure is to bisect: on smaller intervals the overestimation is smaller, and the test succeeds. The function search below bisects until each part is either proved to contain no root or proved to contain exactly one.
The program#
#include <flint/arb.h>
/* f(x) = x exp(x) - 1 and f'(x) = (x + 1) exp(x) */
void f_eval(arb_t y, const arb_t x, slong prec)
{
arb_exp(y, x, prec);
arb_mul(y, y, x, prec);
arb_sub_ui(y, y, 1, prec);
}
void fprime_eval(arb_t y, const arb_t x, slong prec)
{
arb_t t;
arb_init(t);
arb_exp(t, x, prec);
arb_add_ui(y, x, 1, prec);
arb_mul(y, y, t, prec);
arb_clear(t);
}
/* N = m - f(m) / f'(X); returns 0 if f'(X) contains zero */
int newton_operator(arb_t N, const arb_t X, slong prec)
{
arb_t m, fm, fpX;
int ok;
arb_init(m); arb_init(fm); arb_init(fpX);
arb_get_mid_arb(m, X); /* exact midpoint */
f_eval(fm, m, prec);
fprime_eval(fpX, X, prec);
ok = !arb_contains_zero(fpX);
arb_div(N, fm, fpX, prec);
arb_sub(N, m, N, prec);
arb_clear(m); arb_clear(fm); arb_clear(fpX);
return ok;
}
/* search [a, b] for roots; returns 1 and sets X if one root is proved */
int search(arb_t X, double a, double b)
{
arb_t N;
int found = 0;
arb_init(N);
arb_set_d(X, (a + b) / 2);
mag_set_d(arb_radref(X), (b - a) / 2); /* X = [a, b] (or slightly wider) */
if (newton_operator(N, X, 53) && arb_contains(X, N))
{
flint_printf("[%.4f, %.4f]: exactly one root\n", a, b);
found = 1;
}
else if (!arb_overlaps(N, X))
{
flint_printf("[%.4f, %.4f]: no root\n", a, b);
}
else
{
flint_printf("[%.4f, %.4f]: undecided, bisect\n", a, b);
found = search(X, a, (a + b) / 2);
if (!found)
found = search(X, (a + b) / 2, b);
else
search(N, (a + b) / 2, b); /* report the rest, X is kept */
}
arb_clear(N);
return found;
}
int main(void)
{
arb_t X, N, W;
slong prec, target = 3330, step;
arb_init(X); arb_init(N); arb_init(W);
if (!search(X, 0.0, 2.0))
return 1;
/* iterate X = N(X) intersected with X, doubling the precision */
for (step = 1; ; step++)
{
/* twice the current accuracy, plus guard bits */
prec = FLINT_MAX(64, 2 * arb_rel_accuracy_bits(X) + 30);
prec = FLINT_MIN(prec, target + 30);
newton_operator(N, X, prec);
arb_intersection(X, X, N, prec);
flint_printf("step %wd: prec = %4wd, accuracy = %4wd bits\n",
step, prec, arb_rel_accuracy_bits(X));
if (arb_rel_accuracy_bits(X) >= target)
break;
}
arb_printn(X, 1000, ARB_STR_CONDENSE * 10);
flint_printf("\n");
arb_one(W);
arb_lambertw(W, W, 0, target + 30);
flint_printf("overlaps W(1): %d\n", arb_overlaps(X, W));
arb_clear(X); arb_clear(N); arb_clear(W);
flint_cleanup();
return 0;
}[0.0000, 2.0000]: undecided, bisect
[0.0000, 1.0000]: undecided, bisect
[0.0000, 0.5000]: no root
[0.5000, 1.0000]: undecided, bisect
[0.5000, 0.7500]: exactly one root
[0.7500, 1.0000]: no root
[1.0000, 2.0000]: undecided, bisect
[1.0000, 1.5000]: no root
[1.5000, 2.0000]: no root
step 1: prec = 64, accuracy = 5 bits
step 2: prec = 64, accuracy = 15 bits
step 3: prec = 64, accuracy = 39 bits
step 4: prec = 108, accuracy = 87 bits
step 5: prec = 204, accuracy = 184 bits
step 6: prec = 398, accuracy = 380 bits
step 7: prec = 790, accuracy = 772 bits
step 8: prec = 1574, accuracy = 1558 bits
step 9: prec = 3146, accuracy = 3129 bits
step 10: prec = 3360, accuracy = 3357 bits
[0.5671432904{...980 digits...}6227976096 +/- 4.92e-1001]
overlaps W(1): 1The output is a proof: has no root in , and , and exactly one in , and that root is enclosed in the final ball. (On even the exact operator does not decide: overlaps , so one more bisection is needed.)
Notes on the precision#
The accuracy roughly doubles in each step, as expected from quadratic convergence: bits. The working precision only needs to be somewhat larger than the accuracy that the step can produce, so the program sets it to twice the current accuracy plus 30 guard bits. With this schedule, the total cost is dominated by the last step or two: the cost of a step at precision is at least linear in , and the precisions form a geometric sequence. A naive program that runs every step at the full target precision would cost about times as much.
Three details keep the iteration correct and convergent:
- The midpoint is taken exactly (
arb_get_mid_arb), and is evaluated on this exact point, so its radius is only the rounding error. Evaluating on the whole ball instead would give a ball of width proportional to the width of , and no convergence. - The intersection with the previous guarantees that the enclosure never grows. In exact arithmetic once the method converges; with rounding, the intersection also removes overestimation.
- The stopping criterion uses the accuracy of the enclosure, not the size of the last correction. The result is therefore a proved enclosure regardless of when the iteration is stopped.
The library uses the same ideas internally: arb_fmpz_poly_refine_root_arb refines a real root of an integer polynomial with interval Newton steps (with ordinary Newton steps and bisection as fallbacks); arb_calc_refine_root_newton uses the closely related error bound of Refinement; and acb_mat_eig_simple certifies eigenvalues with a matrix version of the method due to Rump [Rum2010].
References#
- [Moo1966] R. E. Moore. Interval Analysis. Prentice-Hall, 1966.
- [Neu1990] A. Neumaier. Interval Methods for Systems of Equations. Cambridge University Press, 1990.
- [Tuc2011] W. Tucker. Validated Numerics: A Short Introduction to Rigorous Computations. Princeton University Press, 2011.
- [Rum2010] S. M. Rump, "Verification methods: Rigorous results using floating-point arithmetic", Acta Numerica 19 (2010), 287-449.
The FLINT team, “Proving and computing a root with the interval Newton method,” FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev, 2026. https://flintlib.org/doc/tutorials/numerics/interval-newton.html (generated 2026-11-02).
@misc{flint-doc-tutorials-numerics-interval-newton,
author = {{The FLINT team}},
title = {{Proving and computing a root with the interval Newton method}},
howpublished = {FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev},
year = {2026},
url = {https://flintlib.org/doc/tutorials/numerics/interval-newton.html},
note = {Generated 2026-11-02}
}