一、前言

    我们真正可以求出解析解的方程其实非常有限,大量的方程难以直接计算解析解,所以发展出了强大的数值解法,利用数值解法去高精度的逼近真实解,并且数值解法往往具有通用性,一种算法可以适用多种形式的方程。

    牛顿迭代法就是一种广泛用于解方程的数值解法,是一种高效的迭代方法,具有局部无条件收敛、迭代次数少、精度可控的优点。

\large x_{k+1} = x_{k}-\frac{f(x_{k} )}{​{f}' (x_{k} )}

注:其中的f(x)是方程的函数形式,如:f(x)=x^2-2x+1,而待求解的是f(x)=0,最终数值解就是x_{k}或者x_{k+1}

二、代码逻辑

  1. 新建setting文件,管理方程
  2. 新建function文件,管理函数
  3. 新建main文件,调用牛顿迭代法

1.setting文件

        需要导入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.具体函数

2.1计算\large f(x_{k})的值

def get_value_fx(fx, x, precision_value):
    """ 计算函数值 """
    return fx.evalf(subs={'x': x}, n=precision_value)  # n指定保留的有效数字

 2.2计算\large {f}' (x_{k} )的值

def get_value_fx_diff(diff_fx, x, precision_value):
    """ 计算导数值 """
    return diff_fx.evalf(subs={'x': x}, n=precision_value)  # n指定保留的有效数字

 2.3迭代一次,计算\large x_{k+1}的值

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判断\large {f}' (x_{k} )的值是否接近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判断\large x_{k+1} -x_{k}是否满足精度要求 

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列表中进行保存

三、main文件调用

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

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