给定f,是否有自动计算牛顿方法的fprime的方法?

时间:2013-05-20 13:30:21

标签: python math python-3.x solver newtons-method

以下内容来自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的方法?

3 个答案:

答案 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的最佳选择取决于xf:数学上差异接近导数,因为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之后直接定义函数derivativeimport

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,以便使用derivativeformula功能自动创建。{/ 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)