Skip to content

Latest commit

 

History

History
99 lines (76 loc) · 4.2 KB

File metadata and controls

99 lines (76 loc) · 4.2 KB

3 - 数值

数值常量

  • Lua 提供了两种数值格式: integerfloat。前者在底层上的实现是 64 位整型,而后者是双精度浮点类型(即 C 语言中的 double)。
  • 具有十进制小数或者指数的数值为 float,其余为 integer
  • 如果用 type 函数来获取这两种数值的类型,结果均为 number
  • 只有用 math.type 函数才能得到细分的类型

数值常量的比较

  • 具有相同算术值的 integerfloat 会被判定为相等,如 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 比较相似。

  • integerfloat 一起参加运算时,integer 会被提升至 float
  • 两个整数相除 / 的结果一定是 float
  • 使用 // 进行 floor 除法(但这一运算符同样适用于 float),结果向 $-\infty{}$ 取整(相比之下,Python 向 $\infty{}$ 取整,而 C/C++ 向零取整(?待进一步确认
  • 取模运算 % 的结果符号与模数相同
    • 适用于 float,如 x - x % 0.01 可以得到 x 保留两位小数(向 $-\infty{}$ 舍入)的结果
  • 支持幂运算 ^,结果总是 float 类型

关系运算

  • Lua 的关系运算符有:< > >= <= == ~=
  • 在判断相等性时,如果两个操作数类型不同,则结果一定为假;如果将两个类型不同的操作数进行大小的比较,则会报错

数学库

Lua 提供了标准数学库 math

三角函数

所有的三角函数和 C 语言一样都使用弧度作为单位 - 可以使用 degrad 进行角度、弧度的转换

随机数

math.random 用于生成伪随机数

  • 不带参数调用:生成 $[0,1)$ 内均匀分布的伪随机实数
  • 带一个整型参数 n:生成 $[1,n]$ 内均匀分布的伪随机整数
  • 带两个整型参数 lr:生成 $[\mathrm{l,r}]$ 内均匀分布的伪随机整数
  • 使用 math.randomseed(os.time()) 来设置伪随机数发生器的种子

取整函数

  • math.floor$-\infty{}$ 取整
  • math.ceil$+\infty{}$ 取整
  • math.modf$0$ 取整,其返回值有两个,分别是整数部分和小数部分

数值的表示范围

  • 使用 math.maxintegermath.mininteger 可以得到 integer 的最大值和最小值
  • 行为和 C 语言的 long long 相同,不同之处在于其溢出并不是 UB,而是严格定义的 “回环”,也就是模 $2^{64}$

float 转换为 integer

Lua 提供了两种方法:

  • |0:将不含小数部分float0 进行 | 运算可以得到 integer
    • 2^53 | 0,注意 2^53 的结果类型是 float
    • 如果操作数包含小数部分,则会报错
  • math.tointeger:行为和前者基本相同,但在操作数包含小数部分时不会报错,而是返回 nil

练习 3.7

利用函数 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: #