首页 > 代码库 > 牛顿迭代法与一道经典编程问题

牛顿迭代法与一道经典编程问题


       牛顿迭代法(Newton’s method)又称为牛顿-拉夫逊(拉弗森)方法(Newton-Raphson method)。它是牛顿在17世纪提出的一种在实数域和复数域上近似求解方程的方法。


技术分享


       既然牛顿迭代法能够用来求解方程的根,那么最好还是以方程 x2=n<script id="MathJax-Element-197" type="math/tex">x^2=n</script> 为例,来试着求解它的根。

为此。

f(x)=x2?n<script id="MathJax-Element-198" type="math/tex"> f(x) = x^2 - n </script>, 也就是相当于求解 f(x)=0<script id="MathJax-Element-199" type="math/tex">f(x) = 0</script> 的解。如上图所看到的。


       首先随便找一个初始值 x0<script id="MathJax-Element-200" type="math/tex"> x_0</script>,假设 x0<script id="MathJax-Element-201" type="math/tex"> x_0</script>不是解,做一个经过 (x0,f(x0))<script id="MathJax-Element-202" type="math/tex">( x_0,f( x_0))</script> 这个点的切线,与x<script id="MathJax-Element-203" type="math/tex">x</script>轴的交点为x1<script id="MathJax-Element-204" type="math/tex">x_1</script>。相同的道理。假设 x1<script id="MathJax-Element-205" type="math/tex">x_1</script>不是解,做一个经过(x1,f(x1))<script id="MathJax-Element-206" type="math/tex">( x_1,f( x_1))</script>这个点的切线,与x<script id="MathJax-Element-207" type="math/tex">x</script>轴的交点为x2<script id="MathJax-Element-208" type="math/tex">x_2</script>。

以此类推。以这种方式得到的xi<script id="MathJax-Element-209" type="math/tex">x_i</script>会无限趋近于 f(x)=0<script id="MathJax-Element-210" type="math/tex">f(x) = 0</script> 的解。


推断xi<script id="MathJax-Element-211" type="math/tex">x_i</script>是否是f(x)=0<script id="MathJax-Element-212" type="math/tex">f(x) = 0</script>的解有两种方法: 一是直接计算f(xi)<script id="MathJax-Element-213" type="math/tex">f(x_i) </script>的值推断是否为0<script id="MathJax-Element-214" type="math/tex">0</script>,二是推断前后两个解xi<script id="MathJax-Element-215" type="math/tex">x_i</script>和xi?1<script id="MathJax-Element-216" type="math/tex">x_{i-1}</script>是否无限接近。


经过(xi,f(xi))<script id="MathJax-Element-217" type="math/tex">(x_i, f(x_i))</script>这个点的切线方程为

f(x)=f(xi)+f(xi)(x?xi)
<script id="MathJax-Element-218" type="math/tex; mode=display">f(x) = f(x_i) + f‘(x_i)(x - x_i)</script>当中。f(x)<script id="MathJax-Element-219" type="math/tex">f‘(x)</script>为f(x)<script id="MathJax-Element-220" type="math/tex">f(x)</script>的导数,本题中为2x<script id="MathJax-Element-221" type="math/tex">2x</script>。

令切线方程等于 0<script id="MathJax-Element-222" type="math/tex">0</script>。就可以求出

xi+1=xi?f(xi)f(xi)
<script id="MathJax-Element-223" type="math/tex; mode=display">x_{i+1}=x_i - \frac{f(x_i)}{f‘(x_i)}</script>


继续化简


xi+1=xi?x2i?n2xi=xi?xi2+n2xi=xi2+n2xi
<script id="MathJax-Element-224" type="math/tex; mode=display">x_{i+1}=x_i -\frac{x_i^2 - n}{2x_i} = x_i - \frac{x_i}{2} + \frac{n}{2x_i} = \frac{x_i}{2} + \frac{n}{2x_i}</script>


基于上述迭代公式,我们其实给出了一个求平方根的算法。其实,这也的确是非常多语言中内置的开平方函数的实现方法。




Leetcode上也有一道经典面试题目涉及到开平方函数的实现。例如以下

技术分享


基于我们已经给出的牛顿迭代法,以下就可来编程解决该问题了。演示样例代码例如以下

class Solution {
public:
    int mySqrt(int x) {
        if (x ==0)  
        return 0;  
        double pre;  
        double cur = 1;  
        do  
        {  
        pre = cur;  
        cur = x / (2 * pre) + pre / 2.0;  
        } while (abs(cur - pre) > 0.00001);  
        return int(cur);  
    }
};
<script type="text/javascript"> $(function () { $(‘pre.prettyprint code‘).each(function () { var lines = $(this).text().split(‘\n‘).length; var $numbering = $(‘
    ‘).addClass(‘pre-numbering‘).hide(); $(this).addClass(‘has-numbering‘).parent().append($numbering); for (i = 1; i <= lines; i++) { $numbering.append($(‘
  • ‘).text(i)); }; $numbering.fadeIn(1700); }); }); </script>

牛顿迭代法与一道经典编程问题