Maple6ch51程序设计.docx
《Maple6ch51程序设计.docx》由会员分享,可在线阅读,更多相关《Maple6ch51程序设计.docx(29页珍藏版)》请在冰豆网上搜索。
Maple6ch51程序设计
第五章程序设计
§5.1简单的程序设计
前面已经用过很多Maple的内部函数和程序包带的外部程序。
现在我们要学着自己建立函数了。
先来看一个关于log函数的源代码,这样能熟悉一下Maple编程的一般规则。
>interface(verboseproc=2):
先调用函数interface,设置参数
>readlib(log);调log的源代码。
改log为sin等,就能看这些函数的源代码
5.1.1过程和函数
过程和函数差得不是很多,它们都可以实现对方的功能,如果没有特别说明,我们对
这两种概念将不做区分。
一个Maple语言的过程定义的格式如下:
proc(argseq)
locallseq;
globalgseq;
optionsoseq;
descriptionstringseq;
statseq
endproc
一个过程一定是以proc开头,以endproc(或)结束。
过程可以带一个或几个参数argseq,也可以不带;在过程的内部我们可以定义全局变量gseq,局部变量lseq(下节讲),选项部分(oseq)和描述部分(stringseq)(后面讲);当然在过程中我们也可以按照自己的要求写入语句或者调用Maple提供的过程。
下面我们动手自己编一个程序,如下:
>restart;
>Area:
=proc(r)#Area为变量,是过程名可以直接调用,procedure
>Pi*r^2;#程序带一个形参
>endproc;
>Area(10);调用函数Area计算半径为10时圆面积的值
>evalf(%);
多参数的过程编写跟单参数的编写是完全相同的,只是在各个形参间直接用逗号隔开,下面我们举一个三参数的例子——给定三角形的两边长度及其夹角,求其面积:
>TripleArea:
=proc(a,b,q)
>a*b*sin(q)/2;
>endproc;
>TripleArea(3,4,Pi/2);
但上面的程序并不完善,他们不能判断形参的形式,不能对过程异常给出有用的信息,而这是一个好的过程所必须具备的条件,在本章的后面我们将给出求三角形面积的改进过程。
5.1.2全局变量和局部变量
先看由上面圆面积计算程改造后的程序:
>restart;
Area:
=proc(s)#AreaΪ±äÁ¿£¬Êǹý³ÌÃû¿ÉÒÔÖ±½Óµ÷Óã¬procedure
localr,u;#定义局部变量
globalt;#定义全局变量
r:
=10;
t:
=15;
r*t;
Pi*s^2;#³ÌÐò´øÒ»¸öÐβÎ
endproc;
>Area(10);
>r;#程序中的局部变量,在程序之外没有定义
>t;
>t^2;
C语言中在函数里面定义的变量一般叫局部变量,相对应的在函数外面定义的变量变叫做全局变量了。
而在Maple里全局变量和局部变量的区分跟C语言中有点出入:
在Maple的过程里定义的也可能是全局变量,在上面讲到过程的定义的时候,我们曾经介绍过一个参数gseq,它就是在过程中用global标示符声明的一个全局变量;但有一点可以肯定的是:
在过程外面的肯定是全局变量,因此可以说局部变量肯定在过程里面。
在过程里面的变量怎么判断其是全局变量还是局部变量呢?
一般说来可以看其定义:
如果是用global标示符标示的肯定是全局变量,而用local标示符标示的肯定是局部变量;假如变量没有经过标示定义,以下两种情况Maple自动认为是局部变量:
(1)出现在赋值符左边的变量;
(2)在for循环或seq、add、mul命令中表示计数性质的变量。
除了这两种情况以外的其它变量,Maple将认为是全局变量。
为了对这些有一个较清晰
的了解,我们来看下面的这个过程:
>temp:
=proc()
>globalnG;
>localnL;
>nG:
=1;
>nL:
=2;
>nTemp:
=3;
>forifrom1to10do
>nTemp:
=0;
>od;
>end;
Warning,`nTemp`isimplicitlydeclaredlocaltoprocedure`temp`
Warning,`i`isimplicitlydeclaredlocaltoprocedure`temp`
上面两行末出现的“`temp`”表示程序名
由于我们定义变量i和nTemp,Maple给出了警告信息,并提醒用户这两个变量将被作为局部变量,在生成过程中的例子中我们能很清楚的看到这一点,Maple将这两个变量用示符local定义了。
我们介绍了局部变量和全局变量的判别,下面来看看它们之间的区别。
全局变量不属于过程,它可以存在于过程之外,而局部变量只能存在于过程之内,当过程创建时,局部变量也同时被创建,而当过程销毁时,局部变量也同时被销毁。
我们来看看上面那些变量:
>temp();先调用此函数,才能给出其内的全局部或局部变量的情况
>nL;
>nG;
>nTemp;
>i;
>Log(exp
(1));
>log(exp
(1));
变量nG是我们定义的一个全局变量,当过程Temp结束时,它的值仍然存在,说明变量没有销毁,而局部变量nL在过程之外就存在了,另外两个没有定义,但被Maple默认为局部变量的变量nTemp和i都不存在。
虽然Maple能判断未定义的变量,但对我们来说有点模糊,为了使变量定义比较明了,建议对每一个变量都进行定义。
Maple将不同过程中的局部变量看成是单独的变量,即使变量名相同,它们之间也不会受影响,并且一个过程中的局部变量不会影响同名全局变量,在过程中使用这个变量时,过程内定义的变量优先,即这个变量的值将是局部变量的值,而与同名的全局变量无关,我们来看下面例子:
>Temp1:
=proc()要与前段程序先后执行,才能有下面的调出结果
>localnG;
>nG:
=10;将局部变量赋值为10
>nG;
>end;
>Temp1();
>nG;此为上程序段外变量,仍是前段程序中的全局变量
我们可以看到我们在过程Temp1中将nG定义为局部变量,并在过程中赋值10,但在过程外nG的值不变,还是等于1,上面这些规则跟C语言都是相同的,但关于全局部量的规则有些不同,在Maple中全局变量能够重复定义,后面的定义将覆盖前面的变量(其实是在赋值时覆盖,在定义时不覆盖),我们可以从下面看出:
>Temp2:
=proc()
>globalnG,nG1;
>nG1:
=nG;此时的是上段程序的结果:
nG=1
>nG:
=10;对上面重新定义的全局变量nG赋值为10
>end;
>
>Temp2();
>nG1;
>nG;
为了查看全局变量在定义以后的数值,我们另外定义了一个全局变量nG1,从运行后的结果来看,重新定义后其值并没有改变,直到赋值后其值才改变了。
在程序设计时要注意一点:
在过程中对全局变量进行赋值时要特别小心,因为别的过程也可能在使用这个全局变量,任何全局变量的改变将影响到所有使用这个变量的过程,而用户往往注意不到这一点,因此在选择变量的类型时要特别注意。
另外为了保持程序的模块化、增强程序的可读性,一般不在过程内部定义全局变量,假如过程内需要用到全局变量的值,一般都用参数来传递,这些原则跟其他高级语言的程序设计原则是一样的。
5.1.3参数声明和标识符args的使用
在调用过程中我们往往要用到形参,Maple允许不定义参数的类型而直接使用,但有时为了限制参数的类型,希望在输入的参数与我们预先定义的参数不匹配时,系统能够给出出错的信息,我们就应该进行参数类型的声明,参数声明的语法如下:
parameter:
:
type;
parameter是参数名,type为参数的类型。
先来看下面的这个过程
>CircleArea:
=proc(r:
:
positive)
>Pi*r^2;
>end;
这个过程前面已经出现过,但那里并没有设定参数的类型——r应为正数。
注:
Maple参数的类型多种多样,读者可以利用命令?
type来查看帮助。
在C语言中传递参数都是通过定义函数的形参来确定的,这就需要知道形参的具体个数和类型,但有时我们在定义的过程中并不知道参数的个数,或者参数的个数是可变的,碰到这种情形C语言一般都是很让人头疼的,但在Maple中事情就变得很简单,Maple提供了一个全局变的标识符args来传递参数,我们可以在定义过程中不定义形参,而直接使用args,因为在调用过程时Maple会自动将参数传给args,来看一个例子:
>SSum:
=proc()
>locali,total;
>total:
=0:
>forifrom1tonargsdo
>total:
=total+args[i];
>enddo;
>total;
>end;
这个过程没有任何形参的定义,除了用到标识符args以外,还用到了一个参数nargs,它是系统用来存储参数个数的一个变量,当我们调用过程时,系统自动将参数个数赋给它,这一点给我们编程带来了很大的方便,下面我们分别代入1、2、3个参数来看看结果:
>SSum(12);
>SSum(10,11);
>SSum(10,11,12);
>
这个过程输入的参数除了可以是具体的数外,还可以是序列,如下:
>seq1:
=seq(n,n=1..100);
利用标识符args,再结合参数nargs,我们就能很方便地处理形参个数不定的情形了。
5.1.4参数声明和标识符args的使用
为了增强程序的可读性,我们经常要在程序的开头或各条语句的后面加上注释语句,系统在编译时忽略注释语句。
Maple用“#”作为注释语句的标志:
>T:
=proc()
>localx;#xisalocalviarable
>x:
=10;
>end;
>T();
另外也可放在过程的开头或前面注释过程的用途:
>#******************#
>#procCircleArea#
>#ComputetheAreaofaCircle#
>#******************#
>CircleArea:
=proc(r:
:
positive)#可先写过程行,再注释
>pi*r^2;
>end;
描述语句类似于注释语句,它对程序的功能也没有影响,但系统编译的时候并不能忽略它,并且在程序的编译后能够给出一条注释语句,其具体形式如下:
descriptionstringseq;
参数stringseq就是我们希望过程编译后提供注释的内容,描述语句在编译后的过程中存在,但在过程运行时并不显示:
>CircleArea:
=proc(r:
:
positive)
>description"ComputetheAreaofacircle";
>Pi*r^2;
>end;
>CircleArea(10);
要查看一个过程可以用print函数,比如:
>print(CircleArea);
5.1.5过程返回值设置
一般为了得到返回值,要用Maple的过程返回值的设置,在默认情况下,过程返回值是过程语句中最后一条语句的值,这种返回方式我们已在前面见过,如上程序的返回值:
>f:
=CircleArea
(1);
求圆面积的过程的返回值就是一个求面积的语句计算么到的结果,这条语句就是最后一条语句,假如在求面积的语句后面再加上一条语句(显示半径的语句),返回的将是新加上去的语句的值,如下:
>CircleArea:
=proc(r:
:
positive)
>pi*r^2;
>r;
>end;
>f:
=CircleArea
(2);
上面我们都是返回一个参数,其实默认的返回方式也可以实现多参数的返回,只需将要返回的语句写在同一条语句里即可,看下面的例子:
>CircleArea:
=proc(r:
:
positive)
>r,pi*r^2;
>end;
>CircleArea(10);
要将多个返回值赋给外面的全局变量,我们只需要像以前那样赋值即可:
>r:
=%[1];
>area:
=%%[2];
参数的返回除了用系统默认的返回方式外,还可以用给形式参数赋值的方式来返回所需要的结果,这种方法跟C语言的参数赋值返回是一样的:
>CircleArea(10,q,area);
>q;
>area;
为了将第二、三个参数作为被赋值的参数,我们将它们声明为evaln类型,这个类型能将一个变量名传入。
除了以上两种方式能够实现过程值的返回以外,还有一种很常见的返回方式:
利用return(或RETURN)来实现强制返回,函数的具体表达式如下:
returnexpr1,expr2,…;
return(expr1,expr2,…);
RETURN(expr1,expr2,…)
参数expr1,expr2,…是返回的值(也可以是表达式或字符串),返回的值可以为空。
使用时要注意没有RETURNexpr1,expr2,…这种格式:
>CircleArea:
=proc(r:
:
positive)
>returnr,pi*r^2;
>end;
>CircleArea(10);
return(RETURN)返回语句将结束过程返回,其后面的语句将不再被执行,所以这条语句也可以作为中断过程进行强制返回的语句:
>CircleArea:
=proc(r:
:
positive,area:
:
evaln)
>returnr,pi*r^2;
>area:
=Pi*r^2;
>end;
>CircleArea(20,area);
>area;
上面这个过程中,我们在return语句后面的赋值语句并没有被执行,全局变量的值仍然是100,而不是我们希望的400。
因此在设计程序时,假如要返回多个参数,都应该用一条return语句带回多个返回值,避免用多条return语句返回。
return语句很简单,功能也很单一,但在结构化程序设计中,这条语句非常有用,我们在后面还将经常用到。
5.1.6格式输出函数printf
函数printf能输出若干个任意类型的数据,其一般格式为
printf(fmt,x1,…,xn);
参数fmt表示“格式控制”,是用双引号括起来的字符串,也称“转换控制字符串”,它包括两种信息:
(1)式说明,由“%”和格式字符组成,如%d,%f等。
它的作用是将输出的数据转换
为指定的格式输出。
格式说明总是由“%”字符开始的。
(2)通字符,即需要原样输出的字符。
参数x1,…,xn是函数将要输出的一些数据,
也可以是表达式。
如
printf(“%d%d”,a,b);printf(“a+b=%,a-b=%d”,a+b,a-b)
>a:
=10:
b:
=6:
>printf("%d,%d",a,b);
10,6
>printf("a+b=%d,a-b=%d",a+b,a-b);
a+b=16,a-b=4
函数printf的格式字符有很多种,几种最常用的格式字符为:
(1)d格式——输出十进制数:
1)%d,按整数型数据的实际长度输出;2)%md,字符m指定输出值段的宽度,如果数据的位数小于m,则左端补以空格,若大于m,则按实际们数输出。
如:
>a:
=12345:
b:
=123:
>printf("%4d,%4d",a,b);
12345,123后面的数的前面有一空格
(2)o格式——以八进制数形式输出整数,由于是将内存单元中的各位的值(0或1)按八进制形式输出,因此输出的数值不带符号,即将符号位也一起作为八进制的一部分输出。
如
>a:
=-1:
>printf("%d,%13o,%8o",a,a,a-a);
-1,37777777777,0
(3)x格式——以十六进制数形式输出整数。
同样也不会出现负的十六进制数。
(4)f格式——用来输出实数(包括单、双精度),以小数形式输出。
有以下几种用法:
1)%f,不指定字段宽度,由系统自动指定,使整数部分全部如数输出,并输出6位小数。
如:
>f:
=12.111:
>printf("%f",f);
12.111000
2)%m.nf,指定输出的数据共点m列,其中有n位小数,注意小数点也占一列,
如果数值长度小于m,则左端补空格。
如
>printf("%5.2f,%10.3f",f,f);
12.11,12.111
3)%-m.nf,与%m.n基本相同,只是输出的数值向左端靠,右端补空格。
(5)e和E格式符——以指数形式输出实数。
可用以下形式:
1)%e,不指定输出数据所占的宽度和数值部分小数位,由系统自动给出6位小数,指数部分占4位,数值按标准化指数形式输出(小数点前仅有一个非零数字)。
如
>e:
=12.111:
>printf("%e",e);
1.211100e+01
2)%m.ne,%-m.ne,两者的含义同前
>printf("%5.2e,%-20.5e,%10.2e",e,e,e);
1.21e+01,1.21110e+01,1.21e+01
(6)g格式符——用来输出实数,它根据数据的大小,自动选f格式或e格式(选择输出时占宽度较小的一种),且不输出无意义的零。
如
>printf("%g%g%g\n",123,123/456,123456789);
123.2697371.234568e+08
(7)c格式符——用来输出一个字符。
如
>c:
='c':
>printf("%c",c);
c
(8)s格式符——用来输出一个字符串。
有几种用法:
1)%s,按实际长度输出字符串。
2)%ms,输出字符串占m列,如字符串本身大于m列,则突破m的限制,将字符全部输出,若串长小于m,则左补空格(%-ms右):
3)%m.ns,输出占m列,但只取字符串中左端n个字符输在右侧,左侧补空。
(%-m.n)
>s:
="It'sme!
":
>printf("%s,%-12s,%12s,%3.6s,%10.4s",s,s,s,s,s);
It'sme!
It'sme!
It'sme!
It'sm,It's
(9)a,A格式符和q,Q格式符——a和A用来准确地输出Maple中的表达式。
而q和Q跟a的功能相似,只是这个格式符将后面所有的表达式序列都用a格式转换后输出:
>a:
=-1:
b:
=123:
f:
=12.111:
e:
=12.111:
c:
='c':
>printf("head=%a\ntail=%q\n",a,b,c,d,e,f);
head=-1
tail=123,c,d,12.111,12.111
§5.2选择结构
判断给定的条件是否满足,并根据判定的结果(真或假)决定执行给出的两种操作之一,这种程序结构就是选择结构。
Maple里的选择结构跟其他高级语言一样,也是用if语句来实现的,下面分三种形式介绍,并简略介绍一下if语句嵌套结构的使用。
普通的if语句可以分成三种形式:
5.2.1if(表达式)then语句1fi
当表达式的值为真时,过程转入语句1执行,否则跳出选择语句:
>Max:
=proc(x:
:
numeric,y:
:
numeric)
>if(x>=y)thenreturnx;
>fi;也可用“endif”
>end;
>Max(1,2);跳出
>Max(3,2);
5.2.2if(表达式)then语句1else语句2fi
当表达式的值为真时,执行语句1,否则执行语句2:
>Max:
=proc(x:
:
numeric,y:
:
numeric)
>if(x>=y)thenreturnx;
>elsereturny;
>endif;
>end;
>Max(1,2);
>Max(3,2);
5.2.3多语句选择结构
if(表达式1)then语句1
elif(表达式2)then语句2
elif(表达式3)then语句3
┇
elif(表达式n)then语句n
else语句n+1
endif
>Test:
=proc(x:
:
numeric)
>if(x>100)thenreturn("xismorethan100");
>elif(x>=10)thenreturn("xisbetween10end100");
>elif(x>0)thenreturn("xisbetween0and10");
>elsereturn("xislessthan0");
>endif;
>end:
>Test(101);
>Test(50);
>Test(5);
>Test(-10);
注:
if还可以嵌套组合使用,就是一个语句中含多个if语句,它们的一般形式如下:
if(表达式1)then
if(表达式2)then语句1
else语句2
endif
else
if(表达式3)then语句3
else语句3
endif
endif
当然各个语句中也可以没有else语句部分,且嵌套的层数可以不止一层,子if语句下面还可以嵌套if语句,如:
>Test:
=proc(x:
:
numeric)
>localy;
>if(x>100)then
>if(x>200)then
>y:
=2;
>return(y);
>elsey:
=1;
>return(y);
>endif;
>elsey:
=0;
>return(y);
>endif;
>end;
>Test(400);
>Test(200);
>Test(100);
§5.3循环结构
5.3.1for…do循环
for变量名i[from表达式1][by表达式2]to表达式3do
语句
enddo;
变量名i是用来控制循环的一个变量,既可以是全局变量也可以是局部变量;from语句后放一个能计算出数值的代数表达式,表示变量i开始的值,这个语句放在方括号中表示这部分可以省略,当语句省略时,系统默认值1;by语句用来设置变量变化的增量(步长),可以是正值也可以负值,此语句也可以省略,省略时步长为1;表达式3表示的数值是变量i的最后界限,当步长为正,变量i的值大于表达