7解一元高次方程的任务树

 

 

 

                      《树型软件工程方法》之系列博文7

 

解一元高次方程的任务树

 


 

 

 

 

 

TREESOFT


 

中国人为什么不可以有自己的软件工程方法及其开发工具平台!

这是介绍《树型软件工程方法》的系列博文,请按文章标题所带的编号顺序阅读,否则你会看不懂本文。

 


7 解一元高次方程的任务树

   笔者连续发表了6篇关于作业树的博文,讨论函数级程序模块的结构化设计,实际意图是为了推介一种全新的软件工程方法,称之为“树型软件工程方法”。由于涉及方法论,文章比较多,组织和发表的时间会比较长。在这里,我要特别感谢oschina的站长红薯先生,他给我很大的帮助与支持,鼓励我说:“等你都写完了,我们发一篇新闻,将所有文章汇总一起给大家推荐一下”。我所说的树型软件共分三级:系统的结构树事件树,事件的结构务树,任务的结构树作业树。有关作业树的基本内容已介绍完成,本文开始将会陆续发文介绍任务树的有关内容。在这里我还要感谢网友们的支持与鼓励,你们给我的每一份留言,对我来说都是“字字值千斤”。此外,我所发表的博文都允许转载传播,若有为者“功德无量,善莫大焉”。

   既然是介绍“树型软件工程方法”的序列文章,后面的文章一定是前面的文章相关的,没有读过前面的文章,后面的文章就一定读不许多网友提的问题都是因为这个原因而引起的。在此我再一次将之前的6篇文章的阅读顺序排列如下:

   1) 冒泡排序程序的结构化设计(内有作业树基本概念的定义)

   2) 解一元二次方程程序的结构化设计(作业树应用实例)

   3) 常用二分查找的作业树(作业树应用实例)

   4) 2分化查找的作业节(作业树应用实例,可以不看)

   5) 作业树设计原理(比较费脑子,但很有趣,一定要看懂)

   6) 作业树通用性证明(也比较费脑子,也很有趣,看懂后会感觉豁然开朗)

   在阅读本博文之前,一定请按序先阅读上述文章。只要按序阅读,弄懂每一篇文章都不难。

   现在言归正传,来讨论求解一元高次方程的任务树。 

7.1 问题需求

   用弦截法一元高级方程f(x)=x3-5x2+16x-80=0的根。

   弦截法解一元高次方程是我们所熟知的,现在要编写计算机程序来求解一个具体的一元高次方程。这个问题是从谭浩强先生的《C程序设计》中摘抄来的,认为比较适合于用来引出任务树的概念。 

7.2 算法设计

   如图7.1所示,曲线f(x)X轴的交点为一元高次方程的根,求解方法如下。

   1)取两个不同点x1x2,如果f(x1)f(x2)符号相反,则区间(x1x2)内必有一个根。如果f(x1)f(x2)同符号,则应改变x1x2,直到f(x1)f(x2)异号为止。

   2)连接(x1f (x1) )(x2f (x2) )两点的弦截线必交X轴于x点。x点的坐标可用下式来出。

   x=(x1*f(x2)-x2*f(x1))/(f(x2)-f(x1))

   如果│f (x)│<ε(设定的精度误差,如10-3 )x就是一元高次方程f(x)=0的根,则过程结束。否则执行步骤3

7.1 弦截法求一元高次方程的根

   3)如果f(x)f(x1)同符号,则根必在(x,x2)区间内,以x取代x1转步骤2。否则f(x)f(x2)必定同符号,则根在(x1, x )区间内,以x取代x2转步骤2 

7.3作业树

   由上面的算法可知,弦截法解一元高次方程涉及四个Oq(原问题):选取初始弦截点;求弦截线与X轴的交点;求曲线上任意点的yf(x);求原方程的解。按照结构化设计的要求,应该将这四个Oq分别形成函数或子程序,然后依算法逻辑形成调用关系。我们知道,每个Oq的求解都对应着一棵作业树,于是就有下面的四棵作业树。 

7.3.1 选取初始弦端点

7.2 选取初始弦端点的作业树

   选取初始弦端点的方法只有试探法。我们可以根据曲线y=f(x)在坐标图上的情况(如图7.1),大至看出曲线与X轴的交点,然后给出x1x2的初值。如果满足f(x1)*f(x2)<0,则本Oq求解结束。图7.2便是求解本Oq的作业树,对应于C函数init()7.2中的控制节点C1的控制类型为“!d”,表示采用C语言中的“dowhile”循环控

