Método de Newton para hallar raíces
Este es un método iterativo inventado por Isaac Newton alrededor de 1664. Sin embargo, este método a veces también se llama método de Raphson, porque Raphson inventó el mismo algoritmo unos años después de Newton, pero su artículo se publicó mucho antes.
La tarea es la siguiente. Se da la siguiente ecuación:
Queremos resolver la ecuación. Más precisamente, queremos hallar una de sus raíces (se asume que la raíz existe). Se asume que es continua y diferenciable en un intervalo .
Algoritmo
Los parámetros de entrada del algoritmo consisten no solo en la función sino también en la aproximación inicial: algún , con el que empieza el algoritmo.
Supongamos que ya hemos calculado ; calculamos como sigue. Trazamos la tangente al gráfico de la función en el punto , y hallamos el punto de intersección de esta tangente con el eje . se pone igual a la coordenada del punto hallado, y repetimos todo el proceso desde el principio.
No es difícil obtener la siguiente fórmula,
Primero, calculamos la pendiente , derivada de , y luego determinamos la ecuación de la tangente, que es
La tangente se interseca con el eje x en la coordenada y ,
Ahora, resolviendo la ecuación obtenemos el valor de .
Intuitivamente está claro que si la función es “buena” (suave), y está lo bastante cerca de la raíz, entonces estará aún más cerca de la raíz deseada.
La velocidad de convergencia es cuadrática, lo que, hablando de forma condicional, significa que el número de dígitos exactos en el valor aproximado se duplica con cada iteración.
Aplicación para calcular la raíz cuadrada
Usemos el cálculo de la raíz cuadrada como ejemplo del método de Newton.
Si sustituimos , entonces después de simplificar la expresión, obtenemos:
La primera variante típica del problema es cuando se da un número racional , y hay que calcular su raíz con alguna precisión eps:
double sqrt_newton(double n) {
const double eps = 1E-15;
double x = 1;
for (;;) {
double nx = (x + n / x) / 2;
if (abs(x - nx) < eps)
break;
x = nx;
}
return x;
}Otra variante común del problema es cuando necesitamos calcular la raíz entera (para el dado hallar el mayor tal que ). Aquí es necesario cambiar un poco la condición de terminación del algoritmo, porque puede ocurrir que empiece a “saltar” cerca de la respuesta. Por lo tanto, añadimos una condición de que si el valor disminuyó en el paso anterior, e intenta aumentar en el paso actual, entonces el algoritmo debe detenerse.
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;
}Por último, se da la tercera variante: para el caso de aritmética de enteros grandes (bignum). Como el número puede ser lo bastante grande, tiene sentido prestar atención a la aproximación inicial. Obviamente, cuanto más cerca esté de la raíz, más rápido se alcanzará el resultado. Es suficientemente simple y efectivo tomar la aproximación inicial como el número , donde es el número de bits del número . Aquí está el código Java que demuestra esta variante:
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;
}Por ejemplo, este código se ejecuta en milisegundos para , y si quitamos la selección mejorada de la aproximación inicial (empezando simplemente con ), entonces se ejecutará en unos milisegundos.