牛顿求根法
Newton's method for finding roots
我正在尝试实现牛顿法在 Python 中求根。
预期结果是 B 点,但 Python returns A 点:
代码:
import matplotlib.pyplot as plt
import numpy as np
def f(theta):
return 1 - (((2 * 1.5) * np.sin(theta))/ 2.7)
def derivative(f, x):
dx = 1E-8
return (f(x + dx) - f(x)) / dx
def x_next(f, x_n):
return 1 - (f(x_n) / derivative(f, x_n))
def newtons_method(f, x_n = 1, i = 0, max_iter = 100):
i = i + 1
if (i == max_iter):
return None
x_n = x_next(f, x_n)
if (abs(f(x_n)) < 1E-4):
return x_n
print("i:",i,"x_n:",x_n,"f(x_n)",f(x_n))
newtons_method(f, x_n, i, max_iter)
print(newtons_method(f))
你的主要问题是你的作息x_next
。你有一个 1
而应该有一个 x_n
。所以套路应该是
def x_next(f, x_n):
return x_n - (f(x_n) / derivative(f, x_n))
你的衍生套路也很差。如果您必须近似导数,Newton-Raphson 不是最好的方法。您使用的近似方法在数值上也不好,尽管它确实遵循导数的定义。如果必须使用近似值,请使用
def derivative(f, x):
dx = 1E-8
return (f(x + dx) - f(x - dx)) / (2.0 * dx)
但是在这种情况下,直接计算导数是非常容易的。所以最好用
def derivative(f, x):
return -2 * 1.5 * np.cos(x) / 2.7
您也不会打印根及其函数值的最终近似值——您计算它并且 return 不打印它。因此,在将 print
语句测试为 return.
之前放置它
通过这些更改(加上注释掉您从未使用过的 matplotlib
的导入),您的代码现在是
#import matplotlib.pyplot as plt
import numpy as np
def f(theta):
return 1 - (((2 * 1.5) * np.sin(theta))/ 2.7)
def derivative(f, x):
return -2 * 1.5 * np.cos(x) / 2.7
def x_next(f, x_n):
return x_n - (f(x_n) / derivative(f, x_n))
def newtons_method(f, x_n = 1, i = 0, max_iter = 100):
i = i + 1
if (i == max_iter):
return None
x_n = x_next(f, x_n)
print("i:",i,"x_n:",x_n,"f(x_n)",f(x_n))
if (abs(f(x_n)) < 1E-4):
return x_n
newtons_method(f, x_n, i, max_iter)
print(newtons_method(f))
结果只有两行
i: 1 x_n: 1.1083264212579311 f(x_n) 0.005607493777795347
i: 2 x_n: 1.1196379358595814 f(x_n) 6.373534192993802e-05
这就是你想要的。如果你坚持使用导数的数值近似,使用我上面给出的版本,结果略有不同:
i: 1 x_n: 1.10832642185337 f(x_n) 0.005607493482616466
i: 2 x_n: 1.1196379360265405 f(x_n) 6.373526104597182e-05
我正在尝试实现牛顿法在 Python 中求根。
预期结果是 B 点,但 Python returns A 点:
代码:
import matplotlib.pyplot as plt
import numpy as np
def f(theta):
return 1 - (((2 * 1.5) * np.sin(theta))/ 2.7)
def derivative(f, x):
dx = 1E-8
return (f(x + dx) - f(x)) / dx
def x_next(f, x_n):
return 1 - (f(x_n) / derivative(f, x_n))
def newtons_method(f, x_n = 1, i = 0, max_iter = 100):
i = i + 1
if (i == max_iter):
return None
x_n = x_next(f, x_n)
if (abs(f(x_n)) < 1E-4):
return x_n
print("i:",i,"x_n:",x_n,"f(x_n)",f(x_n))
newtons_method(f, x_n, i, max_iter)
print(newtons_method(f))
你的主要问题是你的作息x_next
。你有一个 1
而应该有一个 x_n
。所以套路应该是
def x_next(f, x_n):
return x_n - (f(x_n) / derivative(f, x_n))
你的衍生套路也很差。如果您必须近似导数,Newton-Raphson 不是最好的方法。您使用的近似方法在数值上也不好,尽管它确实遵循导数的定义。如果必须使用近似值,请使用
def derivative(f, x):
dx = 1E-8
return (f(x + dx) - f(x - dx)) / (2.0 * dx)
但是在这种情况下,直接计算导数是非常容易的。所以最好用
def derivative(f, x):
return -2 * 1.5 * np.cos(x) / 2.7
您也不会打印根及其函数值的最终近似值——您计算它并且 return 不打印它。因此,在将 print
语句测试为 return.
通过这些更改(加上注释掉您从未使用过的 matplotlib
的导入),您的代码现在是
#import matplotlib.pyplot as plt
import numpy as np
def f(theta):
return 1 - (((2 * 1.5) * np.sin(theta))/ 2.7)
def derivative(f, x):
return -2 * 1.5 * np.cos(x) / 2.7
def x_next(f, x_n):
return x_n - (f(x_n) / derivative(f, x_n))
def newtons_method(f, x_n = 1, i = 0, max_iter = 100):
i = i + 1
if (i == max_iter):
return None
x_n = x_next(f, x_n)
print("i:",i,"x_n:",x_n,"f(x_n)",f(x_n))
if (abs(f(x_n)) < 1E-4):
return x_n
newtons_method(f, x_n, i, max_iter)
print(newtons_method(f))
结果只有两行
i: 1 x_n: 1.1083264212579311 f(x_n) 0.005607493777795347
i: 2 x_n: 1.1196379358595814 f(x_n) 6.373534192993802e-05
这就是你想要的。如果你坚持使用导数的数值近似,使用我上面给出的版本,结果略有不同:
i: 1 x_n: 1.10832642185337 f(x_n) 0.005607493482616466
i: 2 x_n: 1.1196379360265405 f(x_n) 6.373526104597182e-05