F#实现二分法求方程的根

举报
jackwangcumt 发表于 2021/07/28 11:09:37 2021/07/28
【摘要】 在不少工程问题中,我们需要求某一个方程f(x)的根,对于一元一次方程或者二次方程,我们可以利用公式非常方便的求出根。而对于高次方程或非线性方程,求根往往就没有现成的求根公式可以套用,而需要借助数值方法来进行求解。

      在不少工程问题中,我们需要求某一个方程f(x)的根,对于一元一次方程或者二次方程,我们可以利用公式非常方便的求出根。而对于高次方程或非线性方程,求根往往就没有现成的求根公式可以套用,而需要借助数值方法来进行求解。一般来说,对于一个连续的函数来说,如果存在两个点a和b,有f(a)和f(b)异号,那么理论上就存在一个根介于[a,b]之间,设为c,那么f(c)=0。举例来说,如果求x^3-1 这个函数,由于f(0) = -1 ,而f(2)=7,即f(0)*f(2) <0 ,那么说明在[0,2]之间必定存在一个根,根据图形,结合经验,可以判断出根为1。

1.jpg

    那么这个根如何通过计算机程序来实现呢?那么首先需要了解一下求根算法:

1 二分法(Bisection Method)

      在数据结构和算法中,有一种算法也叫二分法,他可以用于快速查找。类似的,二分法也可以用于方程求根上。在https://x-engineer.org/官网上,有一篇解说二分法的文章,感觉非常详细,其中的核心过程如下图所示:

2.jpg
      在二分法当中,每一次迭代,搜索区间的长度就会缩减一半,这是一个指数级的缩减。因此,即使给定的初始搜索区间比较大,但经过二分法多次迭代后也可以迅速缩减,得到一个非常精准的结果。它和泰勒级数一样,除了能得到一个足够精确的值之外,还能得到误差的范围。详细的过程可参考:
 https://x-engineer.org/undergraduate-engineering/advanced-mathematics/numerical-methods/the-bisection-method-for-root-finding

2 二分法实现

      根据上面的二分法算法过程,这里选择F#语言进行二分法求根程序实现。通过总结多种二分法算法描述,将二分法算法总结如下:
第一步:给出一个初始搜索区间[a,b]和精确度eps,如0.0001,使得f(a)*f(b)< 0 。
第二步:计算中间值 c=(a+b)/2 。
第三步:判断闭区间的长度b-a和精确度eps的关系,当闭区间长度>e的时候,返回第二步计算c。当闭区间长度<e的时候,停止迭代。输出结果c。
第四步:求出f(c)的值,如果f(a)*f(c)< 0 ,那么在[a,c]区间进行搜索;否则在[c,b]区间进行搜索。
     这个过程F#代码如下:

    let rec roots ( f , x1 , x2 , eps ) = 
        let  m = (x1 + x2) / 2.
        if (abs(x2 - x1 )< eps ) then
            m
        else 
            if ( f(x1) * f(m) < 0. ) then
                 roots(f,x1,m,eps)
            else
                roots(f,m,x2,eps)

3 求根验证

      为了验证二分法算法是否可以正确工作,下面给出函数进行验证:

    let testRoots = 
        let f x = x ** 2. - 4.
        let r = roots(f,-3.,3.,0.001) 
        printfn "%O" r //-1.9998779296875

        let f x = x ** 2. - 4.
        let r = round(roots(f,0.,3.,0.001))
        printfn "%O" r //2

        let f x = sin(x ** 2.) - 0.7
        let r = roots(f,-3.,3.,0.001) 
        printfn "%O" r //0.8807373046875

     从上述测试可知,x ^2 - 4 = 0  的根,如果在[-3,3]上虽然有2个根,但是程序只能求出一个根 -1.9998779296875 ,理论解析解为 - 2 。如果将搜索范围给定到[0,3],那么可以求出另外一个根,这里用round函数进行处理,四舍五入到 2 。最后一个sin(x^2) - 0.7 = 0 的根,在[-3,3]区域求出一个根0.8807373046875 。实际上,通过绘图可知,在这个区间会有多个根:

3.jpg
     因此,具体的根,需要结合图形来给定初始搜索空间,这往往决定着求出的是哪个根

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。