Mata:Mata 表达式

Mata:Mata 表达式

这一章介绍了 Mata 中的表达式,很枯燥,我跳过了一些我觉得自己已经知道的部分。

更多的惊喜

大多数 Mata 语句都是表达式或者包含表达式,例如:

Stata
1
2
3
4
i = i + 2
r = (-b + sqrt(b^2 - 4 * a * c)) / (2 * a)
y = myfcn(x)
mysubroutine(a, b)

这些都是显而易见的例子,下面的例子可能会令你吃惊了:

Stata
1
2
3
4
5
6
fraction = (++i)/n
a = (b = sqrt(x^2 + y^2)) / sqrt(X^2 + Y^2)
ratio = (number = s1 + s2) / (denom = n1 + n2)
pos = (a > 0) + (b > 0) + (c > 0)
if(i)
while(abs(err = x^2 - 2) > 1e-12)

能理解这些表达式的含义么?不能理解的话听我细细道来:

  1. fraction = (++i)/n等价于
Stata
1
2
i = i + 1
fraction = i/n
  1. a = (b = sqrt(x^2 + y^2)) / sqrt(X^2 + Y^2)等价于
Stata
1
2
b = sqrt(x^2 + y^2)
a = b / sqrt(X^2 + Y^2)
  1. ratio = (number = s1 + s2) / (denom = n1 + n2)等价于
Stata
1
2
3
number = s1 + s2
denom = n1 + n2
ratio = number / denom
  1. pos = (a > 0) + (b > 0) + (c > 0)则是将 a、b 和 c 中的正数存储在 pos 中。

  2. if(i)等价于

Stata
1
if(i != 0) ...
  1. while(abs(err = x^2 - 2) > 1e-12)等价于
Stata
1
2
3
4
5
err = x^2 - 2
while(abs(err) > 1e-12){
...
err = x^2 - 2
}

这里还有一些表达式可能会让你感到吃惊:

Stata
1
2
3
4
5
6
7
8
if(!(a == b & c == d)) ...
if(!sum(A:==0))...
max = (a > b ? a : b)
divline = 55 * "-"
vec = 1..4
B = A'
X = A'A
Z = A # B
  1. 第一个表达式很容易理解;

  2. A:==0的结果会得到一个只含有 0 和 1 的矩阵,其中 1 表示 A 矩阵该位置上的元素为 0,而 1 表示 A 矩阵该位置上的元素不为 0。if(!sum(A:==0))就表示如果A矩阵全为非0元素

  3. max = (a > b ? a : b)表示如果a > bmax = a,否则max = b

  4. divline = 55 * "-"表示 55 个-

  5. vec = 1..4表示把行向量(1, 2, 3, 4)存储在 vec 中。

  6. 转置。

  7. 转置。

  8. #表示 Kronecker 积。

数值型和字符串型复合常量(literals)

数值型复合常量

下面的表示方法可能会令你吃惊:

Stata
1
2
3
4
5
6
2.213e+32
2.213E+32
1e–8
2.213d+32
2.213D+32
1d–8

这六种表示方法都是科学计数法。

所有的非缺失值小于缺失值,对于缺失值:

$$
. < .a < .b < … < .z
$$

比起下面的代码:

Stata
1
d = (f(x+1.0e-8) - f(x)) / 1.0e-8

我更建议你使用:

Stata
1
d = (f(x+1.0x-1a) - f(x)) / 1.0x-1a

你还不知道1.0x-1a的含义,但是你一定认为第一种代码更简单,但是如果你使用第一种代码,那你可能会产生一些舍入误差。换句话来说,如果你使用1.0e-8,你的计算结果将会只有一位小数的精度,然而如果你使用1.0x-1a,你的计算结果会有 8 位小数的精度。

下面将会对此进行解释。

Stata 和 Mata 提供了一种称为X notationbase-2 notation,许多编程者在需要使用较小的值时会使用下面的复合常量:

  • 1e-8
  • 1e-12
  • 1e-14

