你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

牛顿-拉夫逊(拉弗森)(Newton-Raphson method)方法

[复制链接]
gaosmile 发布时间:2020-9-15 10:14

[导读] 前面刚转了一篇文章提到了牛顿-拉夫逊(拉弗森)(Newton-Raphson method)方法,感觉这个数学方法很有必要相对深入写一篇文章来总结分享印证一下自己的理解。这是写本文的由来,如果发现文章中有错误之处,请留言交流讨论。2 Q$ c: E9 L7 o9 n/ ~7 N

什么是牛顿-拉夫逊方法?

牛顿其人:Isaac Newton(1642年12月25日– 1727年3月20日)是一位英国数学家,物理学家,天文学家,神学家和作家,被公认为有史以来最有影响力的科学家之一,并且是科学革命的关键人物。他的书《自然哲学的数学原理》于1687年首次出版,奠定了古典力学的基础。牛顿还为光学做出了开创性的贡献,并与戈特弗里德·威廉·莱布尼兹(Gottfried Wilhelm Leibniz)发展了无穷微积分的学科。

2 _% |! s+ H6 J* o: ^1 W
微信图片_20200915100704.jpg 牛顿0 T8 q. `* a2 N, M

拉弗森Joseph Raphson 生卒不详,其最著名的著作是1690年出版的《通用分析方程》。它包含一种方法,现在称其为牛顿-拉夫森方法,用于近似方程式的求根。艾萨克·牛顿(Isaac Newton)在1671年写的《通量法》中开发了一个非常相似的公式,但是这项工作要到1736年才出版,这是拉夫森分析之后近50年。但是,该方法的Raphson版本比Newton方法更简单,因此通常被认为是更好的方法。

微信图片_20200915100708.jpg
: d$ F, `& x! l- k5 b& {4 `

所以,牛顿迭代法(简写)就是一种近似求解实数域与复数域求解方程的数学方法。那么这个方法是具体是什么原理呢?
& G$ S5 G7 q) R

牛顿迭代如何迭代?

直接看数学公式描述如何迭代不直观,先来看动图就很容易理解牛顿迭代法为什么叫迭代法以及怎样迭代的:

牛顿迭代法是原理是根据一个初始点在该点做切线,切线与X轴相交得出下一个迭代点的坐标,再在处做切线,依次类推,直到求得满足精度的近似解为止。

- n  \) o- w% G: W. Z

微信图片_20200915100711.gif

由前面描述知道,牛顿迭代法是用来近似求解方程的,这里有两个点需要说明:+ g. c" h, C/ z, Q9 t

  • 为啥要近似求解?很多方程可能无法直接求取其解
  • 迭代法非常适合计算机编程实现,实际上计算机编程对于牛顿迭代法广为应用; N: y+ P3 _+ J2 _

来看看,数学上如何描述的?

1600135792(1).png

其中为函数在处的一阶导数,也就是该点的切线。

来简单推一推上面公式的由来,直线函数方程为:

1600135824(1).png

知道一个直线的一个坐标点以及斜率则该直线的方程就很容易可以得知:

1600135844.png

那么该直线与轴的交点,就是也即等式的解:

1600135864(1).png

啥时候停止迭代呢?
  • 计算出
  • 给出一个初始假定根值,利用上面迭代式子进行迭代 1600135885(1).png
  • 计算绝对相对迭代近似误差 1600135936(1).png

  • 将绝对相对近似误差与预定的相对误差容限进行比较。如果\epsilon_s" data-formula-type="inline-equation" style="max-width: 100%; box-sizing: border-box !important;">,则迭代步骤2,否则停止算法。另外,检查迭代次数是否已超过允许的最大迭代次数。如果是这样,则需要终止算法并退出。另一个终止条件是: 1600135953(1).png 0 r) [  `8 V0 }; ]
1 l6 f; s+ S( a5 a0 T5 g8 w
2 P* Q) m& `6 M! h
如何编码呢?

由于牛顿迭代法主要目的是解方程,当然也有可能用于某一个数学函数求极值,所以无法写出通用的代码,这里仅仅给出一个编代码的思路。相信掌握了思路,对于各种实际应用应该能很快的写出符合实际应用的代码。

假定一函数为

1600135978(1).png

其波形图如下:

微信图片_20200915100715.png

其一阶导数为:

1600135996(1).png

那么对于该函数的根:

1600136018(1).png

从图上大致可以知道有两个根,如果直接解方程,则很难求出其根,可以编个代码试试:

#include <stdio.h>, ^; G: \8 u0 |) s( L7 P: Q* V% n9 W6 X7 H
#include <math.h>
, ]" O" }% @8 H- U. q3 o0 m7 z* o! K" ^#include <stdlib.h>
2 H$ f! [8 R: T& v+ g$ A6 m1 {3 m7 ?% L( }( h6 H, d
/*假定待求根函数如下*/% l5 Y, t/ x  s/ u' J) w
#define    F(x)    (2*(x)*(x)-10*cos(x)+(x)-80)# [2 F" a* o3 b5 I

# p# C7 @3 [$ D/*其一阶导数为*/
- x% E3 ]  K  t#define   DF(x)    (4*(x)+10*sin(x)+1)
/ ~) V- ?% `, h$ M: Q5 n" z# x0 |( B
float newton_rooting(float x0,float precision,float min_deltax,int max_iterations)
/ _/ f" D9 W  g, a: ^: m/ g{
8 [) k/ T1 o0 q3 f! g& i/ q7 C     float xn,xn1,fn,fn1,dfn;
$ r7 Z7 ?* D' D1 r4 T" Z+ P     float deltax;
! {) e/ A. d3 ^0 c     int step = 0;. |: D: m/ x- k
     xn  = x0;
