MATLAB 学习笔记——4. 脚本与函数
.M 文件MATLAB 的 .m 文件主要分成两类: 脚本文件,不接受输入参数,它们处理工作区中的变量和数据。 函数文件,可接受输入参数,并且可以有返回值,内部变量是函数的局部变量。 除此之外,还有面向对象编程所涉及的类文件,这里暂时不做讨论。 MATLAB 对于 .m 文件的文件名有一些特殊要求: 文件名允许由字母、数字、下划线(_)和点(.)组成,注意不包括 - 和空格; 文件名必须以字母开头; 文件名区分大小写。 实际就是要求文件名也是一个合法的标识符,因为在 MATLAB 中运行一个脚本就是通过在终端输入脚本文件名来完成的。 较新版本的 MATLAB 提供了后缀为 .mlx 的实时脚本/函数文件,大致就是对 Jupyter Notebook 的模仿,但是用起来并没有后者那么好用,各种操作不够自然。由于 .mlx 文件不是纯文本文件,如果我们需要在 .m 文件和 .mlx 文件之间转换,必须通过 MATLAB 专门提供的工具进行转换,vscode 等编辑器也并不支持 .mlx 文件的显示。 脚本文件载入脚本文件会依次执行所有命令,在重复执行大量命令...
MATLAB 学习笔记——3. 流程控制与输入输出
流程控制在划分控制结构所对应的代码块时,编程语言通常采用如下三种做法: 基于大括号 {}:例如 C/C++,Java 基于 end 标记:例如 FORTRAN,MATLAB 基于缩进:Python MATLAB 受到 FORTRAN 的影响很大,也采用基于 end 的代码块标记,并不使用大括号 {} 来划分代码结构。 if 条件语句提供例子即可 123if x>1 x=1;end 12345if x>1 y=x;else y=1;end 1234567if x>10 y=x;elseif x>0 y=1;else y=0end 在 if 语句中通常需要使用与或非运算(不建议用 & 和 |) 123if cond1 && cond2 % ...end 123if cond1 || cond2 % ...end 123if ~cond % ...end switch 条件语句MATLAB 支持基本的 switch 语句,我们可以判断表达式的值以进入不同的分支,不需...
MATLAB 学习笔记——2. 矩阵
概述MATLAB 对于矩阵的支持非常好,以矩阵运算为代表的基本运算功能一直是 MATLAB 引以为自豪的核心与基础。我们可以把向量和矩阵都视作矩阵进行统一的操作。在下文中我们默认讨论二维矩阵,但 MATLAB 支持多维矩阵。行向量即行数为 1 的矩阵,列向量即列数为 1 的矩阵。 在内存中,MATLAB 使用列主序进行连续存储,与 Fortran 相同,与 C 语言是反的。在下标的使用中,MATLAB 默认下标从 1 开始,与 Fortran 相同,与 C 语言等绝大部分编程语言都不同。 矩阵的尺寸信息可以通过下面的语句获取: size(A) 行数和列数,返回一个1x2的行向量; size(A,1) 行数; size(A,2) 列数。 还有如下函数: numel(A) 可以获取(任意维度数组)所有元素个数; length(A) 可以获取向量的长度(也就是元素个数),但是扩展到高维数组的行为是非常反直觉的——返回最大维数长度,相当于max(size(A))。 注意: MATLAB 对于矩阵的支持是非常彻底的,甚至标量都是被视作 1 行 1 列的矩阵。 MATLAB 的很多...
MATLAB 学习笔记——1. 基础
基本语法注释:MATLAB 使用百分号%进行单行注释,使用%{...%}进行多行注释(不常见),使用%%开头的内容不仅是注释,而且会被视作节标题。(在字符数组中%仍然被用于占位符) 分号:; MATLAB 并不需要强制使用分号作为语句的结尾,以空格或回车结尾即可。不使用分号结尾时会把计算结果显示出来,使用分号结尾则会抑制计算结果的显示。 续行符:在第一行的结尾使用...可以把命令接续到第二行。(如果直接把...接在数字后面会报错,可以加空格) 命令补全:Tab 键。 对命令行窗口清屏:clc MATLAB 几乎所有数据都是矩阵:行向量是行数为 1 的矩阵,数是行数列数均为 1 的矩阵,甚至一个无效命令,它的返回值[]都是一个 0 行 0 列的空矩阵。 和其他现代编程语言类似: MATLAB 对大小写敏感,这与它所参考的 FORTRAN 不同。 MATLAB 对表达式中的空格不敏感,表达式中的空格通常被忽略。(只有bash这些异类才会对空格敏感) 和大部分现代编程语言不同: MATLAB 的索引都从 1 开始,而不是更常见的从 0 开始; 在 MATLAB 中,不等号是~=,...
Linux ssh 笔记
整理记录 SSH 的常见概念、认证方式与典型用法。 基本使用(1)ssh 最基本的用途就是登录远程服务器 1ssh user@hostname 其中: user 是登录用户名 hostname 是主机名,它可以是域名,也可以是某个具体的 IP 地址或局域网内部的主机名。 可以缺省用户名,此时将使用本地用户名作为远程服务器的登录用户名。 1ssh hostname 用户名也可以通过 -l 参数指定,这样用户名和主机名就不用写在一起了,在脚本中可能更方便 1ssh -l username hostname ssh 默认连接远程服务器的 22 端口。使用 -p 参数也可以指定其他端口;前提是远程 SSH 服务端确实监听在该端口上。 1ssh -p 8821 foo.com ssh 在连接到远程服务器后会进行验证:如果第一次通过 ssh 连接某一台服务器,命令行会显示一段文字,表示不认识这台机器,提醒用户确认是否需要连接 123The authenticity of host 'foo.com (192.168.121.111)' can't ...
Cpp 进阶笔记——2. 引用折叠、万能引用和完美转发
引用折叠规则引入了右值引用后,我们必须要处理右值引用所带来的一系列类型推导问题,因为C++不允许“引用的引用”这种类型存在,对于涉及两个连续出现的引用修饰词的类型推导时,定义了如下的引用折叠规则: 1234& + & -> && + && -> &&& + & -> &&& + && -> && 简而言之,就是左值引用短路右值引用:只有连续两个右值引用遇到一起,才会推导出右值引用,只要出现左值引用,就会推导出左值引用。这套规则主要在模板类型匹配和auto中使用。 C++希望坚持“引用就是别名”的原则,并且不允许直接定义引用的引用(还是可以间接实现的),这与指针的指针可以任意级嵌套是不同的。虽然左值引用主要就是靠指针实现,但那其实只是编译器选择的一种实现方案,并不是语法直接规定的。 模板函数实验我们考虑如下五类的模板函数进行实验,对它们的类型推导可谓是各不相同 1234567891011121314template &...
Cpp 进阶笔记——1. 右值引用与移动语义
我们关注现代C++中比较难以理解的概念:右值引用,移动语义,完美转发等,这些概念都是C++11之后才提出的,目的是进一步压榨程序的运行期效率,避免某些非必要的临时变量的拷贝构造和析构过程。这些语法是完全针对底层实现的,并不是针对于上层的语义优化,不是为了让程序变得更易读的语法糖。 左值和右值 (1)在C++中,表达式由一个或多个运算对象通过运算符组成,对表达式求值得到一个结果。字面量和变量是最简单的表达式,它们的结果就是字面量和变量的值。一个表达式至少具有如下两个属性: 类型:描述计算产生的值的静态类型 值类别:描述值是如何产生的,以及表达式的行为如何被影响 从语法上检查一个表达式能否给另一个表达式赋值,既需要判断类型之间能否进行转换,还需要判断值类别是否满足要求。在本文中我们不讨论类型问题,重点关注表达式的值类别。 在C语言和C++的早期语法中,值类别被简单分为左值和右值。简单地说,在一个合法的赋值语句中,等号左边的就是左值表达式,等号右边的就是右值表达式。在赋值过程中,右值表达式不会被改变,而左值表达式会因为赋值而改变。 1lvalue = rvalue; 左值和右值的...
Cpp 函数 API 设计
整理一下关于现代化的C++函数API设计的笔记,我们关注如何设计可读性好,使用安全的函数接口:设计函数接口的名称、参数类型、返回值等。 部分参考现代化的 API 设计指南 基本原则函数API的设计要满足如下的原则: 向用户传达清晰的语义,保证接口的可读性,避免因为语义不清晰导致用户的错误调用; 向编译器提供更多的信息,尽可能让错误的使用在编译时就被发现,由编译器发出警告或直接导致编译失败。 如果需要考虑: 跨编译器使用:混用不同编译器编译得到的库 跨语言使用:混用C语言和C++,或者将当前的C++库提供给其它语言调用(例如Python) 那么必须保证使用extern "C"提供C语言形式的接口。 函数和参数名称保持统一的函数名称风格:大驼峰或使用下划线,例如 123void get_date();void SetDate(); 函数名称通常使用动词加名称的形式,避免提供名称相似的函数接口,尤其是不要出现仅有大小写不同的函数接口。 对于参数的命名,遵循统一的规则即可,但是最好保留具体的语义,例如 1void SetDate(int year, in...
Cpp const* 关键词
C++关于常量提供了很多形如const*的关键词,在语义上涉及到运行期的常量约束和编译期的初始化这两个性质,这几个关键词的含义相当类似,有必要整理一下。 概述C++陆续引入了下面几个关键词: 第一代:const,从C语言中继承,在C++中一直都存在 第二代:constexpr,C++11引入 第三代:consteval和constinit,C++20引入 其中const继承自C语言的,其它几个则是C++独有的关键词,关于它们的用法仍然在迅速发展中,因为C++很想发掘出编译期计算的巨大潜力,但是历史包袱导致它一直干不好。 我们重点关注的是编译期计算,可以使用如下的两种方式来检查: 第一种方式利用在数组的定义,数组长度需要提供一个编译期的值,因为普通变量的初始化始终发生在运行期,直接使用一个变量作为数组长度是无法通过编译的。(有时确实可以通过编译,但那属于编译器的扩展功能,不是语法标准规定的用法) 第二种方式是使用C++专门提供的static_assert关键字来进行静态断言(将其称为编译期断言更合适,与C语言中assert所代表的运行期断言相对应),它会在编译期判定一个编译期...
C语言 定义和声明
定义和声明在 C 语言中,定义和声明是两个极其容易混淆的概念,定义是明确告诉编译器完整的信息,而声明只是给编译器打一个“白条”,具有如下特点: 声明对应的定义可以暂时并不提供,定义可能在源文件的后面,也可能在其它源文件或编译单元中。 前置声明可以让我们在正式定义之前就使用它,这对于解决循环依赖是必要的。 同样的声明可以重复多次提供,但是定义至多只有一次,否则会报错符号重定义。 如果编译器在链接所有编译单元时,如果需要使用某个具体实现,但是没有找到声明对应的定义——对应的“白条”没有被兑现,就会报错符号未定义。 如果只是提供了一个声明,但是没有实际使用它,那么编译器会直接将其忽略掉,此时即使没有提供对应的定义也是允许的,因为压根不需要。 我们主要考虑变量的声明/定义和函数的声明/定义: 变量: 变量声明:变量声明只是告诉编译器变量的名称和类型,但不分配内存。 变量定义:变量定义是在编译过程中分配内存和值并为变量指定名称的操作。 函数: 函数声明:函数声明(也称为函数原型)包含函数的返回类型、参数列表和函数名,但没有函数体。它只是告诉编译器有这个函数存在...
