任何编程语言都需要流程控制,MATLAB也不例外。但MATLAB里有一个很重要的原则:能用矩阵运算就不用循环,循环在MATLAB里相对慢。这篇文章讲清楚各种控制结构的语法和适用场景。
if-elseif-else 条件判断
基本语法:
score=82;ifscore>=90grade='A';elseifscore>=80grade='B';elseifscore>=60grade='C';elsegrade='F';end多条件组合:
x=15;y=-3;% && 和 || 是短路运算符,用于标量ifx>0&&y<0disp('x正y负')end% & 和 | 是逐元素运算符,用于数组v=[1,-2,3,-4];v(v>0&v<5)% 取1到5之间的元素字符串条件判断:
method='spline';ifstrcmp(method,'linear')disp('线性插值')elseifstrcmp(method,'spline')disp('样条插值')end% R2017a之后可以直接比较string类型ifmethod=="spline"disp('样条插值')endswitch-case
枚举类型的多分支判断,比写一堆 if-elseif 清晰:
signal_type='sine';switchsignal_typecase'sine't=0:0.01:1;x=sin(2*pi*5*t);case{'square','rect'}% 多值用cell合并t=0:0.01:1;x=square(2*pi*5*t);case'sawtooth't=0:0.01:1;x=sawtooth(2*pi*5*t);otherwiseerror('不支持的信号类型:%s',signal_type)endswitch 也可以匹配数值:
n=3;switchncase1disp('一')case{2,3}disp('二或三')otherwisedisp('其他')endfor 循环
基础用法:
% 遍历数值范围fori=1:5fprintf('i = %d\n',i)end% 自定义步长fork=0:0.2:1disp(k)end% 倒序fori=10:-1:1fprintf('倒数 %d\n',i)end遍历矩阵的列:
A=[147;258;369];% for循环遍历矩阵时,每次取一列forcol=Adisp(col)% 每次col是一个列向量end遍历cell数组:
files={'data1.csv','data2.csv','data3.csv'};fork=1:length(files)data=readmatrix(files{k});fprintf('文件 %s 加载了 %d 行数据\n',files{k},size(data,1))end预分配内存(重要性能技巧):
% 错误示范:动态扩容,每次循环都要重新分配内存,速度极慢result=[];fori=1:10000result=[result,i^2];% 每次都复制整个数组end% 正确做法:提前分配好大小result=zeros(1,10000);% 预分配fori=1:10000result(i)=i^2;% 只填值,不重新分配end这个差别在数据量大时非常明显,10000次循环可能差10倍速度。
while 循环
当循环次数不确定时用while:
% 牛顿法求平方根x=2.0;% 初始猜测target=10.0;whileabs(x^2-target)>1e-8x=(x+target/x)/2;endfprintf('sqrt(%.1f) ≈ %.10f\n',target,x)防止死循环:
max_iter=1000;iter=0;whilecondition&&iter<max_iter% 迭代计算...iter=iter+1;endifiter>=max_iterwarning('达到最大迭代次数,可能未收敛')end工程代码里,while循环一定要设置最大迭代次数保护,否则算法不收敛时程序会一直卡着。
break 和 continue
break:提前结束循环
% 找第一个大于10的元素data=[3,7,2,15,4,9];found_idx=-1;fori=1:length(data)ifdata(i)>10found_idx=i;break% 找到就立即跳出endend% 更简洁的写法(向量化)found_idx=find(data>10,1,'first');continue:跳过本次,继续下次
% 只处理正数data=[1,-2,3,-4,5,-6];result=zeros(size(data));fori=1:length(data)ifdata(i)<=0continue% 跳过负数和零endresult(i)=sqrt(data(i));end同样,continue的用途大多可以用逻辑索引替代,性能更好:
result=zeros(size(data));pos=data>0;result(pos)=sqrt(data(pos));try-catch 异常处理
读文件、调外部函数时,错误处理必不可少:
filenames={'data1.csv','missing.csv','data3.csv'};results=cell(length(filenames),1);fork=1:length(filenames)trydata=readmatrix(filenames{k});results{k}=mean(data(:));fprintf('✓ %s 处理完成,均值=%.4f\n',filenames{k},results{k})catchME% ME是MException对象fprintf('✗ %s 失败:%s\n',filenames{k},ME.message)results{k}=NaN;endend获取错误信息:
tryx=1/0;% 不会报错,InfA=[12;34];A(5,5)% 这会报错catchMEfprintf('错误ID:%s\n',ME.identifier)fprintf('错误信息:%s\n',ME.message)fprintf('发生位置:%s 第%d行\n',ME.stack(1).name,ME.stack(1).line)end自定义错误和警告:
functionresult=safeDivide(a,b)ifb==0error('safeDivide:zeroDenominator','除数不能为零')endifabs(b)<1e-10warning('safeDivide:smallDenominator','除数接近零,结果可能不可靠')endresult=a/b;enderror会终止执行并抛出异常,warning只显示警告信息但继续执行。
什么时候用循环,什么时候用向量化
这是MATLAB学习的一个重要思维转变:
适合向量化(不用循环):
% 计算1到1000每个数的正弦值x=1:1000;y=sin(x);% 直接作用于整个向量,内部是高度优化的C代码% 找所有大于均值的元素data=randn(1,10000);above_mean=data(data>mean(data));% 对矩阵每行求和A=rand(100,50);row_sums=sum(A,2);% 按行求和,返回100x1向量不得不用循环的情况:
% 有前后依赖关系的递推计算x(1)=1;fori=2:100x(i)=x(i-1)*2+sin(i);% 依赖上一步结果end% 每次迭代的输入由上次迭代结果决定whilenot_converged x_new=update(x_old);% 迭代格式ifnorm(x_new-x_old)<tolbreakendx_old=x_new;end% 需要中途终止的循环fori=1:n result=compute(i);ifisnan(result)||result>thresholdbreakendend核心判断:数据处理用向量化,迭代算法和递推用循环。