MatLab中文版word版第三章Word文档下载推荐.docx
《MatLab中文版word版第三章Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《MatLab中文版word版第三章Word文档下载推荐.docx(56页珍藏版)》请在冰豆网上搜索。
图3.1
2.定义程序所需的输入量和程序所产生的输出量
指定输入量和输出量,只有这样新的程序才能适应全过程计划。
在这个例子中方程式的系数可能有其预先存在的顺序,我们的新程序必须能按照顺序读取它们。
相似地,也需要产生出这个程序所要求的结果,即输出量,我们还要以一定的格式打印出来。
3.设计你的程序得以实现的算法
算法是指为某个问题找到答案一步接一步的程序。
在这个阶段自上而下的编程方法发挥了作用。
编程设计者开始对这个问题进行逻辑划分,把它逐步分解为一个又一个子工作。
这个过程叫做分解(decomposition)。
如果一些子工作还是比较大,设计者还可以把他它分解成更小的块。
这个过程将会继续到问题被分解成许多简单且易理解的小块为止。
在问题被分解成小块之后,每一个小块要被进一步的求精,这个过程叫做逐步求精(stepwiserefinement)。
在这个过程中,设计者开始于对本小块代码总括性的描述,然后开始一步一步地定义所需的函数,越来越具体,直到他能够转化为MATLAB语句。
逐步求精的过程中,我们要用到的伪代码将会在下节为大家介绍。
在算法开发过程中,这个方法是非常有用的。
如果设计者真正理解了解决问题这个些步骤,他将会对问题进行分解和逐步求精。
4.把算法转化为代码
如果分解和逐步求精的过程已经顺利完成,那么这一步将会异常地简单。
所有程序员都会将伪代码一句一句地转化为合适地MATLAB语句。
5检测产生的MATLAB程序
这一步是真正的拦路虎。
首先,程序的每一部分将会被单独地检测,如果有可能的话,整个程序还要被检测一遍。
在我们检测程序时,我们必须证明所有合法输入数据值都能够正常运行。
用标准的输入值检测程序,看它是否产生了值。
如果在一个程序中执行的算法包含了不同的分支,你必须检测每一个分支,以保证产生正确的答案。
大程序在交付大众使用之前,必须经过一系列地检测(图3.2)。
检测的第一步有时被称为单元检测(unittesting)。
在单元检测过程中,程序的子程序将会被独立地检测以证明它的正确性。
当单元检测结束之后,这个程序将进行一系列的组合,把独立的子程序联合产生出最后的程序。
程序第一步的联合通常只包括很少的子程序。
通过组合这些子程序,经常用检查子程序或函数之间的联系。
在一系列地组合过程中,越来越多的子程序被加了进来,直到整个程序的完成。
在每一次组合的过程中,每一个错误都会被发现并在进行下一次组合之前纠正过来。
图3.2大程序典型地调试过程
在整个程序被组合之后,调试继续进行。
程序第一个版本我们通常称之为“alpha版本”。
程序员和其他有机会接近它的人可以想尽一切办法应用它,以发现其中的漏洞,然后改正之。
当许许多多大的错误从程序中去除,一个新的版本出现了,我们称之“beta版本”。
beta版本就要公开地发行给天天需要这个程序工作的人。
这些用户使这个程序在不同的环境下,在不同的输入条件下工作,会发现许多的错误,并报告给程序员。
当这些错误被更正后,这个程序就能够发行给公众使用了。
因为本书中的程序都比较小,没有必要进行上述的大规模的检测。
但是我们会遵循基本的调试原则。
程序设计的基本步骤如下:
1.清晰地陈述出你要解决的问题。
2.确定程序所需地输入量和程序所产生的输出量。
3.为你的程序设计算法
4.将算法转化为MATLAB语句
5.调试MATLAB程序
好的编程习惯
遵循上面的步骤编写可靠,易理解的MATLAB程序。
在大的编程项目中,花在编程序的时间是出奇的少。
FrederickPBrooks在他的theMythicalManMonth书中写道,对于大的软件工程来说,三分之一的时间花在计划如何来做上(第一步到第三步),六分之一的时间花在编写程序上,近一半的时间用来调试程序。
而我们能做的只有压缩调试用的时间。
在计划阶段做好充分的准备和在编程过程使用良好的编程习惯,这样会大大降低我们调试所用的时间。
好的编程习惯能减少出错的数量,也能使别人迅速地找出其中的错误。
3.2伪代码的应用
作为我们设计步骤的一部分,描述出你要执行的算法是非常必要的。
算法的描述有一种标准形式,能让你和大家都能理解,这种描述将帮助你的内容转化为MATLAB代码。
我们用于描述算法的标准形式叫做构造(constructs有时也称structure)。
用这些结构描述出的算法,我们称之为结构化算法。
当在我们在MATLAB程序中执行这个算法时,产生的程序叫做结构化程序。
我们可以用伪代码的形式建立算法的结构。
伪代码是MATLAB和英语的混合体。
和MATLAB一样,它是结构化的,一行表达一个明确的意思或代码的片段,但每一行的描述用的是英语或其他人类语言。
伪代码的每一行都应用普通简单且易于理解的英语或中文描述。
因为修改简单灵活,所以伪代码在开发算法的过程中非常的有用。
因为伪代码给编辑器或字处理器(通常用于编写MATLAB程序)的,而不需要其他的可视化功能。
例如下面是例2.3的算法伪代码
PromptusertoentertemperatureindegreesFahrenheit
ReadtemperatureindegreesFahrenheit(temp_f)
temp_kinkelvins←(5/9)*(temp_f-32)+273.15
Writetemperatureinkelvins
注意用向左指的箭头←替代等号(=)指出一个值将存储到对应的变量中,这样就避免了赋值号与等号的混淆。
在把它们转化为MATLAB代码之前,伪代码将有助于你思想的组织。
3.3关系运算符和逻辑运算符
选择结构的运算由一个表达式控制的,这个表达式的结果只有true
(1)和false(0)。
有两种形式的运算符可以在MATLAB中关系得到true/false:
关系运算符和逻辑运算符。
跟C语言一样,MATLAB没有布尔型和逻辑数据类型。
MATLAB把0值作为结果false,把所有的非0值作为结果ture。
3.3.1关系运算符
关系运算符是指两数值或字符操作数的运算符,这种运算将会根椐两操作数的关系产生结果true或false。
关系运算的基本形式如下
a1opa2
其中a1和a2是算术表达式,变量或字符串,op代表表3.1中的关系运算符中的一个。
如果两者的关系为真(true)时,那么这个运算将会返回1值;
否则将会返回0值。
表3.1关系运算符
运算符
运算
==
等于
~=
不等于
>
大于
=
大于或等于
<
小于
小于或等于
下面是一些关系运算和它的结果运算结果
3<
4
1
=4
3==4
3>
4<
'
A'
<
'
B'
最后一个运算得到的结果为1,是因为字符之间的求值要按照子母表的顺序。
关系运算符也可用于标量与数组的比较。
例如,如果
和b=0,那么表达式a>
b将会产生结果
。
关系运算符也可比较两个关系运算符,只要两个数组具有相同的大小。
例如
,
,表达式a>
=b将会产生结果
如果这个数组具有不同的大小,那么将会产生运行时错误。
注意因为字符串实际上是字符的数组,关系运算符也比较两个相同长度的字符串。
如果它们有不同的长度,比较运算将会产生一个错误。
在第六章中我们将会学到一个更普遍的方法。
等于关系运算符由两个等号组成,而赋值运算符只有一个等号。
它们是完全不同的两个符号,初学者极易混淆。
符号==是一个比较运算符,返回一个逻辑数,而符号=是将等号右边的表达式的值赋给左边的变量。
当进行比较运算的时候,初学者经常用误用符号=。
常见编程错误
小心谨慎不要混淆了等于关系运算符(==)和赋值运算符(=)。
在运算的层次中,关系运算在所有数学运算的之后进行。
所以下面两个表达式是等价的,均产生结果1。
7+3<
2+11
(7+3)<
(2+11)
3.3.2小心==和~=运算符
等于运算符(==)如果两变量值相同将会返回变量值1,如果不同将返回0。
不等运算符(~=)如果两变量值不同则返回1,相则返回0。
用这两个运算符比较两个字符串他是安全的,不会出现错误。
但对两个数字数据的比较,将可能产生异想不到的错误。
两个理论上相等的数不能有一丝一毫的差别,而在计算机计算的过程中出现了近似的现象,从而可能在判断相等与不相等的过程中产生错误,这种错误叫做roundoff错误。
例如,考虑下面的两个数,两者均应等于0。
a=0;
b=sin(pi);
因为这两个数在理论上相等的,所以关系式a==b应当返回值1。
但在事实上,MATLAB计算所产生的结果的是
a=0;
b=sin(pi);
a==b
ans=
0
MATLAB报告了a和b不同因为他产生了一个roundoff错误,在计算中sin(pi)产生了结果1.2246×
10-16而不是0。
两个理论上相等的值因为roundoff错误而失之发生了细微的差别。
我们可以通过检测两数之间在一定的范围内是不是近似相等,在这个精确范围内可能会产生roundoff错误。
例如测试
abs(a-b)<
1.0E-14
1
将会产生正确的结果,不管在a与b的计算中产不产生的roundoff错误。
在我们检测两数值是否相等时一定要小心,因为roundoff错误可能会使两个本来应该相等的值不相等了。
这时你可以在roundoff错误的范围内它是不是近似相等。
3.3.3逻辑运算符
逻辑运算符是联系一个或二个逻辑操作数并能产生一个逻辑结果的运算符。
有三个二元运算符:
分别为AND,OR和异或运算符,还有一个一元运算符NOT。
二元逻辑运算的基本形式
l1opl2
一元逻辑运算的基本形式为
opl1
l1和l2代表表达式或变量,op代表表3.2中的逻辑运算符。
如果l1和l2的逻辑运算关系为true,那么运算将会返回值1,否则将会产生0。
表3.2逻辑运算符
&
逻辑与
|
逻辑或
xor
逻辑与或
~
逻辑非
运算的结果总结在真值表3.3中,它向我们展示每一种运算所有可能的结果。
如果一个数的值不为0,那么MATLAB将把看作true,如
表3.3逻辑真值表
输入
与
或
异或
非
l1
l2
l1&
l2
l1|l2
xor(l1,l2)
~l1
果它为0,则其为false。
所以~5的结果为0,~0的结果为1。
标量和数组之间也可进行逻辑运算。
例如,
,b=0,那么表达式a&
。
两数组之间也可进行逻辑运算,只要它们具有相同的大小。
则a|b产生的结果
如果两个数的大小不相同,那么将会产生运行时错误。
在运算的顺序中,逻辑运算在所有的数学运算和关系运算之后进行。
表达式中的运算顺序如下:
1.所有的数学运算按照前面描述的顺序的进行。
2.从左向右依次进行关系运算
3.执行所有~运算
4.从左向右依次进行&
5.从左向右依次进行|运算和数学运算一样,括号能够改变括号的默认顺序。
下面是关于逻辑运算的一些例子。
例3.1
假设下面有三个变量被初始和一些表达式及其运算结果。
value1=1
value2=0
value3=-10
逻辑表达式
结果
(a)~value1
(b)value1|value2
(c)value1&
value2
(d)value1&
value2|value3
(e)value1&
(value2|value3)
(f)~(value1&
value3)
因为~运算在其它的逻辑运算之前进行,那么(f)中的括号是必须的。
如果去掉括号的话,(f)表达式将等价于(~value1)&
value3。
3.3.4逻辑函数
MATLAB中有大量的逻辑函数,在条件满足时,函数返回1。
条件不满足时,返回0。
这些函数和逻辑运算与关系联合在组成选择结构和循环结构。
表3.4列出了一系列的逻辑函数。
表3.4MATLAB逻辑函数
函数
用途
ischar(a)
a是字符数组返回1,否则返回0
isempty(a)
a是空数组返回1,否则返回0
isinf(a)
a是无穷大,则返回1,否则返回0
isnan(a)
a不是一个数则返1,否则返回0
isnumeric(a)
a是一个数值数组返回1,否则返回0
测试3.1
本测试提供了一个快速的检查方式,看你是否掌握了3.3的基本内容。
如果你对本测试有疑问,你可以重读3.3,问你的老师,或和同学们一起讨论。
在附录B中可以找到本测试的答案。
变量a,b,c,d定义如下,计算后面的表达式。
a=20;
b=-2;
c=0;
d=1;
1.a>
b2.b>
d;
3.a>
b&
c>
d4.a==b
5.a&
b>
c6.~~b
a=2;
b=
c=
d=
7.~(a>
b);
8.a>
c&
c;
9.c<
=d
b=3;
c=10;
d=0;
10.a*b^2>
a*c
11.d|bb>
a
12.(d|b)>
b=-2;
d='
Test'
;
13.isinf(a/b)
14.isinf(a/c)
15.a>
ischar(d)
16.isempty(c)
3.4选择结构(分支语句)
选择结构可以使MATLAB选择性执行指定区域内的代码(称之为语句块blocks),而跳过其他区域的代码。
选择结构在MATLAB中有三种具体的形式:
if结构,switch结构和try/catch结构。
3.4.1if结构
if结构的基本形式如下:
ifcontrol_expr_1
elseifcontrol_expr_2
else
end
其中controlexpression控制if结构的运算。
如果control_expr_1的值非0,那么程序将会执行语句块1(block1),然后跳到end后面的第一个可执行语句继续执行。
否则,程序将会检测control_expr_2的值,。
如果control_expr_2的值非0,那么程序将会执行语句块2(block2),然后跳到end后面的第一个可执行语句继续执行。
如果所有的控制表达式(controlexpression)均为0,那么程序将会执行与else相关的语句块。
在一个if结构中,可以有任意个elseif语句,但else语句最多有一个。
只要上面每一个控制表达式均为0,那么下一个控制表达式将会被检测。
一旦其中的一个表达式的值非0,对应的语句块就要被执行,然后跳到end后面的第一个可执行语句继续执行。
如果所有的控制表达式(controlexpression)均为0,那么程序将会执行else语句。
如果没有else语句,程序将会执行end后面的语句,而不执行if结构中的部分。
注意MATLAB在if结构中的关键字end与第二章中提到的返回已知下标最大值函数end完全不同。
matlab通过end在M文件中的上下文来区分开它的两个用途。
在大多数情况下,控制表达式均可以联合关系运算符和逻辑运算符。
正像我们在本章早些时侯学到的,当对应的条件为真时,关系运算和逻辑运算将会产生1,否则产生0。
所以当一个运算条件为真时,运算结果为非0,则对应的语句块,就会被执行。
例如,一元二次方程的基本形式如下:
ax2+bx+c=0(3.1)
其解为
(3.2)
其中b2-4ac是我们熟知的判别式,当b2-4ac>
0时,方程式有两个不同的实数根,当b2-4ac=0,有两个相同的实数根,当b2-4ac<
0时,方程式有两个不同的复根。
假设我们检测某一元二次根的情况,并告诉使用者这个方程有两个复根,还是两个相等的实根和两个不相等的实根。
用伪代码这个结构的形式如下:
if(b^2-4*a*c)<
Writemsgthatequationhastwocomplexroots.
elseif(b^2-4*a*c)==0
Writemsgthatequationhastwoidenticalrealroots.
Writemsgthatequationhastwodistinctrealroots.
转化为MATLAB语言:
disp('
Thisequationhastwocomplexroots.'
);
elseif(b^2-4*a*c)==0
Thisequationhastwoidenticalrealroots.'
Thisequationhastwodistinctrealroots.'
回忆一下,判断为真时,关系运算符将会返回一个非0值,从而导致对应语句的执行。
为增加程序的可读性,在if结构中的语句块中最好缩进2到3个空格,而实际上没有必要。
if结构体经常缩进2到3个空格,以增强程序的可读性。
你可以在一行内写完一个完整的if结构,只需把结构的每一部分后面加上
分号或逗号,所以下面的两个结构是等价的:
ifx<
y=abs(x);
和
0;
end
但是这种方式只适用于简单的结构。
3.4.2if结构举例
我们将用两个例子来说明if结构的用途
例3.2
求一元二次方程的根
设计并编写一个程序,用来求解一元二次方程的根。
答案:
我们将本章开头介绍的方法进行编程。
1.陈述问题这个问题的陈述非常的简单,我们要求一元二次方程的根,不管它的根是实根还是复根,有一个根还是两个根。
2.定义输入和输出
本程序的输入应为系数a,b,c
输出量应为两个不相等的实数。
两个相等的实数或两个复数。
3.写出算法本程序可分为三大块,它的函数分别为输入,运算过程和输出。
我们把每一个大块分解成更小的,更细微的工作。
根据判别式的值,可能有三种计算途径,
读取输入的数据
计算出根
输入出根
所以我们要用到有三种选项的if结构。
产生的伪代码如下
Prompttheuserforthecoefficientsa,b,andc.
Reada,b,andc
discriminant←b^2-4*a*c
ifdiscriminat>
x1←(-b+sqrt(discriminant))/(2*a)
x1←(-b-sqrt(discriminant))/(2*a)
Writeoutthetworoots.
elseifdiscriminant==0
x1←-b/(2*a)
Writeouttherepeatedroots.
real_part←-b/(2*a)
imag_part←sqrt(abs(discriminant))/(2*a)
en