Newton's Method

Introduction

This article introduces Newton's method for finding approximate solutions of equations. The method was proposed by Newton in the 17th century.

More specifically, given a continuous and monotonic function f(x)f(x) on [a,b][a,b], we seek an approximate solution to f(x)=0f(x)=0.

Explanation

Initially, we start with the given f(x)f(x) and an approximate solution x0x_0 (the choice of the initial value is related to Newton fractals; see 3Blue1Brown's Newton fractal).

Suppose that our current approximate solution is xix_i. Draw the line ll tangent to f(x)f(x) at (xi,f(xi))(x_i,f(x_i)), and let the abscissa of the intersection between ll and the xx-axis be xi+1x_{i+1}. This is a better approximate solution. Repeat this iteration. From the geometric meaning of the derivative, we obtain:

f′(xi)=f(xi)xi−xi+1 f'(x_i) = \frac{f(x_i)}{x_{i} - x_{i+1}}

Rearranging gives the following recurrence:

xi+1=xi−f(xi)f′(xi) x_{i+1} = x_i - \frac{f(x_i)}{f'(x_i)}

Intuitively, if f(x)f(x) is sufficiently smooth, then as the number of iterations increases, xix_i gets closer and closer to the solution of the equation.

Newton's method has quadratic convergence, which means that the number of correct digits in the approximate solution doubles after each iteration. For a proof of convergence, see citizendium - Newton method Convergence analysis.

Of course, Newton's method also has drawbacks; see the analysis in Xiaolin Wu - Roots of Equations, pages 18–20.

Computing Square Roots

We try to use Newton's method to compute a square root. Let f(x)=x2−nf(x)=x^2-n; an approximate solution of this equation is an approximate value of n\sqrt{n}. Therefore,

xi+1=xi−xi2−n2xi=xi+nxi2x_{i+1}=x_i-\frac{x_i^2-n}{2x_i}=\frac{x_i+\frac{n}{x_i}}{2}

In an implementation, choose an appropriate precision. The code is as follows.

Implementation

C++

double sqrt_newton(double n) {
  constexpr static double eps = 1E-15;
  double x = 1;
  while (true) {
    double nx = (x + n / x) / 2;
    if (abs(x - nx) < eps) break;
    x = nx;
  }
  return x;
}

Python

def sqrt_newton(n):
    eps = 1e-15
    x = 1
    while True:
        nx = (x + n / x) / 2
        if abs(x - nx) < eps:
            break
        x = nx
    return x

Computing the Integer Square Root

Although we can call the sqrt() function to obtain a square root, we will also discuss a variant of Newton's method for finding the largest integer solution to the inequality x2≤nx^2\le n. We still consider a process similar to Newton iteration, but make a small change to the boundary condition. If xx's approximate solution decreased in the previous iteration but increases in the current iteration, we do not perform the current iteration and exit the loop.

Implementation

C++

int isqrt_newton(int n) {
  int x = 1;
  bool decreased = false;
  for (;;) {
    int nx = (x + n / x) >> 1;
    if (x == nx || (nx > x && decreased)) break;
    decreased = nx < x;
    x = nx;
  }
  return x;
}

Python

def isqrt_newton(n):
    x = 1
    decreased = False
    while True:
        nx = (x + n // x) // 2
        if x == nx or (nx > x and decreased):
            break
        decreased = nx < x
        x = nx
    return x

High-Precision Square Roots

Finally, consider Newton iteration with high-precision numbers. The iteration itself is unchanged, but this time we need to pay attention to the initial approximate solution, namely the value of x0x_0. Since the numbers for which high precision is needed are usually very large, different initial values can have a significant effect on the algorithm's efficiency. A natural idea is to choose x0=2⌊12log⁡2n⌋x_0=2^{\left\lfloor\frac{1}{2}\log_2n\right\rfloor}, which makes x0x_0 quick to compute and gives a reasonably close approximation to the square root.

Implementation

Here is an implementation in Java:

public static BigInteger isqrtNewton(BigInteger n) {
  BigInteger a = BigInteger.ONE.shiftLeft(n.bitLength() / 2);
  boolean p_dec = false;
  for (;;) {
    BigInteger b = n.divide(a).add(a).shiftRight(1);
    if (a.compareTo(b) == 0 || a.compareTo(b) < 0 && p_dec)
      break;
    p_dec = a.compareTo(b) > 0;
    a = b;
  }
  return a;
}

In practice, when n=101000n=10^{1000}, this algorithm takes 60 ms to run. If we do not optimize the value of x0x_0 and start the iteration directly from x0=1x_0=1, the running time increases to 120 ms.

Exercises

This content comes from OI Wiki: Newton's Method. See the original for authors and revision history. AIOJ has adapted the formatting, in-site links, and resource paths.

Content is shared under CC BY-SA 4.0 and SATA license; additional terms are governed by the original notice. Thanks to the OI Wiki authors and contributors; per the SATA terms, please visit the OI Wiki repository and star it to show your support.