1. 程式人生 > >數學筆記9——牛頓迭代法

數學筆記9——牛頓迭代法

  牛頓迭代法(Newton's method)又稱為牛頓-拉夫遜(拉弗森)方法(Newton-Raphson method),它是牛頓在17世紀提出的一種在實數域和複數域上近似求解方程的方法。

示例1:求解平方根

  先來看如何用牛頓迭代法求解5的平方根。在計算器上的結果是2.236067…

  問題可以看作解方程x2=5,下面嘗試用牛頓迭代法求解。

  首先令f(x)= x2 – 5 = 0,這是標準步驟,取得一個新函式,令該函式為0。這是一個拋物線:

  拋物線與x軸的交點x就是方程的解,它比2稍大一點。

  現在在x=2處對f(x)做切線:

f(x)的切線

切線與x軸的交點

  x0=2,y0= x02 – 5 = -1,設k是切線斜率:

  在x1處做f(x)的切線,重複上面步驟,

  這就是牛頓迭代法的公式。通過作圖可以看出,每一次迭代,x都將更靠近最終解。

  f’(x)=2x,將公式代入目標方程f(x)=x2-5:

  已經相當接近計算器的結果。

示例2:2cosx=3x

  解方程2cosx=3x

  由影象可知,方程存在唯一解。

  f(x)=2cosx-3x=0,f’(x)=-2sinx-3,x0=π/6≈0.52

注意事項

  牛頓迭代法幾乎可以求解所有方程,但它仍然有一些限制。

  通過前兩個例子可以看到,在使用牛頓迭代法時,需要選取一個較為解接近真實解的x0作為迭代基數,x0如何選取呢?一句參考是:“f’不能太小,f’’不能太大,x0要在x附近”,這似乎要憑經驗和感覺了,沒有什麼太好的辦法;實際上,如果x0和x的差距過大,可能會得到一個沒譜的解。

  設第n次迭代的誤差是En=|x-xn|,那麼需要滿足En+1<En。如果選擇和計算都正確,誤差縮小的速度將非常快。

  以計算5的平方根為例,如果選擇x0=-2,結果將偏向於-2.236067…;如果選擇x0=0,則f’(0)=0,沒法繼續迭代,函式曲線如下圖所示:

選擇了錯誤的x0

程式碼示例:牛頓迭代法開平方

  設x2=a,則f(x)= x2-a,根據牛頓迭代法公式:

 1 const float EPS = 0.00001; 
 2 double sqrt(double x) { 
 3     if(x == 0) 
 4         return 0; 
 5     double result = x; 
 6     double lastValue; 
 7     do{ 
 8         lastValue = result; 
 9         result = result / 2.0f + x / 2.0f / result; 
10     }while(abs(result - lastValue) > EPS);
11     return (double)result;
12  } 

  1999年12月,美國id Software公司釋出了名為“雷神之錘III”的電子遊戲。它是第一個支援軟體加速的遊戲,取得了極大成功。(由於影響力過大,文化部於2004年將它列入了非法遊戲名單)雷神之錘III並不是id Software公司的第一次成功。早在1993年開始,這家公司就以“毀滅戰士”系列遊戲名聞天下。1995年,“毀滅戰士”的安裝數超過了當年微軟的windows 95。據傳比爾蓋茨才曾經考慮買下id software。(id software公司後來被推出過“上古卷軸”系列的Bethesda公司買下)

  id Software所取得的成功很大程度上要歸功於它的創始人約翰·卡馬克。馬克爾也是一個著名的程式設計師,他是id Software遊戲引擎的主要負責人。 回到剛才提到的雷神之錘,馬克爾是開源軟體的積極推動者,他於2005年公佈了雷神之錘III的原始碼。至此人們得以通過研究這款遊戲引擎的原始檔來檢視它成功的祕密。

  在其中一個名字為q_math.c的檔案中發現瞭如下程式碼段:

 1 float Q_rsqrt( float number ) { 
 2     long i; float x2, y; const float threehalfs = 1.5F;
 3     x2 = number * 0.5F; 
 4     y = number; 
 5     i = * ( long * ) &y; // evil floating point bit level hacking 
 6     i = 0x5f3759df - ( i >> 1 ); // what the fuck? 
 7     y = * ( float * ) &i; 
 8     y = y * ( threehalfs - ( x2 * y * y ) ); // 1st iteration 
 9     // y = y * ( threehalfs - ( x2 * y * y ) ); // 2nd iteration, this can be removed
10     #ifndef Q3_VM #
11     ifdef __linux__ assert( !isnan(y) ); // bk010122 - FPE?
12     #endif
13     #endif return y; 
14 }

  這段程式碼的作用就是求number的平方根,並且返回它的倒數。

  經過測試,它的效率比上述牛頓法程式要快幾十倍。也比c++標準庫的sqrt()函式要快好幾倍。此段程式碼有一個奇怪的句子:

  i = 0x5f3759df - ( i >> 1 ); // what the fuck? 

  沒錯,一般的求平方根都是這麼迴圈迭代算的但是卡馬克(quake3作者)真正牛B的地方是他選擇了一個神祕的常數0x5f3759df 來計算那個猜測值,就是我們加註釋的那一行,那一行算出的值非常接近1/sqrt(n),這樣我們只需要2次牛頓迭代就可以達到我們所需要的精度。好吧如果這個還不算NB,接著看:

  普渡大學的數學家Chris Lomont看了以後覺得有趣,決定要研究一下卡馬克弄出來的這個猜測值有什麼奧祕。Lomont也是個牛人,在精心研究之後從理論上也推匯出一個最佳猜測值,和卡馬克的數字非常接近, 0x5f37642f。卡馬克真牛,他是外星人嗎?

  傳奇並沒有在這裡結束。Lomont計算出結果以後非常滿意,於是拿自己計算出的起始值和卡馬克的神祕數字做比賽,看看誰的數字能夠更快更精確的求得平方根。結果是卡馬克贏了... 誰也不知道卡馬克是怎麼找到這個數字的。

  最後Lomont怒了,採用暴力方法一個數字一個數字試過來,終於找到一個比卡馬克數字要好上那麼一丁點的數字,雖然實際上這兩個數字所產生的結果非常近似,這個暴力得出的數字是0x5f375a86。

  Lomont為此寫下一篇論文,"Fast Inverse Square Root"。

向牛頓致敬

  牛頓是近代科學的先驅,智商290,在多個領域都有非凡的成就。

  他在1687年發表的論文《自然定律》裡,對萬有引力和三大運動定律進行了描述。這些描述奠定了此後三個世紀裡物理世界的科學觀點,併成為了現代工程學的基礎。他通過論證開普勒行星運動定律與他的引力理論間的一致性,展示了地面物體與天體的運動都遵循著相同的自然定律;為太陽中心說提供了強有力的理論支援,並推動了科學革命。

  在力學上,牛頓闡明瞭動量和角動量守恆的原理,提出牛頓運動定律[1]  。在光學上,他發明了反射望遠鏡,並基於對三稜鏡將白光發散成可見光譜的觀察,發展出了顏色理論。他還系統地表述了冷卻定律,並研究了音速。

  在數學上,牛頓與戈特弗裡德·威廉·萊布尼茨分享了發展出微積分學的榮譽。他也證明了廣義二項式定理,提出了“牛頓法”以趨近函式的零點,併為冪級數的研究做出了貢獻。

  在經濟學上,牛頓提出金本位制度。

  在天文成上,牛頓1672年創制了反射望遠鏡。他還用萬有引力原理說明潮汐的各種現象,指出潮汐的大小不但同月球的位相有關,而且同太陽的方位有關。牛頓預言地球不是正球體。

  在哲學成上,牛頓的哲學思想基本屬於自發的唯物主義,他承認時間、空間的客觀存在。如同歷史上一切偉大人物一樣,牛頓雖然對人類作出了巨大的貢獻,但他也不能不受時代的限制。例如,他把時間、空間看作是同運動著的物質相脫離的東西,提出了所謂絕對時間和絕對空間的概念;他對那些暫時無法解釋的自然現象歸結為上帝的安排,提出一切行星都是在某種外來的“第一推動力”作用下才開始運動的說法。《自然哲學的數學原理》牛頓最重要的著作,1687年出版。

  向偉大的牛頓致敬!

總結

  1. 牛頓迭代法的公式:
  2. 注意事項,f’不能太小,f’’不能太大,x0要在x附近

    作者:我是8位的

  出處:http://www.cnblogs.com/bigmonkey

  本文以學習、研究和分享為主,如需轉載,請聯絡本人,標明作者和出處,非商業用途!