+ n+ O# g$ Y( Z- w5 g5 a1 Y  k, x, a     xn1 = x0;
' Z/ L# H7 N+ C* ?* s7 z     do{# S+ a9 d' W( e: L+ t3 ~/ _+ _
       xn  = xn1;
( x* F' s, o. s8 a7 L       fn  = F(xn);
& i3 p3 ?4 g5 r2 {7 ^* ~& x: P       dfn = DF(xn);
: K* I8 h2 P  h, N2 a1 ~- g; P: U       /*判0*/' b# b, B; y: X( q% o
       if( fabs(dfn) <1e-6 )
. I' e" @! m6 c4 J( V       {
+ {& F; o: u! W1 `            if( fabs(fn)>precision )
) l( e$ }1 h& U& ?/ k- P" o                return NAN;7 p, {( B0 m9 P$ E' ]2 Q2 }0 C
            else
& H& r+ S" {9 m                return fn;; {" _9 w. a8 o
       }, h; I5 ^. V* H& W+ j7 h
7 F' k/ M0 G* F
       xn1 = xn - fn/dfn;. f! f/ f- z9 g0 c0 z
       fn1 = F(xn1);% t/ Y: I6 V& A, E) K1 E' O
       deltax = fabs(xn1-xn);9 a, u, B3 b3 U! s3 m3 a
       ' ^! S7 _) p, A: R$ [( Q) a
       step++;
3 d* l8 @1 D" F; h3 f& e       if( step>max_iterations )5 Q( X' O, {/ ?! o  r; ], P  X
       {
* y; N3 [0 g7 l# w, I. H6 Z           if( fabs(fn1)<precision )% f- m, v- ~) H* q+ a) U. H* w
               return xn;
9 g, G% A8 m( R4 ]           else( [0 ?& K# S# @/ w
               return NAN;: m3 P& o9 P3 q1 V' W
       }
# V4 }8 Q; s; {3 W! e( G     }3 [0 B7 w0 v, J" m
     while( fabs(fn1)>precision || deltax>min_deltax );
! A. N5 ?# s3 R# f& f% K! o; m2 |; d5 `( V
     return xn1;
# r/ f" |- `0 T" _# U}7 Y4 V9 y* |& g: k/ \

! f1 W. s7 Q1 _: \void main()
$ D) N# A2 @' Q% k7 ]{& C8 }! m( D0 K5 s3 T
     float root_guess = 23.0f;
1 l7 F2 L# |+ N; ~; [0 E* q     float precision = 0.00001f;# `) |% l$ M! B6 h5 g
     float min_deltax = 0.001f;
) r, E0 R( J/ `0 l( m7 L7 k     float root;
3 [  ?/ R, r8 X' t  j. w- N" G     int step = 7;9 U% }- |  X) _; r/ @

0 Q" l; F9 R1 ]0 R     root = newton_rooting( root_guess,precision,min_deltax,step );
* m. p0 _; l! r' h! e' f& \2 |     printf("根为: %f,函数值为:%f\n", root,F(root));
( ?2 q- s7 y6 B' J# u) W4 ?4 S6 Q* N! J# r! F* O! `
     root_guess = -23;6 J1 r' {0 t. C- H  O
     root = newton_rooting( root_guess,precision,min_deltax,step );
! Y3 z* U2 E, @2 H( M8 U* H- P     printf("根为: %f,函数值为:%f\n", root,F(root));/ i% M; ~: q: G
}9 `5 B, P$ s4 [6 A

结果:

根为: 6.457232, 函数值为:0.0000046 z7 E  J' ]: e" Y6 t( U
根为: -6.894969,函数值为:-0.000008; [. M1 T+ F# l% X% B4 U+ T

函数值已经很接近于0了,如果还需要更为精确的值,则可以选择在此基础上进一步求解,比如利用二分法逼近。

需要注意些啥?
  • 求斜率可能为0,如为0时,则可能找到了函数的极值,比如:


    & O" e6 q  S' y7 N1 W
微信图片_20200915100718.png
  • 如果选择的初始猜测根的接近方程f(x)=0中函数f(x)的拐点 ,Newton-Raphson方法可能开始偏离根。然后,它可能会又收敛回到根。例如:
    1 s% ~& U7 y& Y" f4 A8 b
微信图片_20200915100721.png 5435866
  • 如果选择的初值不合适,可能会跳掉一些根,比如:

    微信图片_20200915100725.png

    , k) _, I4 V1 [: H

所以实际应用时,需要知道自己待求解模型的大致情况,在合理的加以调整。

有哪些应用?
  • 比如知道某系统的传递函数,求解传函的参数,可以将上述方法推而广之,求解多维变量方程组,求导就变成求偏导了
  • 又比如设计一电路测量某物质的阻抗
  • ....' z0 X! d- R8 D) P7 k
总结一下

牛顿迭代法在解决实际问题时,利用迭代求方程近似根的数学原理,在工程中有着很好的实用价值。比如求一个趋势的极值,传递函数参数辨识等都有广泛的实际应用。本文抛砖引玉,有可能文章也有很多错误疏漏的地方,如有不同看法或者发现错误,欢迎留言交流指正。

; m, E8 d1 k# ~( F8 @4 [' c
4 [# T) R" }; ^1 ^0 ]* [$ {( I
赞 收藏 1 评论1 发布时间:2020-9-15 10:14

举报

1个回答
Kevin_G 回答时间:2020-9-15 11:40:00
大大的点赞,好厉害!
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版