制,遍历编程该作业树后得到如下伪代码。

// In:选初始点//

init()

{//C1//

do

   {

        input x1,x2;

       f1=f(x1);

       f2=f(x2);

   }

while (f1*f2>=0);

return;

}

 7.3.2 求弦截线与X轴的交点

   求弦截线与X轴的交点问题也没有什么特殊算法,将曲线上两点的坐标(x1f(x1))(x2f(x2))代入公式即可。相应的作业树示于图7.3,函数xpoint()的功能即是计算弦截线与X轴的交点(x0)。这棵作业树的特点是没有控制节点(除初始节点外),是最简单的作业树,只有一级Tq,也就是Oq自身。

7.3 本弦截点的作业树

7.3.3 求曲线上任意点的f(x)

 

7.4 求曲线上任意点f(x)的作业树

   求曲线上任意点f(x)问题的算法也很简单,将x值代入高次方程即可,求解作业树示于图7.4,也是一棵单级Tq的作业树。函数f(x)的功能是按f(x)的表达式计算y=f(x) 

7.3.4 求一元高次方程的根

   有了上面3Oq的求解子程序后,就可设计求解一元高次方程根的作业树了。显然,我们是将本Oq的求解程序作为main函数,按逻辑需要调用其它子程序,相应的作业树示于图7.5

7.5 求一元高次方程根的作业树

   该作业树中控制节点C1的控制类型标志为“!d*”,其中“*”为控制结标志,“!d”为“dowhile”循环的类型标志。遍历编程该作业树后可生成如下伪代码。

// Rt:解高次方程//

float x,x1,x2,y,y1;

main()

{// C1:迭代求方程根//

   init();

      y1=f(x1);

   do

     {// C2:新的x1x2//

       x=xpoint();

              y=f(x);

              if (y*y1>0)

         {//根在(xx2)区间//

                    y1=y;

                    x1=x;

                   }

             else

                  {//根在(x1x)区间//

                     x2=x;

                   }

            }

         while (fabs(y)>=e);

         print(x);

         stop;

  }

 

7.4 任务树

   我们看到,弦截法解一元高次方程的程序并不象此前叙述过的“冒泡排序”、“二分查找”等问题那样,只需一棵作业树就可以园满地表示其求解算法。弦截法解一元高次方程的程序由四棵作业树组成,每棵作业树对应于一个C函数。这就是结构化设计所要求的。实际上也可以将这四棵作业树并成一棵,但这样的作业树是非规范的,有关这方面的讨论将在后续的博文中叙述。

 

7.4.1 任务

   现在,我们来定义范畴比作业大一级的规范模块任务。

   作业树所表示的程序段称为任务。

   上述断语是从程序作用范畴的角度来定义任务的。换句话说,任务是作业树所表示的程序段,作业树则是任务的结构树。也可以说这是从数学的角度来定义任务的,因为树是一种数学模型。另一方面,我们曾经指明,作业树是算法的树型图表示。什么叫算法?求解问题的计算方法就叫算法。由此可见,任务又可称为问题,任务是现实世界中的问题。通常,人们将一个独立的概念称为问题,所以又可以说:

   任务是可用算法描述的独立概念。

   显然,这个定义不如前面的严密。什么叫独立概念,不好说也说不清楚。尽管如此,这个定义还是很有用的,人们日常生活中都是用这个定义来确定任务的,程序设计时也经常依据这个定义来划分出任务模块。将任务的这两个定义结合起来使用,就可以发现任务。如何将独立概念形成任务,严格任务的作用范畴,将是我们在下一篇博文中要着力解决的问题。

 

7.4.2 任务树

   由图7.5可以看出,解一元高次方程的四个任务之间是以函数调用的方式相互关联的,这种调用关系也形成一棵树,称为任务树。

