數學之美:牛頓-拉夫遜迭代法原理及其實現

關注、星標嵌入式客棧,精彩及時送達

[導讀] 前面剛轉了一篇文章提到了牛頓-拉夫遜(拉弗森)(Newton-Raphson method)方法,感覺這個數學方法很有必要相對深入寫一篇文章來總結分享印證一下自己的理解。這是寫本文的由來,如果發現文章中有錯誤之處,請留言交流討論。

什麼是牛頓-拉夫遜方法?

牛頓其人:Isaac Newton(1642年12月25日– 1727年3月20日)是一位英國數學家,物理學家,天文學家,神學家和作家,被公認爲有史以來最有影響力的科學家之一,並且是科學革命的關鍵人物。他的書《自然哲學的數學原理》於1687年首次出版,奠定了古典力學的基礎。牛頓還爲光學做出了開創性的貢獻,並與戈特弗裏德·威廉·萊布尼茲(Gottfried Wilhelm Leibniz)發展了無窮微積分的學科。


牛頓

拉弗森Joseph Raphson 生卒不詳,其最著名的著作是1690年出版的《通用分析方程》。它包含一種方法,現在稱其爲牛頓-拉夫森方法,用於近似方程式的求根。艾薩克·牛頓(Isaac Newton)在1671年寫的《通量法》中開發了一個非常相似的公式,但是這項工作要到1736年纔出版,這是拉夫森分析之後近50年。但是,該方法的Raphson版本比Newton方法更簡單,因此通常被認爲是更好的方法。

所以,牛頓迭代法(簡寫)就是一種近似求解實數域與複數域求解方程的數學方法。那麼這個方法是具體是什麼原理呢?

牛頓迭代如何迭代?

直接看數學公式描述如何迭代不直觀,先來看動圖就很容易理解牛頓迭代法爲什麼叫迭代法以及怎樣迭代的:

牛頓迭代法是原理是根據一個初始點 在該點做切線,切線與X軸相交得出下一個迭代點 的座標,再在 處做切線,依次類推,直到求得滿足精度的近似解爲止。


由前面描述知道,牛頓迭代法是用來近似求解方程的,這裏有兩個點需要說明:

  • 爲啥要近似求解?很多方程可能無法直接求取其解

  • 迭代法非常適合計算機編程實現,實際上計算機編程對於牛頓迭代法廣爲應用

來看看,數學上如何描述的?

其中 爲函數 處的一階導數,也就是該點的切線。

來簡單推一推上面公式的由來,直線函數方程爲:

知道一個直線的一個座標點 以及斜率 則該直線的方程就很容易可以得知:

那麼該直線與 軸的交點,就是 也即等式 的解:

啥時候停止迭代呢?

  1. 計算出

  2. 給出一個初始假定根值 ,利用上面迭代式子進行迭代

  3. 計算絕對相對迭代近似誤差

  4. 將絕對相對近似誤差與預定的相對誤差容限 進行比較。如果 ,則迭代步驟2,否則停止算法。另外,檢查迭代次數是否已超過允許的最大迭代次數。如果是這樣,則需要終止算法並退出。另一個終止條件是:

如何編碼呢?

由於牛頓迭代法主要目的是解方程,當然也有可能用於某一個數學函數求極值,所以無法寫出通用的代碼,這裏僅僅給出一個編代碼的思路。相信掌握了思路,對於各種實際應用應該能很快的寫出符合實際應用的代碼。

假定一函數爲

其波形圖如下:

其一階導數爲:

那麼對於該函數的根:

從圖上大致可以知道有兩個根,如果直接解方程,則很難求出其根,可以編個代碼試試:

#include <stdio.h>
#include <math.h>
#include <stdlib.h>

/*假定待求根函數如下*/
#define    F(x)    (2*(x)*(x)-10*cos(x)+(x)-80)

/*其一階導數爲*/
#define   DF(x)    (4*(x)+10*sin(x)+1)

float newton_rooting(float x0,float precision,float min_deltax,int max_iterations)
{
     float xn,xn1,fn,fn1,dfn;
     float deltax;
     int step = 0;
     xn  = x0;
     xn1 = x0;
     do{
       xn  = xn1;
       fn  = F(xn);
       dfn = DF(xn);
       /*判0*/
       if( fabs(dfn) <1e-6 )
       {
            if( fabs(fn)>precision )
                return NAN;
            else
                return fn;
       }

       xn1 = xn - fn/dfn;
       fn1 = F(xn1);
       deltax = fabs(xn1-xn);
       
       step++;
       if( step>max_iterations )
       {
           if( fabs(fn1)<precision )
               return xn;
           else
               return NAN;
       }
     }
     while( fabs(fn1)>precision || deltax>min_deltax );

     return xn1;
}

void main()
{
     float root_guess = 23.0f;
     float precision = 0.00001f;
     float min_deltax = 0.001f;
     float root;
     int step = 7;

     root = newton_rooting( root_guess,precision,min_deltax,step );
     printf("根爲: %f,函數值爲:%f\n", root,F(root));

     root_guess = -23;
     root = newton_rooting( root_guess,precision,min_deltax,step );
     printf("根爲: %f,函數值爲:%f\n", root,F(root));
}

結果:

根爲: 6.457232, 函數值爲:0.000004
根爲: -6.894969,函數值爲:-0.000008

函數值已經很接近於0了,如果還需要更爲精確的值,則可以選擇在此基礎上進一步求解,比如利用二分法逼近。

需要注意些啥?

  • 求斜率可能爲0,如爲0時,則可能找到了函數的極值,比如:

  • 如果選擇的初始猜測根的接近方程f(x)=0中函數f(x)的拐點 ,Newton-Raphson方法可能開始偏離根。然後,它可能會又收斂回到根。例如

5435866

  • 如果選擇的初值不合適,可能會跳掉一些根,比如:

所以實際應用時,需要知道自己待求解模型的大致情況,在合理的加以調整。

有哪些應用?

  • 比如知道某系統的傳遞函數,求解傳函的參數,可以將上述方法推而廣之,求解多維變量方程組,求導就變成求偏導了

  • 又比如設計一電路測量某物質的阻抗

  • ....

總結一下

牛頓迭代法在解決實際問題時,利用迭代求方程近似根的數學原理,在工程中有着很好的實用價值。比如求一個趨勢的極值,傳遞函數參數辨識等都有廣泛的實際應用。本文拋磚引玉,有可能文章也有很多錯誤疏漏的地方,如有不同看法或者發現錯誤,歡迎留言交流指正。

END

往期精彩推薦,點擊即可閱讀

▲Linux驅動相關專輯 

手把手教信號處理專輯

片機相關專輯

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章