我们真正可以求出解析解的方程其实非常有限,大量的方程难以直接计算解析解,所以发展出了强大的数值解法,利用数值解法去高精度的逼近真实解,并且数值解法往往具有通用性,一种算法可以适用多种形式的方程。
牛顿迭代法就是一种广泛用于解方程的数值解法,是一种高效的迭代方法,具有局部无条件收敛、迭代次数少、精度可控的优点。
注:其中的是方程的函数形式,如:,而待求解的是,最终数值解就是或者
需要导入sympy包,创建一个方程类设置其基本性质。(setting文件完整代码)
import sympy as sp
class Equation:
def __init__(self, fx):
""" 初始化方程的性质 """
self.precision = 1e-6 # 初始化计算精度
self.precision_diff = 1e-3 # 初始化导数最小值,以判断是否接近0
self.x = sp.symbols('x')
self.fx = fx # 接收传入的方程的函数表达式
self.diff_fx = sp.diff(self.fx, self.x) # 生成方程的导数表达式
2.1计算的值
def get_value_fx(fx, x, precision_value):
""" 计算函数值 """
return fx.evalf(subs={'x': x}, n=precision_value) # n指定保留的有效数字
2.2计算的值
def get_value_fx_diff(diff_fx, x, precision_value):
""" 计算导数值 """
return diff_fx.evalf(subs={'x': x}, n=precision_value) # n指定保留的有效数字
2.3迭代一次,计算的值
def get_new_x(fx,
diff_fx,
x,
precision_value,
descent_factor
):
""" 迭代一次,计算新一个X的值,即X(k+1) """
value_fx = get_value_fx(fx, x, precision_value) # 获取函数值
value_fx_diff = get_value_fx_diff(diff_fx, x, precision_value) # 获取导数值
return x - descent_factor * (value_fx / value_fx_diff) # 带入牛顿迭代的表达式,并返回计算出的X(k+1)
2.4判断的值是否接近0
def fx_diff_close_to_0(value_fx_diff, precision_diff):
""" 判断导数值是否接近0 """
if abs(value_fx_diff) < precision_diff:
return True
else:
return False
2.5判断是否满足精度要求
def precision_requirement_meet(precision, list_x):
""" 判断X的精度是否满足要求 """
if len(list_x) == 1:
return False
difference = abs(list_x[-1] - list_x[-2])
if difference < precision:
return True
else:
return False
2.6 主循环进行迭代
def method_iterative_newton(fx,
diff_fx,
list_x,
precision,
precision_diff,
precision_value=5, # 结果有效数字默认保留5位
descent_factor=1 # 下山因子默认为1
):
""" 主循环进行计算 """
while not precision_requirement_meet(precision, list_x): # 当未满足精度时,进行一次迭代
value_fx_diff = get_value_fx_diff(diff_fx, list_x[-1], precision_value) # 为随后的判断,需单独计算一次导数值
if fx_diff_close_to_0(value_fx_diff, precision_diff): # 如果导数接近0.则终止计算
print('导数接近0,结束计算,最终结果可能不满足精度要求\n')
return
list_x.append(get_new_x(fx=fx,
diff_fx=diff_fx,
precision_value=precision_value,
x=list_x[-1],
descent_factor=descent_factor))
function文件完整代码
def get_value_fx(fx, x, precision_value):
""" 计算函数值 """
return fx.evalf(subs={'x': x}, n=precision_value) # n指定保留的有效数字
def get_value_fx_diff(diff_fx, x, precision_value):
""" 计算导数值 """
return diff_fx.evalf(subs={'x': x}, n=precision_value) # n指定保留的有效数字
def get_new_x(fx,
diff_fx,
x,
precision_value,
descent_factor
):
""" 迭代一次,计算新一个X的值,即X(k+1) """
value_fx = get_value_fx(fx, x, precision_value) # 获取函数值
value_fx_diff = get_value_fx_diff(diff_fx, x, precision_value) # 获取导数值
return x - descent_factor * (value_fx / value_fx_diff) # 带入牛顿迭代的表达式,并返回计算出的X(k+1)
def fx_diff_close_to_0(value_fx_diff, precision_diff):
""" 判断导数值是否接近0 """
if abs(value_fx_diff) < precision_diff:
return True
else:
return False
def precision_requirement_meet(precision, list_x):
""" 判断X的精度是否满足要求 """
if len(list_x) == 1:
return False
difference = abs(list_x[-1] - list_x[-2])
if difference < precision:
return True
else:
return False
def method_iterative_newton(fx,
diff_fx,
list_x,
precision,
precision_diff,
precision_value=5, # 结果有效数字默认保留5位
descent_factor=1 # 下山因子默认为1
):
""" 主循环进行计算 """
while not precision_requirement_meet(precision, list_x): # 当未满足精度时,进行一次迭代
value_fx_diff = get_value_fx_diff(diff_fx, list_x[-1], precision_value) # 为随后的判断,需单独计算一次导数值
if fx_diff_close_to_0(value_fx_diff, precision_diff): # 如果导数接近0.则终止计算
print('导数接近0,结束计算,最终结果可能不满足精度要求\n')
return
list_x.append(get_new_x(fx=fx,
diff_fx=diff_fx,
precision_value=precision_value,
x=list_x[-1],
descent_factor=descent_factor)) # 将结果追加到x列表中进行保存
import setting
import function
import sympy as sp
# 设置迭代初始值
init_x = 0
# 设置方程表达式
x = sp.symbols('x')
func = sp.cos(x) - x
# 获取方程对象
equation = setting.Equation(func)
# 创建x值的队列
list_x = [init_x]
# 调用牛顿迭代法
function.method_iterative_newton(fx=equation.fx,
diff_fx=equation.diff_fx,
list_x=list_x,
precision=equation.precision,
precision_diff=equation.precision_diff,
precision_value=10) # 计算结果的有效数字设为10位
print("方程:", func)
print("迭代结果:", list_x) # 简单打印计算结果
测试结果:
如有任何疑问,请在评论区留言,我会努力回复。
demo源码链接如下
github地址:https://github.com/method_iterative_newton