给自学游戏和图形开发者的数学符号指南
之前补数学知识的时候,看到数学符号就头大,前几天在 Github 上发现了这篇文章,尝试翻译了一下,现在全文贴到这里。
由于原文会持续更新,可以到我的 github 上 watch 这个项目,我会随原文进行更新。
https://github.com/nshen/math-as-code/blob/master/README-zh.md
正文:
math-as-code
译注:译者英文与数学水平都非常有限,尝试翻译,如有错误请指正。英文原版 在此。
这是一份通过对比数学符号和 JavaScript 代码来帮助开发者更容易了解数学符号的参考。
动机:学术论文可能会吓着自学游戏和图形的程序猿:)
这个指南还没有完成。如果你发现错误或者想要贡献,请open a ticket或发一个 PR。
注意: 简洁起见,有些代码示例使用了npm 包。你可以到他们的 GitHub repos 来查看实现的详细情况。
前言
数学符号可以表示不同的意思,这取决于作者,上下文和所学习的领域(线性代数,集合理论,等等)。这份指南也许不会涵盖符号的所有用法。在某些情况,会引用一些真实材料(博客文章,出版物等等)来演示某个符号的实际用法。
更完整的列表,请看Wikipedia - List of Mathematical Symbols。
简单起见,这里许多的代码示例都操作浮点数值,并不是数字健壮的(numerically robust)。为什么这会是一个问题的更多细节请看Robust Arithmetic Notes 作者是 Mikola Lysenko。
目录
- 变量名约定
- 等号
=
≈
≠
:=
- 平方根与复数
√
i
- 点 & 叉
·
×
∘
- 西格玛
Σ
- 求和 - 大写 Pi
Π
- 序列的积 - 管道
||
- 帽子
â
- 单位向量 - "属于"
∈
∉
- 常见数字集
ℝ
ℤ
ℚ
ℕ
- 函数
ƒ
- 撇号
′
- 向下取整和向上取整(floor & ceiling)
⌊
⌉
- 箭头
- 逻辑非
¬
~
!
- 区间(intervals)
- 更多...
变量名约定
有很多命名约定取决于上下文和所学领域,他们并不太一致。然而在一些文献中你会发现变量名遵循一些模式,例如:
- s - 斜体小写字母用做标量 (例如一个数字)
- x - 粗体小写字母用做向量 (例如一个 2D 点)
- A - 粗体大写字母用做矩阵 (例如一个 3D 变换)
- θ - 斜体小写希腊字母用做常量和特殊变量 (例如 欧拉角 θ, theta)
本指南也基于这个格式。
等号
有很多符号很像等号 =
。这里有些常见的例子:
=
表示相等 (值相同)≠
表示不相等 (值不同)≈
表示约等于 (π ≈ 3.14159
):=
表示定义 (A 被定义为 B)
在 JavaScript 中:
你也许看过 :=
, =:
和 =
符号用来表示 定义。1
例如,下边定义 x 为 2kj 的别名。
在 JavaScript 中,我们用 var
来 定义 变量和提供别名:
然而,这里的 x 值是可变的,仅是当时的一个快照。在某些有预处理器语言中的 #define
语句才比较接近于数学中的 定义。
在 JavaScript (ES6) 中,更精确的 定义 ,应该有点类似这样:
与此不同的是,下边这句表示的是相等:
上边的等式也可以解释为一个 断言:
平方根与复数
一个平方根运算是这种形式:
在编程语言中我们使用 sqrt
函数, 像这样:
复数是 形式的表达式, 其中 是实数部分, 是虚数部分。 虚数 的定义为:
.
JavaScript 没有内置复数的功能,但有一些库支持复数算法。例如, mathjs:
这个库还支持字符串表达式求值, 所以上边的可以写为:
其他实现:
点 & 叉
点 ·
和叉 ×
符号根据上下文的不同有不同的用法。
他们可能看上去很明显,但在进入下一部分之前,理解他们之间微妙的不同是非常重要的。
标量乘法
两个符号都可以表示简单的标量之间的乘法。下边的写法意思相同:
在编程语言中,我们倾向用星号表示相乘:
通常,使用乘法符号只是为了避免意义模糊(例如两个数字之间的)。这里,我们可以完全省略:
如果这些变量表示的是标量,则代码应该这样写:
向量乘法
表示向量和标量之间相乘,或两向量的逐元素相乘(element-wise multiplication),我们不用点 ·
或叉 ×
符号。 这些符号在线性代数中有不同的意思,后边讨论。
让我们用之前的例子,但用在向量上。对于向量的逐元素相乘(element-wise vector multiplication)来说,你可能会看到用一个空心点来表示 Hadamard product。2
某些时候,作者可能会显式定义一个不同的符号,例如圆中点 ⊙
或实心圈 ●
。3
这是对应的代码,使用数组 [x, y]
来表示 2D 向量。
multiply
和 multiplyScalar
函数应该这样:
同样的,矩阵相乘也不用 ·
或 ×
符号。 矩阵乘法会在后边章节提到.
点乘
点符号 ·
可用来表示两向量之间的 点乘 。 由于其值是一个标量,通常被叫做 标量积(scalar product) 。
这在线性代数和 3D 向量中是非常常见的,代码类似这样:
结果为 0
告诉我们两向量互相垂直. 这是 3 元素向量的 点乘
函数:
叉乘
叉乘符号 ×
可以用来表示两向量的 叉乘。
在代码中,应该是这样:
这里得到结果为 [ 0, 0, -1 ]
,这个向量同时垂直于 k 和 j 。
我们的叉乘 cross
函数:
向量乘法,叉乘,点乘的其他实现:
西格玛(sigma)
大写希腊字母 Σ
(Sigma) 用来表示 总和 Summation。 换句话说就是对一些数字求和。
这里, i=1
是说从 1
西格玛上边的数字100
为止。这些分别为上下边界。 "E" 右边的 i 告诉我们求和的是什么。代码:
sum
的结果为 5050
。
提示: 对于整数,这个特殊形式可以优化为:
这里有另一个例子,这里的 i ,或 “想要求和的东西” 是不同的:
代码:
sum
的结果为 10200
。
这个符号可被嵌套,非常像嵌套一个 for
循环。 你应该先求和最右边的西格玛, 除非作者加入括号改变了顺序。然而下边的例子,由于我们处理有限的和,顺序就不重要了。
代码:
这里,sum
值为 135
。
大写 Pi
大写 Pi 或 “大 Pi” 与 西格玛 非常接近, 不同的是我们用乘法取得一系列数字的乘积。
看下边:
代码应该类似这样:
value
结果应得到 720
。
管道(pipes)
管道符号,就是 竖线(bars),根据上下文不同,可以表示不同意思。下边的是 3 种常见用途 绝对值, 欧几里得模, 和 行列式。
这 3 种特性都是描述对象的 长度(length) 。
绝对值
对于数字 x, |x|
表示 x 的绝对值。代码为:
欧几里得模(Euclidean norm)
对于向量 v, ‖v‖
是 v 的欧几里得模(Euclidean norm) 。也叫做向量的 "量级(magnitude)" 或 "长度(length)" 。
通常用双竖线表示来避免与绝对值 符号混淆,但有些时候也会看见单竖线。
这里的例子用数组 [x, y, z]
来表示一个 3D 向量。
length
函数:
其他实现:
- magnitude - n-dimensional
- gl-vec2/length - 2D vector
- gl-vec3/length - 3D vector
行列式
对于一个矩阵 A, |A|
表示矩阵 A 的行列式(determinant)。
这是一个计算 2x2 矩阵行列式的例子,矩阵用一个 column-major 格式的扁平数数组表示。
实现:
- gl-mat4/determinant - 也可以看 gl-mat3 和 gl-mat2
- ndarray-determinant
- glsl-determinant
- robust-determinant
- robust-determinant-2 和 robust-determinant-3,专门 2x2 和 3x3 的矩阵
帽子
在几何里,字母上的 “帽子” 符号用来表示一个单位向量。例如,这是向量 a 的单位向量。
在笛卡尔空间中,单位向量的长度为 1。意思是向量的每个部分都在 -1.0 到 1.0 之间。这里我们 归一化(normalize) 一个 3D 向量为单位向量。
这是 归一化(normalize)
函数,接收一个 3D 向量参数:
其他实现:
- gl-vec3/normalize 和 gl-vec2/normalize
- vectors/normalize-nd (n-dimensional)
属于
集合理论中,“属于”符号 ∈
和 ∋
可以被用来描述某物是否为集合中的一个元素。例如:
这里我们有一个数字集 A { 3, 9, 14 }
而且我们说 3
是“属于”这个集合的。
在 ES5 种一个简单的实现应该这样:
然而,可以用只能保存唯一值的Set
,这样更精确。这是 ES6 的一个特性。
反向的 ∋
意义相同,只是顺序改变:
你可以使用 "不属于" 符号 ∉
和 ∌
像这样:
常见数字集
你可能在一些公式中看见一些大黑板粗体字。他们一般是用来描述集合的。
例如,我们可以描述 k 是属于 ℝ
集的一个元素。
下边列出一些常见集和他们的符号。
ℝ
实数(real numbers)
大 ℝ
描述 实数(real numbers) 的集合。他们包括整数,有理数,无理数。
JavaScript 认为整数和浮点数为相同类型,所以下边将是一个 k ∈ ℝ 的简单测试:
注意: 实数也是 有限数(finite),非无限的(not infinite)
ℚ
有理数(rational numbers)
有理数是可以被表示为分数,或 比率(类似⅗
)的实数。有理数不能以 0 作分母。
这意味着所有的整数都是有理数,因为可以看成分母为 1。
换句话说无理数就是不能表示为比率的数,例如 π (PI)。
ℤ
整数(integers)
一个整数,是没有小数部分的实数。可为正也可以为负。
在 JavaScript 中的简单测试应该这样:
ℕ
自然数(natural numbers)
自然数是正整数或非负整数。取决于所学领域和上下文,集合中可能包含也可能不包含 0,所以可以是下边任意一种集合。
前者在计算机科学中更常见,例如:
ℂ
复数
复数是实数域虚数的组合,被视为 2D 平面上的一个坐标。更详细的信息请看A Visual, Intuitive Guide to Imaginary Numbers。
函数
函数 是数学的基本特性,其概念很容易转换成代码。
函数把输入输出值联系起来。例如下边是一个函数:
我们可以给函数一个 名字 。一般来说我们用 ƒ
来描述一个函数,但也可以命名为 A(x)
或其他什么。
在代码中,我们可以给函数命名为 square
写出来应该类似这样:
有时函数没有名字,而是直接写出输出值。
在上边的例子中,x 是输入值,y 是输出值,他们是平方的关系。
像编程语言一样,函数也可以有多个参数。他们在数学中被称为 arguments,并且函数接受的参数数量被称为函数的 arity 。
代码:
分段函数
有些函数根据输入值 x 的不同会有不同的关系。
下边的函数 f 根据不同的输入值选择两个不同的“子函数”。
abc def
这非常接近于代码中的if
/ else
。右边的条件经常被写为**"for x < 0"** 或 "if x = 0"。如果条件为 true,就使用其左边的函数。
在分段函数中,"otherwise" 和 "elsewhere" 类似于代码中的 else
。
通用函数
有些函数名在数学中是普遍存在的。在一个程序员的角度看,这些应该类似于编程语言中的“内置”函数(就像 JavaScript 中的 parseInt
)。
一个例子就是 sgn 函数。这是 正负号 函数,或者叫 符号 函数。让我们用分段函数来描述它:
代码中,应该这样:
此函数作为独立的 module 在这里signum。
其他类似函数的例子还有: sin, cos, tan。
函数符号
在某些著作中,函数可以被更明确的符号定义。例如,让我们回到之前提到的 square
函数。
也可以写为以下形式:
带尾巴的箭头通常意思为“映射到”,如,将 x 映射到 x2
有时,不是很常见,这个符号也用来描述函数的 domain 和 codomain。对 ƒ 更正式的定义可以写为:
函数的 domain 和 codomain 分别跟他的 input 和 output 类型有点像。这里有另一个例子,使用了我们之前输出整数的 sgn 函数。
这里的箭头(没有尾巴)用来映射一个 集合 到另一个。
在 JavaScript 和其他动态类型语言中,你也许会用文档 和/或 运行时检查来解释和验证函数的输入/输出。例子:
有些工具例如flowtype尝试将静态类型带入到 JavaScript 中。
其他语言,例如 Java,允许真正的方法重载(overloading),它们基于函数输入输出的静态类型。这更接近于数学领域:使用不同 domain 的两个函数是不同的。
撇号(prime)
撇号 (′
) 通常用在变量名上,用来描述某物很类似,而不用另起个名来描述它。也可以描述经过一些变换后的“下一个值”。
例如,如果我们有一个 2D 点 (x, y) ,然后旋转它,你会把旋转后的点命名为*(x′, y′)*。 或者将矩阵 M 的 转置矩阵 命名为 M′。
在代码中,我们通常的分配一个描述更详细的变量名,例如transformedPosition
。
作为数学函数,撇号通常描述为函数的 衍生(derivative) 函数。衍生物会在未来的章节解释。我们来看一个之前的函数:
它的衍生物函数(derivative)可以写为一个带撇号′
的函数:
代码:
多个撇号可以用来表示第二个衍生函数(derivative) ƒ′′ 或 第三个衍生函数(derivative)ƒ′′′ ,之后更高的数字,一般作者会用罗马数字 ƒIV 或上标数字 ƒ(n) 表示。
向下取整和向上取整(floor & ceiling)
⌊x⌋
和 ⌈x⌉
这种特殊的括号分别用来表示floor 和 ceil 函数。
代码:
当这两个符号混合⌊x⌉
,它通常表示一个取整到最近的整数的函数。
代码:
箭头
箭头通常用来表示函数符号。这里还有一些在其他领域中的用法可以看看。
实质蕴含(material implication)
⇒
和 →
优势被用作表示实质蕴涵(material implication)的逻辑。意思是如果 A 是 true,那么 B 也是 true。
解释为代码应该为:
箭头可以是左右任何方向 ⇐
⇒
,也可以双向⇔
。当 A ⇒ B 并且 B ⇒ A,就是他们是相等的:
等式(equality)
在数学中, <
>
≤
和 ≥
与代码中的使用方法一样:分别为 小于, 大于, 小于等于 和 大于等于。
偶尔会看到在这些符号上加了一条斜线,来表示 不,比如, k 不 "大于" j.
≪
和 ≫
通常用来表示 明显(significant) 不相等。这是说 k 是有数量级(order of magnitude)的大于 j。
在数学中,数量级(order of magnitude) 是相当明确的;不只是“相当大的不同”而已。上边的一个简单例子:
下边是我们的 orderOfMagnitude
函数,使用了Math.trunc (ES6)。
这里是在 ES5 下使用math-trunc 的 polyfill。
与(conjunction) & 或(disjunction)
另一种箭头在逻辑中的使用是与(conjunction)∧
和 或(disjunction) ∨
。他们分别类似于程序员的 AND
和 OR
操作。
下边展示了与(conjunction)∧
, 逻辑中的AND
.
在 JavaScript 中,我们使用 &&
假设 k 是一个自然数,那么这个逻辑意味着 k 等于 3:
由于双边都相等 ⇔
,所以也说明下边成立:
下箭头 ∨
是逻辑或(disjunction),就像 OR 操作符一样。
代码:
逻辑非(logical negation)
有时候,¬
, ~
和 !
符号都用来表示逻辑 NOT
。例如,只有在 A 为 false 的时候,¬A 为 true。
这里是一个使用 not 符号简单的例子:
翻译成代码的例子:
注意: 根据上下文的不同,波浪线 ~
可以有很多种不同的意思。例如,行等价(row equivalence)(矩阵理论)或相同数量级(same order of magnitude) (在等式(equality)章节讨论过)。
区间(intervals)
有时函数会处理被一些值限定范围的实数,这样的约束可以用*区间(interval)*来表示。
例如我们可以表示 0 和 1 之间的数,让他们包含或不包含 0 和 1:
- 不包含 0 或 1:
- 包含 0 但不包含 1:
- 不包含 0 但包含 1:
- 包含 0 和 1:
例如我们指出一个点 x
在 3D 单位立方体中,我们可以说:
在代码中我们可以用两个元素大小的一维数组表示区间:
区间与集合运算结合符使用:
- 交集(intersection) e.g.
- 并集(union) e.g.
- 差集(difference) e.g. 还有
代码:
见:
更多...
喜欢这份指南?提出更多的特性的建议或给我们发 Pull Request!
贡献
关于怎样贡献详见 CONTRIBUTING.md。
License
MIT, 详见 LICENSE.md。