# 前言
推荐官方提供的入门手册:MATLAB 快速入门 (opens new window)
help xxx
用于查看命令,doc xxx
直接调用文档- 单引号
'
和双引号"
一样,推荐单引号。用单引号转义单引号,如disp('f''(x)')
输出f(x)
- 用分号
;
结束语句,以屏蔽输出。 - 等于
==
,不等~=
,取反~
,与或是&&
和||
。 - 行末
...
表示下一行接着这行。
# 构造矩阵
>> a = [2 2; 5 8]
2 2
5 8
>> 1:2:10 % 1 3 5 7 9
>> 1:5 % 1 2 3 4 5
>> linspace(1,2,10)
% (start, end, length)
% 1.0000 1.1111 1.2222 1.3333 1.4444 1.5556 1.6667 1.7778 1.8889 2.0000
1:5
语法是闭区间,和 Python 左闭右开不一样。
# 构造常见矩阵
>> rand(2)
0.8147 0.0975
0.9058 0.2785
>> eye(5)
>> ones(3)
>> zeros(3) % 可用于初始化
神奇的是, zeros
一开始并没有占用内存,而 ones
就会占用。
另有 normrnd(mu, sigma)
按正态分布生成随机函数,sparse
构造稀疏矩阵。
# 矩阵的合并、取行列
>> a = [2 2; 5 8]
>> A=[a,a]
>> A=[a;a]
>> a = [2 2; 5 8]
>> a(1, 2) % 第一行第二列,2
>> a(1,1:2) % 2 2
>> a(1,:) % 2 2
>> a([1,2],:) % 2 2; 5 8
>> a(end-1:end,:) %% 取倒数两列,倒数第一行
>> A(1,:)=[] %% 删除第一行,a = [5 8]
可以把矩阵变为线性矩阵:
A = [1 2 3; 6 5 4];
A(:); %返回 [1 6 2 5 3 4]'
看起来没什么用,但是求矩阵元素和 sum(A(:))
、最大值就很香了。
# 四则运算
A\B
B/A
(当A为方阵)等价于A^(-1)*B- (对应元素)点乘、点除、幂:
A.*A
,A./B
,A.\B
,A.^B
,A.^4
# 矩阵变换
- 转置:
A'
- 上、下三角矩阵:
tril
,triu
- 逆矩阵:
inv(a)
- 取对角变为列向量:
diag(A)
- 取对角矩阵:
diag(diag(A))
- 左右翻转:
fliplr(A)
- 将增广矩阵化为简化为阶梯形:
rrefA)
- 特征值、特征向量:
[V,D] = eig(A)
即的对角线是特征值.
- 范数
norm()
# 编程语法
# 数据类型
double
, char
, sym
, struct
, cell
数组以1开头(毕竟万物皆矩阵)
# 取整函数
ceil
向上取整、floor
向下取整、round
四舍五入、fix
向零取整。
然而 C++ 用户还是喜欢使用 int32
# 强制转换
c = char(49)
a = double('1')
# 查询数据类型
class(A)
% 返回数据类型名字的字符串khx
# cell 数组
各元素可为不同类型tql
a=cell{2,3}
a{4} = 'str'
a{1,2} = 123
class(a{4}) % == 'str'
class(a(4)) % == 'cell',注意区别
感觉有点鸡肋,但是 strsplit
能用。
# 全局变量
MATLAB 脚本执行的时候,其变量默认是既不跨文件,也不跨函数的,只是在命令行中调用脚本,其变量会保留在命令行中。
如在 test.m
中 a=2; fun(1);
(fun.m
为 function y=fun(x); a=1;
)以后,a
的值为 2。
如果需要全局变量,在声明和定义的部分都要写 global a;
。
修改上述脚本得到:
global a;
a=2;
fun(1);
disp(a);
function y=fun(x)
a=1;
end
输出 1。
# 输入输出
score=input('请输入您的成绩:') %输入MATLAB表达式
name=input('请输入您的姓名:','s') %输入姓名
disp(a) 显示数组内容
fprintf('%6d', score)
str=sprintf('%6d',score) %不能输出
转义字符:单引号'
貌似字符串的单双引号可以混用。
文件输入输出件另一篇博客。
# 控制流程
# for
for a = 1:10 % for a = [array]
string('njjnb')
end
支持 continue
和 break
。
# if
MATLAB 代码实属随和,判断条件部分,加不加括号都可以。
if (a == 1)
disp('1');
elseif a == 2
sprintf("hehe");
else
disp('233');
end
# 逻辑运算符
==
,&
,|
,~
,~=
,>
,<
、>=
、<=
用逻辑运算符比较时,矩阵对应元素比较,得到的结果也是矩阵。
对于 if
while
是否执行的判定,实际上是判断矩阵的每个元素是否都是非零值。这一点在判断等于、大于小于的时候挺合理,但是在某些情况下会有问题:
- 比较的两个矩阵维度不同时,会运行报错
- 判断不等时容易出错:
a = [1 2 3];
b = [2 3 3];
if (a ~= b)
disp('not equal')
end
上面的代码不会输出 not equal
。原因是 a~=b
的结果矩阵中,第三个元素是 1,是非零值。将代码改写为 ~(a == b)
会有同样的问题。
解决方案是,使用 ~isequal(a, b)
。他能比较两个矩阵是否相同,并给出一个逻辑值 1
/0
。也可以对不同维数的矩阵给出 0
而不是报错。
a = [1 2 3];
b = [2 3 3];
if (~isequal(a,b))
disp('not equal')
end
输出 not equal
。
# switch
switch name(1)
case {'a','b','c','d','e','f','g','h'},
disp(['Hello,',name])
otherwise,
disp(['Welcome,',name])
end
# 函数
MATLAB 函数好多啊,容易被绕进去。那我就不按教程讲叭。
函数这个词,有两个含义:
- 一个是数学上的含义,指数(数组)到数(数组)的映射;
- 第二个是编程意义上的,传入一个或多个参数,按规定执行某些操作,然后返回一个或多个参数。
原生 C 语言作为一种编程语言,只有第二种,因此概念不会混淆;
而 MATLAB 作为一个数学计算软件+脚本编程软件,两种函数都要有, 于是初学者就混淆了。
MATLAB 的编程函数有两种:函数文件和子函数,具体区别放在后面。 MATLAB 的数学函数,网上都说有两种,分别是内联函数和匿名函数,但是我觉得要加上符号函数,一共三种。
在以后的版本中将会删除
inline
内联函数。请改用 匿名函数。
因此对内联函数不做介绍,仅提供官方文档 (opens new window)以查阅。
而匿名函数和符号函数呢,前者是可以代值运算的函数,后者是可以进行求导积分泰勒展开等等等等。
用比较形象的话来说,匿名函数就是 f(x)=x^2
,而符号函数是 y=x^2
。
- 匿名函数可以求
f(1)
、f(2)
等等,但是x
并不是一个已经声明的符号(或者说,自变量),它只起了占位的功能,代值的时候就会被替换。 - 而符号函数不能直接求
y(1)
,而且需要提前声明 x 是符号(sym x;
),但是它就可以进行求导等操作。 你可能会说,数学上,可以通过y=f(x)
相互转换吖。确实,二者是可以互相转换的。具体方法在后面提到。
# 函数文件和子函数
函数文件是把函数作为模块,可以被其他程序调用,是模块化编程很重要的一点。
而子函数是作为主函数的一部分,只能被主函数调用,不能被其他程序调用。
存储上,函数文件需要单文件存储。而子函数不用。
如果涉及到了子函数,该文件所有函数(主函数和子函数)都需要写 end
。
调用时,使用 hello
或 test(1, 2)
。
正常情况下,函数外的参数不能被使用,自变量也不能被修改。和 C 一样。
若想要使用全局变量,在声明和使用变量时,都需要加 global
关键字,
% hello.md
function ret = hello
disp('hello world');
ret = 1;
% test.m
function r=test(r1, r2)
r = r1 + r2 + get_r3();
end
function r3 = get_r3
r3 = 2;
end
返回值可以为多参数。可以用 nargin
和 nargout
检测输入、输出参数个数。
函数中支持 return
。
function [r, v]=myfun(x)
r=x.^2; %计算第1个输出参数
if nargout>=2,
v = 2*x; %计算第2个输出参数
end
# Function in Function
摘自:如何评价 MATLAB R2016b ? - winner245的回答 - 知乎 https://www.zhihu.com/question/50662537/answer/122451045
在 MATLAB R2016b 以后,还支持在函数里面写函数,并且对于输入和输出相同的函数(即原地调用),性能会有优化。
function main
tic, x = rand(1e8,1); toc
tic, y = notInplace(x); toc
tic, x = inplace(x); toc
isequal(x,y)
function y = notInplace(x)
y = 1.2*x;
function x = inplace(x)
x = 1.2*x;
# 匿名函数
官方文档 (opens new window)写的很好,就直接引用了。
匿名函数是一个
函数句柄
(function_handle
)(我注:第一句话官方翻译的太烂了,我重新写了一下;函数句柄可理解为指向某个函数的指针,它并不存储这个函数)。匿名函数可以接受输入并返回输出,就像标准函数一样。但是,它们可能只包含一个可执行语句。例如,创建用于计算平方数的匿名函数的句柄:
sqr = @(x) x.^2;
变量sqr
是一个函数句柄。@
运算符创建句柄,@
运算符后面的圆括号()
包括函数的输入参数。该匿名函数接受单个输入x
,并显式返回单个输出,即大小与包含平方值的x
相同的数组。通过将特定值 (5) 传递到函数句柄来计算该值的平方,与您将输入参数传递到标准函数一样。
a = sqr(5)
返回 25许多 MATLAB® 函数接受将函数句柄用作输入(我注:无需创建符号变量
syms
,直接调用即可不过貌似不多)。例如,通过将函数句柄传递到 integral 函数,计算 sqr 函数从 0 到 1 范围内的积分:
q = integral(@(x) x.^2,0,1);
可以对匿名函数嵌套:
g = @(c) (integral(@(x) (x.^2 + c*x + 1),0,1));
上述g(2) == 3
。可以使用不带参数或多个参数的匿名函数:
t = @() datestr(now); d = t()
匿名函数可以有多个返回值(本文作略,请查阅官方文档)。
@
还可以把一个程序函数变成一个函数句柄。
如,定义 function y=fun(x)
,就可以用 g(@fun,1)
跑遗传算法了。
匿名函数可以转化为符号函数:f=@(x)x^2; syms x; y=f(x);
符号函数可以转为匿名函数:syms x; y=x^2; f=matlabFunction(y);
# MATLAB 结构体
MATLAB 结构体在实际应用中用到的不多,但是作为程序员,还是简单叙述一下。
MATLAB 的结构体不需要定义,当有数据要放入结构体中时,就直接用 .
装进去即可。
s.a = 1;
s.b = {'A','B','C'}
% s = struct with fields:
% a: 1
% b: {'A' 'B' 'C'}
# MATLAB 自带函数
这都是查手册可以解决的事情。
我总结的可见 MATLAB 函数。
# 字符串与文件
# MATLAB 符号编程
见 MATLAB 符号编程。
# MATLAB 绘图
见 MATLAB 绘图。
# MATLAB显示
# 回显
不回显:使用分号 ;
回显:使用回车或逗号 ,
# 显示模式
# 分数模式
format rat %% 分数模式
format %% 小数模式
注意这里的分数仍然是近似解,只是将近似解化为了分数形式。如果需要完全精确的结果,请使用符号编程 或考虑使用其他数学软件如 Mathematica。
对于符号编程中的函数,由于其返回的是分数,可通过 double()
或 vpa()
函数将其转为小数,后者返回的同样是 sym
类型,但可以给出任意的精度(对,任意!)。
# 显示小数位数
format long %%小数位数更多
format short %%回到短模式
# 清屏、清变量
clc %% 清屏
clear
clear A B %% 清变量
# 暂停
pause %按任意键以继续
pause(0.5)
# MATLAB 和 MAT 文件
MAT 文件即是将 MATLAB 运行中存储在工作区的变量等从内存存储到文件,方便下次继续使用。(这比其他编程语言方便的多)
读取的方法就一行:
load data
# 稀疏矩阵
创建稀疏矩阵可以使用 sparse
函数:
% 设 M, N, K 为同维列矩阵,表示稀疏矩阵的 M(i) 行 N(i) 列是 K(i)
S = sparse(M, N, K);
% 将普通矩阵转为稀疏矩阵
S = sparse(A);
% 构造单位矩阵的稀疏矩阵
S = speye(10);
稀疏矩阵和其他矩阵一样,可以使用 S(a,b)
读取,+
-
*
/
^
运算,以及其他函数。
稀疏矩阵的特殊操作有:
% 用图像描述稀疏矩阵的非零元的分布
spy(S);
稀疏矩阵和普通矩阵的互相转化:
% S 为稀疏矩阵,M 为普通矩阵
S = sparse(M);
M = full(S);