C#(Winform)实现求解函数全部零点(二分法)

文章介绍了如何改进二分查找法以处理非单调函数的零点问题,通过增加分支处理确保所有可能的零点区间都被探索,同时引入精确度控制并给出了C#代码示例。
摘要由CSDN通过智能技术生成
  1. 算法概要

二分法,就是把函数零点所在区间分成两半,分半找零点,然后再分半,再找零点。不断分半,到分半的两个端点之差逐步逼近零点,满足近似值。

人教新课标必修一的数学课本上已经讲过如何求单调函数的零点了,现在我们的任务是改进算法,求类似二次函数等非单调函数的零点。

如上图所示,这是原版的算法。在验证f(a)f(c)是否小于0后,如果小于零,那么就有零点,如果大于零,这段区间就没有零点,讨论另一段区间。不过,根据零点存在性定理,这只适用于单调函数,如果我换成下图的二次函数,我在(-4,4)区间找零点,根据上面的算法,c=0,f(a)f(c)的确小于0,可是它直接b=c,相当于接下来就只讨论(-4,0)了,(0,4)上的零点就不管了。所以,我们要做到不管怎么样,另一段区间都需要接着讨论。

这样,我们只需要在上面的流程图加几个分支就行了。不过,要是直接根据上面的添加分支,讨论完取左边,再讨论右边,而此时b已经被销毁了(b=c),所以在此之前我们再把b存储到tb中(对a同理),以便在此反调用函数时提供参数。

第二个问题,有多个解,如何输出?这很简单,只需要每找到一个解,就添加到列表框就可以。所以,算法变成这样:

可是,如果这样,按照这个写出程序,其实会出现好多错解。仔细看看算法,你会发现只要a-b的绝对值小于精确度,那么就输出一个解。这对于原来的算法可以,零点左边a右边b,逐渐夹逼,直到小于精确度。可是现在不管怎样都要把二分后的两段都要接着二分讨论,这样a-b绝对值小于精确度在区间内都有可能。所以我们还需要验证解。很简单,在输出之前带入x测试一下,看看解和0的差值多大,小于精确度就输出。

这样,最终算法:

好,接下来我们还需要解决输入f(x)这个问题,我们可以根据需要设计界面,这里我们设计一个五次方程的计算

我们可以在代码中定义一个函数f(x),参数就是x,输出值就是,其中abcdef分别是六个文本框里的数据。

这样,问题完美解决,上代码

using System;
using System.Linq;
using System.Windows.Forms;

namespace 零点
{
    public partial class frmMain : Form
    {
        public frmMain()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            listBox1.Items.Clear();//清除上次的数据
            double j = Convert.ToDouble(textBox7.Text);//读取数据
            double a = Convert.ToDouble(textBox8.Text);
            double b = Convert.ToDouble(textBox9.Text);
            if (j != 0)
            {
                FindZeroPoint(j, a, b);
                if (listBox1.Items.Count == 0)
                {
                    listBox1.Items.Add("找不到零点");
                }
            }
            else
            {
                MessageBox.Show("精确度不能为0"); //不然程序会崩溃               
            }
        }
        private void FindZeroPoint(double j,double a,double b)
        {
            double c = (a + b) / 2;
            if (f(a) * f(c) < 0)
            {
                double tb = b;
                b = c;
                if(Math .Abs(a - b) < j)//判断精确度
                {
                    if (Math.Abs(f(a) - 0) < j)//判断是不是真的解
                    {
                        listBox1.Items.Add(a.ToString());
                    }
                }
                else
                {
                    FindZeroPoint(j, a, b);
                    FindZeroPoint(j, c, tb);//两边都要判断
                }
                
            }
            else
            {
                double ta = a;
                if (f(c) == 0)
                {
                    a = c;
                    listBox1.Items.Add(a.ToString());
                }
                else
                {
                    a = c;
                    if(Math .Abs(a - b) < j)
                    {
                        if (Math.Abs(f(a) - 0) < j)
                        {
                            listBox1.Items.Add(a.ToString());
                        }
                    }
                    else
                    {
                        FindZeroPoint(j, a, b);
                        FindZeroPoint(j, ta, c);
                    }
                }
                
            }
        }
        public double f(double x)//获取用户输入的函数
        {
              //由于C#中double变量不能直接乘方,因此这里只能不断使用乘号
              return Convert.ToDouble(textBox1.Text) * (x * x * x * x * x) + Convert.ToDouble(textBox2.Text) * x * x * x * x + Convert.ToDouble(textBox3.Text) * x * x * x + Convert.ToDouble(textBox4.Text) * x * x + Convert.ToDouble(textBox5.Text) * x+Convert .ToDouble (textBox6 .Text );
        }
    }
}

其实,本质上是根据精确度挨个假设,只不过是用二分法假设,可以提高效率

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值