《MATLAB编程-循环结构.pdf》由会员分享,可在线阅读,更多相关《MATLAB编程-循环结构.pdf(35页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、 1目录 目录 第四章 循环结构.1 4.1 while 循环.1 例 4.1.1 4.2 for 循环.5 例 4.2.6 例 4.3.6 例 4.4.8 4.2.1 运算的细节.9 例 4.5.11 4.2.2 break 和 continue 语句.12 4.2.3 循环嵌套.13 4.3 逻辑数组与向量化.14 4.3.1 逻辑数组的重要性.15 例 4.6.15 4.3.2 用 if/else 结构和逻辑数组创建等式.17 测试 4.1.17 4.4 附加例子.18 例 4.7.18 例 4.8.23 4.5 总结.28 4.5.1 好的编程习惯总结.29 4.5.2 matlab
2、总结.29 4.6 练习.29 4.1.29 4.2.29 4.3.29 4.4.29 4.5.29 4.6.30 4.7.30 4.9.31 4.10.31 4.11.31 4.12.31 4.13.31 4.14.31 4.15.31 4.16.31 4.17.32 4.18.32 4.19.32 4.20.32 4.21.33 4.22.33 4.23.33 4.24.33 4.25.34 4.26.34 4.27.34 4.28.34 1第四章第四章 循环结构循环结构 循环(loop)是一种 matlab 结构,它允许我们多次执行一系列的语句。循环结构有两种基本形式:while 循环和
3、 for 循环。两者之间的最大不同在于代码的重复是如何控制的。在while 循环中,代码的重复的次数是不能确定的,只要满足用户定义的条件,重复就进行下去。相对地,在 for 循环中,代码的重复次数是确定的,在循环开始之前,我们就知道代码重复的次数了。4.1 while 循环循环 只要满足一定的条件,While 循环是一个重复次数不能确定的语句块。它的基本形如下 while expression.code block.end 如果 expression 的值非零(true),程序将执行代码块(code block),然后返回到 while 语句执行。如果 expression 的值仍然非零,那么
4、程序将会再次执行代码。直到 expression 的值变为 0,这个重复过程结束。当程序执行到 while 语句且 expression 的值为 0 之后,程序将会执行 end 后面的第一个语句。while 循环的伪代码为 while expr.end 我们将用 whlie 循环编写一个统计分析的程序。例例 4.1 统计分析在科学工程计算中,跟大量的数据打交道是非常平常的事,这些数据中的每一个数据都是对我们关心的一些特殊值的度量。本课程的第一次测验的成绩就是一个简单的例子。每一个成绩都对某一个学生在本课程中学到多少东西的度量。许多的时侯,我们并不关心某一个单个数据。我们可以通过总结得到几个重要
5、的数据,以此告诉我们数据的总体情况。例如,一组数据的平均数(数学期望)和标准差。平均数的定义如下:=NiixNx11 (4.1)其中 xi代表 n 个样本中的第 i 个样本。如果所有的输入数据都可以在一个数组中得到,这些数据的平均数就可以通过公式(4.1)直接计算出来,或应用 matlab 的内建函数mean。标准差的定义如下:2)1()(2112=NNxxNsNiNiii (4.2)标准差则体现随机变量取值与其期望值的偏差。标准差的值较大,则表明该随机变量的取值与其期望值的偏差较大,反之,则表明此偏差较小。如果所有的输入数据都可以在一个数组中得到,这些数据的平均数就可以通过公式(4.2)直接
6、计算出来,或应用 matlab 的内建函数 std。本例的目的是要通过公式 4.1,4.2 计算平均数和标准差,向大家介绍 while循环的应用。我们要执行的算法是读取一个组数据,计算它们的平均数和标准差,最后输出结果。答案:程序必须能读取一系列的测量值,并能够计算出这些测量值的数学期望和标准差。在进行计算之前,我们有 while 循环来读取这些测量值。当所有的测量值输入完毕,我们必须通过一定的方法来告诉程序没有其它的数据输入了。在这里,我们假设所有测量值均为非负数,我们用一个负数来表示数据输入完毕。当一个负数输入时,程序将停止读取输入值,并开始计算这些数据的数学期望和方差。1.陈述问题因为我
7、们假设所有的输入数据为非负数,则合适地问题陈述为:计算一组测量数的平均数和方差,假设所有测量值为非负数;假设我们事先不知道有多少个测量数。一个负数的输入值将代表测量值输入的结束。2.定义输入值和输出值这个程序的输入是未知数目的非负数。输出为这些非负数的平均数和标准差。顺便还要打印出输入数据的数据,以便于检测程序的正确性。3.设计算法这个程序可分为以下三大步:Accumulate the input data Calculate the mean and standard deviation Write out the mean,standard deviation,and number of
8、points 每一大步的为读取输入值。为达此目的,我们必须提示用户输入合适的值。当数据输入完毕,我们将计算出数据的个数,它们的和与平方和。这些步骤的伪代码如下所示 Initialize n,sum_x,and sum_x2 to 0 Prompt user for first number Read in first x while x=0 nn+1 sum_xsum_x+x sum_x2sum_x2+x2 Prompt user for next number Read in next x end 注意我们必须在 while 循环开始之前,我们必须读取第一个值,这样在 while 循环第一次
9、运行中才有了检测值。下一步,我们要计算出数学期望和标准差。这个步骤的伪代码就是公式(4.1)和(4.2)的 matlab 版本。x_bar sum_x/n std_dev sqrt(n*num_x2 sum_x2)/(n*(n-1)最后我们写出输出结果:Write out the mean value x_bar Write out the standard deviation std_dev Write out the number of input data points n 4.将伪代码转化为相应的 matlab 语句最终的 matlab 程序如下%Script file:stats_1
10、.m%Purpose:%To calculate mean and the standard deviation of 3%an input data set containing an arbitrary number%of input values.%Record of revisions:%Date Programmer Description of change%=%12/05/97 S.J.Chapman Original code%Define variables:%n-The number of input samples%std_dev-The standard deviati
11、on of the input samples%sum_x-The sum of the input values%sum_x2-The sum of the squares of the input values%x-An input data value%xbar-The average of the input samples%Initialize sums.n=0;sum_x=0;sum_x2=0;%Read in first value x=input(Enter first value:);%While Loop to read input values.while x=0%Acc
12、umulate sums.n=n+1;sum_x=sum_x+x;sum_x2=sum_x2+x2;%Read in next value x=input(Enter next value:);end%Calculate the mean and standard deviation x_bar=sum_x/n;std_dev=sqrt(n*sum_x2-sum_x2)/(n*(n-1);%Tell user.fprintf(The mean of this data set is:%fn,x_bar);fprintf(The standard deviation is:%fn,std_dev
13、);fprintf(The number of data points is:%fn,n);5.检测程序为检测这个程序,我们将手工算出一组简单数据的平均数和标准差,然后与程序产生的结果进行比对。如果我们用三个输入值:3,4 和 5,那么它的平均数和标准差分别为 4123111=NiixNx 1)1()(2112=NNxxNsNiNiii 我们把这些值输入程序后,产生的结果为 stats_1 Enter first value:3 Enter next value:4 Enter next value:5 Enter next value:-1 The mean of this data set
14、 is:4.000000 The standard deviation is:1.000000 The number of data points is:3.000000 这个结果说明了程序的正确性。在这个例子中,我们并没有完全遵循设计过程。这个失误导致这个软件有一个致命的缺陷。你能指出来它吗?4我们的错误就在于我们没有检测程序所有可能的输入类型。请重看一遍程序。如果我们不输入数或者只输入一个数,那么上面的公式就会出现除以 0 的情况。这种除 0 错误将会在导致在命令窗口内出现 divide-by-zero 的警告,导致输出值为无穷大(NaN)。我们需要修改这个程序来解决这个问题,告诉用户这个
15、问题是什么,并在适当的时侯停止。这个程序的修定版本为 stats_2。在运行运算之前,我们必须检查是否有足够多的输入值。如果没有,程序将打印出错误提示信息,并且跳出。你自己检测一下这个版本的程序。%Script file:stats_2.m%Purpose:%To calculate mean and the standard deviation of%an input data set containing an arbitrary number%of input values.%Record of revisions:%Date Programmer Description of chan
16、ge%=%12/05/97 S.J.Chapman Original code%1.12/06/97 S.J.Chapman Correct divide-by-0 error if%0 or 1 input values given.%Define variables:%n-The number of input samples%std_dev-The standard deviation of the input samples%sum_x-The sum of the input values%sum_x2-The sum of the squares of the input valu
17、es%x-An input data value%xbar-The average of the input samples%Initialize sums.n=0;sum_x=0;sum_x2=0;%Read in first value x=input(Enter first value:);%While Loop to read input values.while x=0%Accumulate sums.n=n+1;sum_x=sum_x+x;sum_x2=sum_x2+x2;%Read in next value x=input(Enter next value:);end%Chec
18、k to see if we have enough input data.if n 0 计算 N 的阶乘的 matlab 代码为 n_factorial=1 for ii=1:n n_factorial=n_factorial*ii;end 假设我们要计算 5 的阶乘。如果 n 为 5,for 循环控制表达式将会产生行向量1 2 3 4 5。这种循环将会执行 5 次,ii 值按先后顺序依次为 1,2,3,4,5。n_factorial 最终的计算结果为 12345=120。例例 4.3 计算 the day of year the day of year 是指这一年已经逝去的天数(包括当天)
19、。在平年中,它的取值范围为 1到 365,在闰年中,它的取值范围 1 到 366。编写一个 matlab 程序,输入年,月,日,输入为对应的 the of year。答案:为了确定 the day of year,程序需要计算先前月份的天数之后,然后再计算当月已经过去了多少天,在求和的过程中将会用到 for 循环。因为每一个月的天数不尽相同,所以我们要确定每一个月的正确天数。我们用 switch 结构来确定它。在闰年时,在二月后的某一天的 the day of year 将会比平年时大 1。因为在闰年的二月份多出一个 2 月 29 号。所以为了正确地计算出 the day of year,我们
20、必须确定那一年是闰年。在公历中,闰年是这样规定的 1.能被 400 整除的年为闰年 2.能被 100 整除但不能被 400 整除的年不为闰年 3.能被 4 整除但不能被 100 整除年为闰年 4.其余的年份不为闰年 我们将用到 mod(求余)函数来确定一个数是否能被另一个数整除。如果函数的返回值为 0,则说一个数能被另一个数整除,否则,则不然。下面是一个用于计算 the day of year 的程序。注意程序如何计算出前面月份总共的天数,如何应用 switch 结构确定每一月的天数。%Script file:doy.m 7%Purpose:%This program calculates t
21、he day of year corresponding%to a specified date.It illustrates the use switch%and for constructs.%Record of revisions:%Date Programmer Description of change%=%12/07/98 S.J.Chapman Original code%Define variables:%day -Day(dd)%day_of_year -Day of year%ii -Loop index%leap_day -Extra day for leap year%
22、month -Month(mm)%year -Year(yyyy)%Get day,month,and year to convert disp(This program calculates the day of year given the);disp(current date.);month=input(Enter current month(1-12):);day=input(Enter current day(1-31):);year=input(Enter current year(yyyy):);%Check for leap year,and add extra day if
23、necessary if mod(year,400)=0 leap_day=1;%Years divisible by 400 are leap years elseif mod(year,100)=0 leap_day=0;%Other centuries are not leap years elseif mod(year,4)=0 leap_day=1;%Otherwise every 4th year is a leap year else leap_day=0;%Other years are not leap years end%Calculate day of year by a
24、dding current day to the%days in previous months.day_of_year=day;for ii=1:month-1%Add days in months from January to last month switch(ii)case 1,3,5,7,8,10,12,day_of_year=day_of_year+31;case 4,6,9,11,day_of_year=day_of_year+30;case 2,day_of_year=day_of_year+28+leap_day;end end%Tell user fprintf(The
25、date%2d/%2d/%4d is day of year%d.n,.month,day,year,day_of_year);我们用下面已知的结果来检测这个程序。1.1999 年不是闰年。它的 1 月 1 号对应的 day of year 是 1,12 月 31 号必定对应的是365。2.2000 年是一个闰年。它的 1 月 1 号对应的 day of year 是 1,12 月 31 号必定对应的是366。83.2001 年不是闰年。它的 1 月 1 号对应的 day of year 是 30。这个程序 5 次运行后的结果分别为 doy This program calculates th
26、e day of year given the current date.Enter current month(1-12):1 Enter current day(1-31):1 Enter current year(yyyy):1999 The date 1/1/1999 is day of year 1.doy This program calculates the day of year given the current date.Enter current month(1-12):12 Enter current day(1-31):31 Enter current year(yy
27、yy):1999 The date 12/31/1999 is day of year 365.doy This program calculates the day of year given the current date.Enter current month(1-12):1 Enter current day(1-31):1 Enter current year(yyyy):2000 The date 1/1/2000 is day of year 1.doy This program calculates the day of year given the current date
28、.Enter current month(1-12):12 Enter current day(1-31):31 Enter current year(yyyy):2000 The date 12/31/2000 is day of year 366.doy This program calculates the day of year given the current date.Enter current month(1-12):3 Enter current day(1-31):1 Enter current year(yyyy):2001 The date 3/1/2001 is da
29、y of year 60.通过 5 次不同情况的检测,这个程序给出了正确的结果。例例 4.4 统计分析 执行如下算法:输入一系列的测量数,计算它们的平均数和标准差。这些数可以是正数,负数或 0。答案:这个程序必须能够读取大量数据,并能够计算出这些测量值的平均数和标准差。这些测量值可以是正数,负数或 0。因为我们再也不能用一个数来表示数据中止的标识了,我们要求用户给出输入值的个 9数,然后用 for 循环读取所有数值。下面的就是这个修定版本的程序。它允许各种输入值,请你自己验证下面 5 个输入值的平均数和标准差:3,-1,0,1,-2。%Script file:stats_3.m%Purpose
30、:%To calculate mean and the standard deviation of%an input data set,where each input value can be%positive,negative,or zero.%Record of revisions:%Date Programmer Description of change%=%12/08/97 S.J.Chapman Original code%Define variables:%ii Loop index%n The number of input samples%std_dev The stand
31、ard deviation of the input samples%sum_x The sum of the input values%sum_x2 The sum of the squares of the input values%x An input data value%xbar The average of the input samples%Initialize sums.sum_x=0;sum_x2=0;%Get the number of points to input.n=input(Enter number of points:);%Check to see if we
32、have enough input data.if n 2%Insufficient data disp(At least 2 values must be entered.);else%we will have enough data,so lets get it.%Loop to read input values.for ii=1:n%Read in next value x=input(Enter value:);%Accumulate sums.sum_x=sum_x+x;sum_x2=sum_x2+x2;end%Now calculate statistics.x_bar=sum_
33、x/n;std_dev=sqrt(n*sum_x2-sum_x2)/(n*(n-1);%Tell user.fprintf(The mean of this data set is:%fn,x_bar);fprintf(The standard deviation is:%fn,std_dev);fprintf(The number of data points is:%fn,n);end 4.2.1 运算的细节运算的细节 既然我们已经看了许多 for 循环的例子。在用 for 循环时,我们必须检查许多重要的细节。1.没有必要缩进 for 循环的循环体。即使所有语句都左对齐,matlab 程序
34、也会识别出这个循环。但缩进循环体能增强代码的可读性,所以建议大家缩进循环体。好的编程习惯 10对于 for 循环体总是要缩进两个或更多空格,以增强程序的可读性。2.在 for 循环中,我们不能随意修改循环指数。循环指数常被用作计算器,如果修改了它们将会导致一些奇怪而难以发现的错误。下面的一个例子将初始化一个函数的数组。但是语句“ii=5”的突然出现,导致只有 a(5)得到了初始化,它得到了本应赋给a(1),a(2)等等的值。for ii=1:10 .ii=5;%Error!.a(ii)=end 好的编程习惯 在循环体中绝不修改循环指数的值。3.我们在第二章已经学过,用赋值的方法可以扩展一个已知
35、的数组。例如,语句 arr=1:4;定义了一个数组1 2 3 4。如果执行语句 arr(8)=6;将会产生一个八元素数组1 2 3 4 0 0 0 6。不幸的是,每一次扩展数组,都要经过以下步骤:第一步,创建一个新数组。第二步,把旧数组的元素复制到新数组当中。第三步,把扩展的元素写入新数组。第四步,删除旧数组。对于大数组来说这些步骤是相当耗时的。当一个 for 循环中存储了一个预先未定义的数组,在第一次循环执行的时侯,循环结构迫使 matlab 重复执行以上步骤。从另一方面说,如果在循环开始之前数组预先分配了数组的大小,那么复制就不需要了,执行代码的速度也将加快。下面代码片段向大家展示了在循环
36、开始之前如何预先分配数组。好的编程习惯 在循环执行开始之前,总是要预先分配一个数组,这样能大大增加循环运行的速度。4.用 for 循环和向量计算是非常常见的。例如,下面的代码片段用 for 循环计算 1 到100 之间的所有整数的平方,平方根,立方根。for ii=1:100 square(ii)=ii 2;square_root(ii)=ii (1/2);cube_root(ii)=ii (1/3);end 下面一个代码片段是用向量计算上面的问题。ii=1:100;square=ii.2;square_root=ii.(1/2);cube_root(ii)=ii.(1/3);尽管两种算法得到
37、了相同的结果,但两者并不同等价。因为 for 循环算法比向量算法慢 15 倍还多。这是由于 matlab 通过每一次循环时,每行都要翻译执行一次。也相当于matlab 翻译执行了 300 行代码。相反,如果用向量算法,matlab 只需要翻译执行 4 行代码。所以用向量语句它的执行速度非常快。向量算法的缺点是需要很大的内存,因为一些间接的数组需要创建。这经常是一小点损失,所以要比 for 循环算法好的多。在 matlab 中,用向量算法代替循环的算法的过程称之为向量化(vectorization)。向量化能够改进许多的 matlab 程序。11好的编程习惯 那种既可以用向量可以解决的问题,也可
38、以用循环解决的问题,最好用向量解决,这是因为向量执行的速度快。例例 4.5 比较向量算法和循环为了比较循环和向量算法执行若无事所用的时间,用两种方法编程并测试三个运算所花的时间。1.用 for 循环计算 1 到 10000 的之间每一个整数的平方,而事先不初始化平方数组。2.用 for 循环计算 1 到 10000 的之间每一个整数的平方,而事先初始化平方数组。3.用向量算法计算计算 1 到 10000 的之间每一个整数的平方。答案:这个程序必须用上面提供的三种方示计算出 1 到 10000 之间的每一个整数的平方,并测试每一个种算法的时间。测试时间要用到 matlab 函数 tic 和 to
39、c。tic 函数复位内建计时器,而 toc 函数则从最后一次调用 tic 以秒开始计时。因为在许多的计算机中它的时间钟是相当粗略的,所以有必要多运行几次以获得相应的平均数。下面就是用三种方法编出的 matlab 程序。%Script file:timings.m%Purpose:%This program calculates the time required to%calculate the squares of all integers from 1 to%10,000 in three different ways:%1.Using a for loop with an uniniti
40、alized output%array.%2.Using a for loop with an preallocated output%array.%3.Using vectors.%Record of revisions:%Date Programmer Description of change%=%12/08/97 S.J.Chapman Original code%Define variables:%ii,jj Loop index%average1 Average time for calculation 1%average2 Average time for calculation
41、 2%average3 Average time for calculation 3%maxcount Number of times to loop calculation%square Array of squares%leap_day Extra day for leap year%month Month(mm)%year Year(yyyy)%Perform calculation with an uninitialized array%square.This calculation is done only once%because it is so slow.maxcount=1;
42、%One repetition tic;%Start timer for jj=1:maxcount clear square%Clear output array for ii=1:10000 square(ii)=ii2;%Calculate square end 12end average1=(toc)/maxcount;%Calculate average time%Perform calculation with a preallocated array%square.This calculation is averaged over 10%loops.maxcount=10;%On
43、e repetition tic;%Start timer for jj=1:maxcount clear square%Clear output array square=zeros(1,10000);%Preinitialize array for ii=1:10000 square(ii)=ii2;%Calculate square end end average2=(toc)/maxcount;%Calculate average time%Perform calculation with vectors.This calculation%averaged over 100 execu
44、tions.maxcount=100;%One repetition tic;%Start timer for jj=1:maxcount clear square%Clear output array ii=1:10000;%Set up vector square=ii.2;%Calculate square end average3=(toc)/maxcount;%Calculate average time%Display results fprintf(Loop/uninitialized array=%8.4fn,average1);fprintf(Loop/initialized
45、 array=%8.4fn,average2);fprintf(Vectorized=%8.4fn,average3);4.2.2 break 和和 continue 语句语句 有两个附加语句可以控制 while 和 for 循环:break 和 continue 语句。break 语句可以中止循环的执行和跳到 end 后面的第一句执行,而 continue 只中止本次循环,然后返回循环的顶部。如果 break 语句在循环体中执行,那么体的执行中止,然后执行循环后的第一个可执行性语句。用在 for 循环中的 break 语句的例子如下:程序执行的结果为:%test_break.m for ii
46、=1:5;if ii=3;break;end fprintf(ii=%d n,ii);end disp(End of loop!);test_break ii=1 ii=2 End of loop!注意 break 语句在 ii 为 3 时执行,然后执行 disp(End of loop!);语句而不执行 fprintf(ii=%d n,ii);语句。continue 语句只中止本次循环,然后返回循环的顶部。在 for 循环中的控制变量将会更 13新到下一个值,循环将会继续进行。下面是一个在 for 循环中的 continue 的例子。%test_continue.m for ii=1:5;i
47、f ii=3;continue;end fprintf(ii=%d n,ii);end disp(End of loop!);程序运行的结果为;test_continue ii=1 ii=2 ii=4 ii=5 End of loop!注意 continue 语句在 ii 为 3 时执行,然后程序返回循环的顶部而不执行 fprintf 语句。break 和 continue 语句可用在 while 循环和 for 循环中。4.2.3 循环嵌套循环嵌套 一个循环完全出现在另一个循环当中,这种情况经常发生。如果一个循环完全出现在另一个循环当中,我们称这两个循环为带嵌套的循环带嵌套的循环。下面的例子
48、用两重 for 循环嵌套来计算并写出结果。for ii=1:3 for jj=1:3 product=ii*jj;fprintf(%d*%d=%d n,ii,jj,product);end end 在这个例子中,外部的 for 循环将把 1 赋值于循环指数 ii,然后执行内部 for 循环。内部循环的循环体将被执行 3 次,它的循环指数 ii 将会先后被赋值为 1,2,3。当完全执行完内部的循环后,外部的 for 循环将会把 2 赋值于循环指数 ii,然后内部的 for 循环将会再次执行。直到外部 for 循环执行 3 次,这个重复过程结束。产生的结果为 1*1=1 1*2=2 1*3=3 2
49、*1=2 2*2=4 2*3=6 3*1=3 3*2=6 3*3=9 注意外部 for 循环指数变量增加之前,内部 for 循环要完全执行完。当 matlab 遇到一个 end 语句,它将与最内部的开放结构联合。所以第一个 end 语句与语句“for jj=1:3”,第二个 end 语句与语句“for ii=1:3”联合。如果在循环嵌套中一个end 语句突然被删除,将会产生许多难以发现的错误。如果 for 循环是嵌套的,那么它们必须含有独立的循环变量。如果它们含有相同的循环变量,那么内部循环将改变外部循环指数的值。如果 break 或 continue 语句出现在循环嵌套的内部,那么 brea
50、k 语句将会在包含它的最内部的循环起作用。for ii=1:3 for jj=1:3 if jj=3;14 break;end product=ii*jj;fprintf(%d*%d=%d n,ii,jj,product);end fprintf(End of inner loopn);end fprintf(End of outer loopn);如果内部循环指数 jj 为 3,那么 break 语句开始执行,这将导致程序跳出内部循环。程序将会打印出”End of inner loop”,外部循环指数将会增加 1,内部循环的执行重新开始。产生的输出值为:1*1=1 1*2=2 End of