例如,他们可能会编写这样的代码:

Stata
1
2
if(abs(x - y) < 1e-14) ...
deriv = (f(x + 1e-8) - f(x)) / 1e-8

这样的代码有什么问题呢?1e-8,1e-12 和 1e-14 这些值不能被二进制的电脑很精确的表示。存储起来的并不是$10^{-8}$、$10^{-12}$和$10^{-14}$,而是与之近似的$10^{-8} + 5.17 \times 10^{-24}$、$10^{-12} + 5.86 \times 10^{-28}$和$10^{-14} + 7.88 \times 10^{-30}$。这种小的差异会导致潜在的数值不精确问题。

一个建议就是,当你需要小值的时候,你应该选择这些:$1 \times 2^{-26}$、$1 \times 2^{-40}$和$1 \times 2^{-46}$,因为这些值产生的误差较小。

X notation 和 E notation:

你可以用 X 格式写数字,也可以用 X 格式展示他们:

Stata
1
2
3
4
5
. di %21x 1e-13
+1.c25c268497682X-02c

. mata: printf("%21x\n", 1e-13)
+1.c25c268497682X-02c

1.c25c268497682X-02c的含义是:

$$
1.c25c268497682 \times 2^{-2c}
$$

这是 16 进制的,0, 1, 2, ..., 9, a, b, c, d, e, f,在 16 进制中,8/16 = 0.8,表示一半。1.c25c268497682 = 1 + 0.c25c268497682,由于 0.c > 0.8,所以这个数大概是 2,所以$1.c25c268497682 \times 2^{-2c}$大约是$2 \times 2^{-2c} = 2^{-2c+1} = 2^{-2b}$,在 X 表示法中,$2^{-2b}$被写作1.0x-2b

因此建议使用下面的值代替 1e-8,1e-12 和 1e-14:

1.0e-8 和 1.0x-1a 在计算deriv = (f(x + h) - f(x))/h中的误差比较:

不要使用 1e–8、1e–12 和 1e–16。使用 1.0x–1a、1.0x–28 和 1.0x–2e。

复数复合常量

The expression z > . returns true when z contains missing for both real and complex z.

当我们分配实数值给复数变量时,使用 Mata 的复数化函数C()函数:

x = C(.)
x = C(.a)
x = C(2)

为什么你要这么做呢,看看下面的例子你就明白了:

Stata
1
2
3
4
5
6
7
8
9
10
11
12
13
. mata:
------------------------------------------------- mata (type end to exit) ---
: sqrt(-2)
.

: sqrt(-2 + 0i)
1.41421356i

: sqrt(C(-2))
1.41421356i

: end
-----------------------------------------------------------------------------

运算符的优先级

记是肯定记不住的,该打括号的时候记得打括号。

增减运算符

矩阵填充运算符

  • a..b:行填充;
  • a::b:列填充。

例如,1..4 = (1, 2, 3, 4);1::4 = (1 \ 2 \ 3 \ 4)

分号运算符

比起不带分号的运算符,分号运算符表示分别的含义。

子矩阵

A[|1, 1 \ 3, 2|]表示矩阵 A 的一个子矩阵,这个子矩阵包含了 A 矩阵的(1, 1)号元素到(3, 2)号元素。

而对于向量,V[|2\4|]表示矩阵 V 的一个子矩阵,这个子矩阵包含了矩阵 V 的第 2 到第四个向量。

指针和地址操作符

运算 含义
NULL 空地址
p –> MBR 获取结构体或类成员 MBR
(*p).MBR 与 p –> MBR 的含义相同
*p 获取指向 p 的对象
&NAME 获取非函数对象 NAME 的地址
&NAME() 获取函数 NAME()的地址
&(expr) 获取 expr 结果存储的地址
&(NAME(…)) 获取函数 NAME(…)运算结果存储的地址。
# Mata

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×