以下内容来自Newton's method上的维基百科文章中的伪代码:
#! /usr/bin/env python3
# https://en.wikipedia.org/wiki/Newton's_method
import sys
x0 = 1
f = lambda x: x ** 2 - 2
fprime = lambda x: 2 * x
tolerance = 1e-10
epsilon = sys.float_info.epsilon
maxIterations = 20
for i in range(maxIterations):
denominator = fprime(x0)
if abs(denominator) < epsilon:
print('WARNING: Denominator is too small')
break
newtonX = x0 - f(x0) / denominator
if abs(newtonX - x0) < tolerance:
print('The root is', newtonX)
break
x0 = newtonX
else:
print('WARNING: Not able to find solution within the desired tolerance of', tolerance)
print('The last computed approximate root was', newtonX)
问题
在Python 3.x中有某种形式的fprime
,是否有自动计算某种形式的f
的方法?
答案 0 :(得分:2)
在f
处逼近x
的导数的常用方法是使用有限差分:
f'(x) = (f(x+h) - f(x))/h Forward difference
f'(x) = (f(x+h) - f(x-h))/2h Symmetric
h
的最佳选择取决于x
和f
:数学上差异接近导数,因为h趋于0,但该方法因灾难性取消而失去准确性如果h
太小。 x + h也应与x不同。像h = x*1e-15
这样的东西可能适合您的应用程序。另请参阅implementing the derivative in C/C++。
您可以使用secant method来避免逼近f'。它不像牛顿那样快速收敛,但它的计算成本更低,你可以避免必须计算导数的问题。
答案 1 :(得分:1)
您可以通过任意数量的方式近似fprime
。其中最简单的是:
lambda fprime x,dx=0.1: (f(x+dx) - f(x-dx))/(2*dx)
这里的想法是在点f
周围采样x
。采样区域(由dx
确定)应足够小,以使f
在该区域内的变化近似为线性。我使用的算法称为中点方法。通过对大多数函数使用高阶多项式拟合可以得到更准确的结果,但计算成本会更高。
当然,如果您了解分析衍生物,您将始终更加准确和有效。
答案 2 :(得分:0)
<强>答案强>
在formula
之后直接定义函数derivative
和import
。
def formula(*array):
calculate = lambda x: sum(c * x ** p for p, c in enumerate(array))
calculate.coefficients = array
return calculate
def derivative(function):
return (p * c for p, c in enumerate(function.coefficients[1:], 1))
使用f
重新定义formula
,方法是按照增加功率的顺序插入函数的系数。
f = formula(-2, 0, 1)
重新定义fprime
,以便使用derivative
和formula
功能自动创建。{/ p>
fprime = formula(*derivative(f))
这应该可以解决您在Python 3.x中从fprime
自动计算f
的要求。
<强>摘要强>
这是在自动计算fprime
时生成原始答案的最终解决方案。
#! /usr/bin/env python3
# https://en.wikipedia.org/wiki/Newton's_method
import sys
def formula(*array):
calculate = lambda x: sum(c * x ** p for p, c in enumerate(array))
calculate.coefficients = array
return calculate
def derivative(function):
return (p * c for p, c in enumerate(function.coefficients[1:], 1))
x0 = 1
f = formula(-2, 0, 1)
fprime = formula(*derivative(f))
tolerance = 1e-10
epsilon = sys.float_info.epsilon
maxIterations = 20
for i in range(maxIterations):
denominator = fprime(x0)
if abs(denominator) < epsilon:
print('WARNING: Denominator is too small')
break
newtonX = x0 - f(x0) / denominator
if abs(newtonX - x0) < tolerance:
print('The root is', newtonX)
break
x0 = newtonX
else:
print('WARNING: Not able to find solution within the desired tolerance of', tolerance)
print('The last computed approximate root was', newtonX)