- Lua 提供了两种数值格式:
integer和float。前者在底层上的实现是 64 位整型,而后者是双精度浮点类型(即 C 语言中的 double)。 - 具有十进制小数或者指数的数值为
float,其余为integer - 如果用
type函数来获取这两种数值的类型,结果均为number - 只有用
math.type函数才能得到细分的类型
- 具有相同算术值的
integer和float会被判定为相等,如1 == 1.0 - 联系前面提到的 “底层实现”,我们知道双精度浮点数最大能精确表示的奇数为
$2^{53}-1$ ,那么 Lua 能否处理$2^{53}+1$ 的比较呢?也就是,9007199254740993 == 9007199254740993.0的结果是true还是false?- 经测试,结果为
false - 而
9007199254740991 == 9007199254740991.0(即$2^{53}-1$ ) 为true - 在 3.6 节原书提到了这个有趣的现象——看来我的思路和作者是相同的
- 经测试,结果为
和 Python 比较相似。
- 当
integer和float一起参加运算时,integer会被提升至float - 两个整数相除
/的结果一定是float - 使用
//进行 floor 除法(但这一运算符同样适用于float),结果向$-\infty{}$ 取整(相比之下,Python 向$\infty{}$ 取整,而 C/C++ 向零取整(?待进一步确认) - 取模运算
%的结果符号与模数相同- 适用于
float,如x - x % 0.01可以得到x保留两位小数(向$-\infty{}$ 舍入)的结果
- 适用于
- 支持幂运算
^,结果总是float类型
- Lua 的关系运算符有:
<>>=<===~= - 在判断相等性时,如果两个操作数类型不同,则结果一定为假;如果将两个类型不同的操作数进行大小的比较,则会报错
Lua 提供了标准数学库 math
所有的三角函数和 C 语言一样都使用弧度作为单位
- 可以使用 deg 和 rad 进行角度、弧度的转换
math.random 用于生成伪随机数
- 不带参数调用:生成
$[0,1)$ 内均匀分布的伪随机实数 - 带一个整型参数
n:生成$[1,n]$ 内均匀分布的伪随机整数 - 带两个整型参数
l和r:生成$[\mathrm{l,r}]$ 内均匀分布的伪随机整数 - 使用
math.randomseed(os.time())来设置伪随机数发生器的种子
-
math.floor向$-\infty{}$ 取整 -
math.ceil向$+\infty{}$ 取整 -
math.modf向$0$ 取整,其返回值有两个,分别是整数部分和小数部分
- 使用
math.maxinteger和math.mininteger可以得到integer的最大值和最小值 - 行为和 C 语言的
long long相同,不同之处在于其溢出并不是 UB,而是严格定义的 “回环”,也就是模$2^{64}$
Lua 提供了两种方法:
|0:将不含小数部分的float和0进行|运算可以得到integer- 如
2^53 | 0,注意2^53的结果类型是float - 如果操作数包含小数部分,则会报错
- 如
math.tointeger:行为和前者基本相同,但在操作数包含小数部分时不会报错,而是返回nil
利用函数 math.random 编写一个遵循正态分布(高斯分布)的伪随机数发生器。
这是本章的最后一道练习题,其他的都比较 trivial,只有它看起来有点意思,但也不多。
在之前阅读某篇 SIGGRAPH 论文的时候,我学习了两种利用均匀分布生成服从非均匀分布的概率密度函数的算法,第一种是接受-拒绝采样,第二种是逆累积分布函数法,因为高斯函数的 CDF 不太好求(解析式算不出来,但可以通过数值积分计算),这里仅实现前者。
代码见 gauss.lua。为了验证结果的正确性,我模仿以前曾经在《C++ Primer》上看到过的方法:将频度用柱状图的形式打印出来。
运行结果:
-10: #
-09: #
-08: #
-07: #
-06: #
-05: ##
-04: ##
-03: ##
-02: #####
-01: ###########
000: ###########
001: ######
002: ##
003: ##
004: #
005: #
006: #
007: #
008: #
009: #
010: #