程振兴 @czxa.top
截止今天,我已经在本博客上写了607.9k个字了!
在连玉君老师的帮助下终于找到了这本书的电子版,之前看的是从图书馆借的纸质版(当然也是我推荐图书馆购买的)。点击即可下载这本书:The_Mata_Book.pdf。
所以再帮连玉君老师做个广告:连玉君 | 简书
Mata程序的结构
一个程序就是一段代码块,下面是一些示例:
函数speed_of_light()
没有任何参数传入,返回一个值:1
2
3
4real scalar speed_of_light()
{
return(299792458 /* m/s */)
}
使用:1
2
3
4
5
6
7
8mata:
mata clear
real scalar speed_of_light()
{
return(299792458 /* m/s */)
}
speed_of_light()
end
函数show()
传入参数之后什么也不返回,但是会打印出来一些东西:1
2
3
4void show(real scalar a)
{
printf("a = %f\n", a)
}
使用:1
2
3
4
5
6
7
8mata:
mata clear
void show(real scalar a)
{
printf("a = %f\n", a)
}
show(12)
end
下面的函数n_choose_k()
和函数nfactorial_over_kfactorial()
则具有实际数据意义了,他们接收参数并返回结果。
1 | real scalar n_choose_k(real scalar n, real scalar k) |
正如上篇博客中已经说明的一样:
$$
\begin{align}
nfactorial\_over\_kfactorial(n, k) & = \frac{n!}{k!} \
n\_choose\_k(n, k) = C^k_n & = \frac{n!}{(n-k)!k!}
\end{align}
$$
相信从上面的示例中你已经发现了Mata程序的一般结构了,如果没有返回值,函数会被声明为void
。虽然你可以省略函数类型的声明,但是本书的作者不建议这么做,因为这会增加错误的概率和让程序编译的更慢。
程序体
在Mata中有九种语句:
- 条件语句:
1 | if (expr) ... else ... |
- 循环语句:
1 | for (expr; expr; expr) ... |
- Go-to语句(在翻译Fotran程序的时候非常有用):
1 | goto stmt |
- 退出与返回值语句:
1 | return and return(expr) |
- 赋值、子程序调用语句:
1 | expr |
表达式
在下一章我们将会更加深入的讲解表达式,一些常见的表达式示例:
1 | i = i + 1 |
还有一种你看起来不像表达式的表达式,但它就是表达式:返回void
的表达式。
需要注意的是,数学表达式和逻辑表达式虽然运算方法不一样,但是返回的结果的类型是一样的,这就意味着你可能把数学表达式和逻辑表达式一起使用。例如,考虑三个数值变量a、b和c,它们中有几个是负数?,答案就是(a < 0) + (b < 0) + (c < 0)。
数学表达式也可以被当作逻辑表达式来使用,规则就是如果表达式返回的不是0就是1。数学表达式和逻辑表达式等同是Mata语言的第一个特性。
Mata语言的第二个特性就是,=
表示赋值而==
表示逻辑判断。
所以你一定要注意不要把:1
if (x == 2) ...
打成了:1
if (x = 2) ...
因为第二个式子并不会返回错误,它会把x赋值为2,同事x = 2
这个表达式会被视为true。
Mata的最后一个特性就是++
和--
运算符了,观察下面的两个式子:
- z = v[i++] + x
- z = v[++i] + x
v[i++]
表示获取v[i]
然后把i
增加1;v[++i]
表示先增加i
然后再获取v[i]。
例如,如果在语句执行前i为2,那么:
v[i++]是v[2],而v[++i]是v[3]。
条件语句
这里没什么值得啰嗦的。
循环语句
Mata中有三种循环结构:
- for;
- while;
- do … while
例如求$\sqrt{2}$:1
2
3
4
5
6mata:
mata clear
x = 1
while (abs(x^2 - 2) > 1e-8) x = x - (x^2 - 2)/(2 * x)
x
end
运行结果:1
2
3
4
5
6
7
8
9
10
11
12
13. mata:
------------------------------------------------- mata (type end to exit) ----------------------
: mata clear
: x = 1
: while (abs(x^2 - 2) > 1e-8) x = x - (x^2 - 2)/(2 * x)
: x
1.414213562
: end
------------------------------------------------------------------------------------------------
而如果使用for语句,下面的三种形式都是可以的:1
2
3for (x = 1; abs(x^2 - 2) > 1e-8;) x = x - (x^2 - 2)/(2*x)
for (x = 1; abs(x^2 - 2) > 1e-8; x = x - (x^2 - 2)/(2*x)){}
for (x = 1; abs(x^2 - 2) > 1e-8; x = x - (x^2 - 2)/(2*x));
例如:1
2
3
4. mata: for (x = 1; abs(x^2 - 2) > 1e-8; x = x - (x^2 - 2)/(2*x));
. mata: x
1.414213562
而对于continue
和break
,continue
表示循环剩下的部分将被跳过,但是循环还会继续,而break
表示跳出循环。
GOTO语句在翻译Fortran语句时非常有用,例如对于下面的Fortran语句:1
2
3
4
5 A = 4.0e0/3.0e0
10 B = A - 1.0e0
C = B + B + B
EPS = DABS(C - 1.0e0)
if (EPS.EQ.0.0e0) GOTO 10
翻译成Mata语句:1
2
3
4
5 A = 4.0e0/3.0e0
s10: B = A - 1.0e0
C = B + B + B
EPS = abs(C - 1.0e0)
if (EPS == 0.0e0) goto s10
return
这里只有一点需要额外知道的,就是return可以用在程序中以提前结束程序。