# 前言

推荐官方提供的入门手册: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(:))、最大值就很香了。

# 四则运算

  1. A\B B/A (当A为方阵)等价于A^(-1)*B
  2. (对应元素)点乘、点除、幂:A.*AA./BA.\BA.^BA.^4

# 矩阵变换

  1. 转置:A'
  2. 上、下三角矩阵:triltriu
  3. 逆矩阵:inv(a)
  4. 取对角变为列向量:diag(A)
  5. 取对角矩阵:diag(diag(A))
  6. 左右翻转:fliplr(A)
  7. 将增广矩阵化为简化为阶梯形:rrefA)
  8. 特征值、特征向量:[V,D] = eig(A)

V1DV=AV^{-1} \cdot D \cdot V = A

DD的对角线是特征值.

  1. 范数 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.ma=2; fun(1);fun.mfunction 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

支持 continuebreak

# if

MATLAB 代码实属随和,判断条件部分,加不加括号都可以。

if (a == 1)
    disp('1');
elseif a == 2
    sprintf("hehe");
else
    disp('233');
end
# 逻辑运算符

==&|~~=><>=<=

用逻辑运算符比较时,矩阵对应元素比较,得到的结果也是矩阵。

对于 if while 是否执行的判定,实际上是判断矩阵的每个元素是否都是非零值。这一点在判断等于、大于小于的时候挺合理,但是在某些情况下会有问题:

  1. 比较的两个矩阵维度不同时,会运行报错
  2. 判断不等时容易出错:
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

调用时,使用 hellotest(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

返回值可以为多参数。可以用 narginnargout 检测输入、输出参数个数。
函数中支持 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 符号编程

syms 英文文档 (opens new window)

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);