zoukankan      html  css  js  c++  java
  • 寻找“最好”(8)——牛顿法

      牛顿是近代科学的先驱,智商290,碾压无数学霸,一个苹果都能砸出万有引力定律。

      在力学上,牛顿阐明了动量和角动量守恒的原理,提出牛顿三大运动定律,它们和万有引力定律奠定了此后三个世纪里物理世界的科学观点,并成为无数中学生的噩梦。牛顿他通过论证开普勒行星运动定律与他的引力理论间的一致性,展示了地面物体与天体的运动都遵循着相同的自然定律;为太阳中心说提供了强有力的理论支持,并推动了科学革命。

      在天文学上,牛顿创制了反射望远镜。他还用万有引力原理说明潮汐的各种现象,指出潮汐的大小不但同月球的位相有关,而且同太阳的方位有关。牛顿预言地球不是正球体。

      在哲学上,牛顿的哲学思想基本属于自发的唯物主义,他承认时间、空间的客观存在。如同历史上一切伟大人物一样,牛顿虽然对人类作出了巨大的贡献,但他也不能不受时代的限制。例如,他把时间、空间看作是同运动着的物质相脱离的东西,提出了所谓绝对时间和绝对空间的概念;他对那些暂时无法解释的自然现象归结为上帝的安排,提出一切行星都是在某种外来的“第一推动力”作用下才开始运动的说法。

      在经济学上,牛顿提出金本位制度。这是一种以黄金为本位币的货币制度,当不同国家使用金本位时,国家之间的汇率由它们各自货币的含金量之比——金平价来决定。

      在数学上,我们已经见识过牛顿的微积分,他与莱布尼茨共同分享了微积分学的荣誉,尽管哥俩为谁的功劳大掐过架。

      此外,牛顿还提出了著名的牛顿法(Newton's method)也叫牛顿迭代法,它是牛顿在17世纪提出的一种在实数域和复数域上近似求解值的方法。

    牛顿法

      先来看如何用牛顿迭代法求解5的平方根。

      首先令f(x)= x2 – 5,这是标准步骤,取得一个新函数;再令该函数为0,这样原问题就可以看作是解方程x2 – 5 = 0。f(x)是一个抛物线:

      抛物线与x轴正方向的交点x就是方程的解,它比2稍大一点。

      现在在x = 2的点(2, -1)处对f(x)做切线,切线方程是y = kx + b,斜率k是f(x)在x = 2处的导数:

      将(2, -1)代入切线后得到截距b= -9:

     

      设f(x)与x轴正半轴的交点是x,切点是x0,切线与x轴的交点是x1,x1在x的右侧:

      由于x1贴近x,所以只要求得x1就能近似地求出x。求解x1的方法之一是找出过x0的切线,之后计算切线与x轴的交点。设切线的斜率是k,根据斜率的公式:

      过x0的切线的斜率正式f(x)在x0处导数的定义,因此:

      这样一来就找到了x的近似解x1。然而x1还没达到标准,我们还想更贴近真实值一点,这次选取更进接近x的(x1, f(x1))做切点,新切点的切线与x轴的交点x2将比原来的x1更贴近x:

      计算器上计算根号5的结果是2.236067,x2的值已经相当接近。

      重复上面步骤,每一次迭代的结果都将更接近真实值:

      这就是牛顿迭代法的公式。

    牛顿法的注意事项

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

      在使用牛顿迭代法时,需要选取x0作为迭代基数,x0如何选取呢?一句参考是:x0要在x附近,它是一个较为解接近真实解的值,这要凭经验和感觉了,没有什么太好的办法。

      实际上,如果x0和x的差距过大,可能会得到一个没谱的解。以计算5的平方根为例,如果选择x0= -2,结果将偏向于-2.236067;如果选择x0=0,则f’(0)=0,没法继续迭代:

      设第n次迭代的误差是En=|x-xn|,那么需要满足En+1<En。如果选择和计算都正确,误差缩小的速度将非常快。

    从泰勒公式看牛顿法

      泰勒展开式是一种计算近似值的方法,是一个用函数某点的信息描述在该点附近取值的公式,这就与牛顿法有些相似了。

      把f(x)在x0的某邻域内展开成泰勒级数:

      进一步得到:

      反复迭代就得到了牛顿法的公式:

    解方程2cosx = 3x

      先作图,画出y = 2cosx和y = 3x的曲线:

      两条曲线相交于一点,方程存在唯一解。根据牛顿法,先设置f(x):

      两条曲线交点的位置似乎是π/6附近,所以选择π/6作为x0,根据牛顿迭代法:

      第二次迭代与第一次迭代的差距已经非常微小,可以说x2就是最终的近似解。

    求平方根

      在一次code review会议上,一个同事展示了一段他不理解的C++代码:

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

      sqrt函数是求平方根,并且运行的很好,虽然展示者能够看懂每一行代码,但不知道为什么要这么写,不明白那个神奇的2.0是什么意思。

      现在看起来,不懂数学都没法快乐地阅读代码了。这段代码其实是在使用牛顿法计算平方根,过程是这样的:

      如果改成计算机程序的写法:

      现在可以和第9行代码对应上了。

      


       作者:我是8位的

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

      本文以学习、研究和分享为主,如需转载,请联系本人,标明作者和出处,非商业用途! 

      扫描二维码关注公众号“我是8位的”

  • 相关阅读:
    【C++ 系列笔记】03 C++ 面向对象进阶
    【C++ 系列笔记】02 C++ 面向对象基础
    【C++ 系列笔记】01 C++ 与 C
    【JavaScript】简单取随机数 ~~(Math.random() * number)
    英语测试
    Linux指令入门
    RE-攻防世界 T3 insanity
    PWN-攻防世界 level0
    ISCC不会的理论题
    kali linux配置ssh
  • 原文地址:https://www.cnblogs.com/bigmonkey/p/9922699.html
Copyright © 2011-2022 走看看