7.6 求解一元高次方程的任务树

   在任务树中,如果任务A是任务B的父亲,说明A调用了B一次或多次。如果任务C既被任务A调用又被任务B调,则将C分别作为AB的儿子。

   按照上面的规定,解一元高次方程的任务树就如图7.6所示。这里,以扁长的六边形表示任务节点。六边形被分为上下两部分:上部为注释部,一般存放任务简称;下部为标识部,存放任务的ID。与作业树类似,遍历编程任务树时,任务节点注释部的内容将被编写成注释行。任务的ID将参与组成相应作业树参数文件《作业表》的文件名。作业树中的每一个作业对应于《作业表》中的一条记录,存放相应作业的所有属性;作业节点编号,控制类型,控制逻辑表达式,注释内容,顺序部内容,父亲节点编号,…,等等。对于任务树,也有称之为《任务表》的文件,记录每个任务节点的相关属性。

   在图7.6的任务树中,任务Rt是任务树的根节点,又称为“主任务”。显然,主任务是任务树对应程序的入口,每棵任务树有且只有一个主任务。任务树中除主任务外的其他所有任务都称为“协作任务”,他们一起协同主任务完成问题的求解。根据调用关系,协作任务IniXp都被主任务调用过,都是Rt的儿子。协作任务Fx被所有任务调用,所以他是其它3个任务的儿子。同一个任务被多次调用的现象称为任务的复用。显然,Fx是一个复用任务。

 

7.4.3 遍历编程

   与遍历作业树一样,也是通过遍历任务树形成程序的。对于遍历过程中遇到的每一个任务,就去遍历相应的作业树。但要注意,遍历过程中遇到的复用任务只能被编程一次,不可重复编程。由于任务树所形成的程序是按调用关系运行的,任务程序模块的先后次序并不影响运行,故可以将任务树简化成只有两层的“任务目录树”,根节点仍为主任务,所有协作任务都作为主任务的儿子。图7.7就是对应于图7.6的任务目录树。这样简化并不会引起混乱,即便是某任务没有直接被主任务调用,但它至少会被某协作任务调用。对任务目录树遍历编程,既简单且不必判断复用任务的存在。今后,我们只画任务目录树,并且直接称任务目录树为任务树。

7.7 与图7.6对应的任务目录树

   任务树遍历编程规则:自上至下、从左向右遍历任务树。每进入一个任务节点,就遍历编程相应的作业树。对图7.7的任务树遍历后,就得到下面的任务节点顺序,继而就可以生成相应的伪代码。

//解高次方程//

Rootx(作业树的程序代码)

//选初始点//

Ini(作业树的程序代码)

//求弦截点//

Xp(作业树的程序代码)

//求曲线上点//

Fx(作业树的程序代码)

 

7.4.4 协作关系

   从上面遍历编程任务树的结果可以看出,各任务的程序模块是各自独立的,分别对应一个C函数。这从前面解一元高次方程的四棵作业树中也可以看出,任务之间是调用和被调用的关系,任务程序模块放置的顺序并不会影响程序的正确执行。

   我们称任务之间的调用和被调用关系为协作关系。任务之间相互协作,去求解由任务树所表示的问题。主任务是任务树中唯一不被其它任务调用的任务,其它任务都是协作任务。显然,协作关系是非控制关系。这有点象经济社会中公司之间的相互协作。甲公司与乙公司签订合同,要求乙公司配套生产某产品。但乙公司并不受甲公司的控制,只要按合同要求完成相应产品就可以了。乙公司也可以不与甲公司协作。另一方面,甲公司并不参与乙公司的生产管,其也可以不与乙公司合作,另选别的公司。当然,我们这里没有选择的余地,所需调用的任务是唯一配套的。但调用者并不参与被调用者的内部控制,只要求被调用者提供正确的结果。

   作业树中作业节点之间的关系是控制关系,我们称之为同宗关系。什么叫同宗关系,下一篇博文会有详细讨论。我们知道,作业树本质上是程序流程图,节点之间是依严格的算法逻辑而相互联系的。任务树不属于程序流程图,它是结构图,是表示范畴比任务更大的程序模块的结构树。我们也称作业树为结构树,是任务的结构树。

 

7.5 结束语

   我们看到,任务树的概念很简单,比作业树的概念要简单得多。但是,如何划分任务(子程序)却不容易,这在我们软件设计实践中经常会碰到。辟如这里的例子“弦截法解一元高次方程”,是从谭浩强先生的《C程序设计》一书中摘抄来的,在那本书里关于这个问题的子程序化分就与这里的不同。任务对应的是C函数,如何确定C函数的范畴就是如何划分任务。设计作业树的重点是树内逻辑而不是作业划分,设计任务树的重点是任务划分而不是树内逻辑。在下一篇博文“任务独立规则”中将会讨论相关问题。

转载于:https://my.oschina.net/treesoft/blog/77644

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值