由于我使用的lua for windows是 5.1.5 版本所以很多 5.3 的特性并不能使用,比如说整型。
我们可以用科学计数法书写数值常量,例如:
整型值和浮点型值类型都是number
由于整型和浮点型都是number
类型,所以它们可以互相转换,具有相同算术值的整型值和浮点值在 Lua 中是相等的:
少数情况下需要区分整型和浮点型的时候可以使用math.type()
,由于我的 Lua 是低版本,所以并没有这个函数。
Lua 语言同样支持以0x
开头的十六进制常量,与其他语言不同,Lua 还支持十六进制浮点数,这种浮点数以 小数部分 和 以p
或'P'开头的指数部分组成。我的版本并没有这种特性。
可以使用%a
参数,通过函数string.format()
对这种带p
的格式进行格式化输出,但我的版本并没有%a
的参数。
接受一个数字,并将其转化为ASCII码表中对应的字符 |
接受一个数字并将其转化为有符号的整数格式 |
接受一个数字并将其转化为八进制数格式 |
接受一个数字并将其转化为无符号整数格式 |
接受一个数字并将其转化为十六进制数格式,使用小写字母 |
接受一个数字并将其转化为十六进制数格式,使用大写字母 |
接受一个数字并将其转化为科学计数法格式,使用小写字母e |
接受一个数字并将其转化为科学计数法格式,使用大写字母E |
接受一个数字并将其转化为浮点数格式 |
接受一个数字并将其转化为%e(%E,对应%G)即%f中较短的一种格式 |
接受一个字符串并将其转化为可安全被 Lua 编译器读入的格式 |
接受一个字符串并按照给定的参数格式化该字符串 |
为了进一步细化格式,可以在%后添加参数将以如下的顺序读入:
- 符号:一个
+
号表示其后的数字转义符将让正数显示正号,默认情况下只有负数才显示符号。 - 占位符:一个
0
,在后面制定了字串宽度时展位用,不填默认用空格占位。 - 对齐表示:在指定了字串宽度时,默认右对齐,增加一个
-
号可以改为左对齐。 - 小数位数/字串裁切:在宽度数值后增加的小数部分
n
,若后接f则设定该浮点数只保留n位,若后接s则设定该字符串只显示前n位。
除了加减乘除运算外,Lua 语言还支持取整除法、取模和指数运算。
对于 Lua 5.3 引入的整型而言,主要的建议就是 “开发人员要么选择忽略整型和浮点型二者之间的不同,要么就完整地控制每一个数值表示。” 因此,不论时操作整型值还是浮点型值,结果都应该是一样的。
除除法外,任意两个整型运算结果应仍是整型,两个浮点型运算结果仍是浮点型,当有一个操作数是整型另一个是浮点型时,Lua 会先将整型转化为浮点型。
由于两个整数相除的结果不总是整数,所以除法运算的操作数永远会被转换为浮点型。
Lua 5.3针对整数除法引入了一个称为 floor 除法的新算术运算符//
。顾名思义,floor除法会对得到的商向负无穷取整,从而保证结果是一个整数。这样,floor 除法就可以跟其他算术运算符遵守一样的规则,当两个操作数都是整数的时候,结果就是整型值,否则就是浮点型值。
以下公式是取模运算的定义:
如果操作数是整数,那么取模运算的结果也是整型值,否则是浮点型值。
取整的结果永远与第二个操作数的符号保持一致,对于任意指定的正常量K,不论x的正负,表达式 x % K
的结果永远在[0,k-1]或者[k-1,0]之间(取决于K的正负):
x - x%0.01
恰好是保留两位小数的结果,x-x%0.001
恰好是保留三位小数的结果,以此类推:
因此,x-x%1
是获取整数部分,x%1
是获取小数部分。
Lua 同样支持幂运算,使用符号^
表示即可,我们可以用x^0.5
来进行开方操作。
Lua 语言提供了下列关系运算:
这些关系运算的结果都是Boolean
类型。
==
和~=
进行相等性判断,如果两个操作数不是同一个类型,Lua 语言会认为他们是不相等的(整型和浮点型都是number
型):
Lua 语言提供了数学库math
。标准数学库由一组标准的数学函数组成,包括三角函数、指数函数、取整函数、最大和最小、随机数函数以及常量pi
和huge
,huge指的是最大的可表示数。
所有的三角函数都以弧度为单位,并通过函数deg和rad进行角度和弧度的转换。
函数math.random
用于生成伪随机数,共有三种调用方式。不带参数时,该函数将返回一个在 [0, 1) 范围内均匀分布的伪随机实数。当使用一个带有整型值 n 的参数调用时,该函数将返回一个在 [1, n] 范围内的伪随机整数。当使用两个整型值 l 和 u ,该函数返回在 [l, u] 范围内的随机整数。
函数randomseed
用于设置伪随机数发生器的种子,该函数的唯一参数就是数值类型的种子。在一个程序启动时,系统固定使用1为种子初始化伪随机数发生器。如果不设置其他的种子,每次程序运行时都会生成相同的随机数序列。所以通常用math.randomseed(os.time())
来使用当前系统时间作为种子初始化随机数发生器。
数学库提供了三个取整函数:floor
、ceil
和modf
。其中floor
向负无穷取整,ceil
向正无穷取整,modf
向零取整。取整结果能用整型表示时,返回结果为整型值,否则返回浮点型值(用浮点数表示的整数值),除了返回取整后的值以外,函数modf
还会返回小数部分作为第二结果:
如果参数本身就是一个整型值,那么就会返回它本身。
如果想要将数值 x 向最近的整数取整,可以对 x + 0.5 调用floor
函数。
大多数编程语言使用某些固定长度的比特位来表达数值。因此,数值的表示范围和精度上都是有限制的。
标准 Lua 使用 64 个比特位来存储整型值,其最大值为263-1,约等于1019;精简 Lua 使用 32 个比特位,存储整型值,其最大值约为20亿,数学库中定义了整型值的最大值math.maxinteger
和最小值math.mininteger
。
当我们在整型操作时出现比mininteger
更小或者maxinteger
更大二点数值时,就会出现 回环。
由于我的版本较低,数学库中并没有这两个常量,所以无法在 lua 环境下进行测试
对于浮点数而言,标准 Lua 使用双精度。标准 Lua 使用 64 个比特位表示所有数值,其中11位为指数。双精浮点数可以表示具有大致16个有效十进制位的数,范围从 -10^308 到 10^308。精简 Lua 使用32个比特位表示单精度浮点数,可以表示具有大致7个有效十进制位,范围从 -10^38 到 10^38。
我们可以简单地通过增加 0.0 的方式将整型值转换为浮点型值(我的版本中并没有这样的效果)。
小于 2^53 的所有整型值的表示与双精度浮点型值的表示一样,对于绝对值超过了这个值的整型值而言,再将其转换为浮点型值时可能导致精度丢失:
通过与零进行按位或运算,可以把浮点型值强制转换为整型值(需要 Lua 5.3),但是小数不能与零进行按位或运算:
因此对于小数必须显式调用取整函数floor
、ceil
或 modf
。
在第一章 习题 1.7 中已经介绍了运算符优先级,此处不再赘述。
在二元运算符中,除了幂运算和连接操作符是右结合外,其余运算符都是左结合。所谓右结合就是从右向左执行运算,例如:x^y^z
等价于x^(y^z)
,而x+y+z
等价于(x+y)+z
。
在不能确定某些表达式的运算符优先级的时候,应该显式地使用括号来指定顺序。
Lua 5.3 引入的整型值导致其相对于此前的 Lua 版本出现了一定的不兼容,但是如前所述,程序员基本上可以忽略整型值和浮点型值之间的不同。
Lua 5.2 和 Lua 5.3 之间最大的不同是整数的表示范围。Lua 5.2 支持的最大整数为 2^53,而 Lua 5.3 支持的最大整数为 2^63。在当作计数值使用时,它们之间的区别通常不会导致问题;然而,当把整型值当作通用的比特位使用时(例如,把 3 个 20-bit 的整型值放在一起使用),他们之间的区别则可能很重要。
虽然 Lua 5.2 不支持整型,但是几个场景下仍然会涉及整型问题。例如,C 语言实现的库函数通常使用整型参数,但 Lua 5.2 却并没有约定这些情况下浮点型值和整型值之间的转换方法:Lua 5.2 可能将 -3.2 转换为 -3,也可能转换成 -4。Lua 5.3则明确了这种转换规则。
可能让人感到震惊的是,与整型引入相关的问题根源在于,Lua 语言将数值转换为字符串的方式。Lua 5.2将所有的整数值格式化为整型(即不带小数点),而 Lua 5.3则将所有的浮点数格式化为浮点型(带有十进制小数点或指数)。因此 Lua 5.2 会将 7.0 格式化为 ”7“ 输出而 Lua 5.3 则会将其格式化为 ”7.0“输出。虽然 Lua
语言从未说明过格式化数值的方式,但是很多程序员都默认的是早期版本的格式化输出行为。在将字符串转换为字符串时,我们可以通过显式的指明格式的方式来避免这种问题。
math.maxinteger的二进制为除符号位外全1,乘以2相当于整体左移1位,最后两位为10,1被移到符号位,有符号数用补码表示,取反+1后为全零,最后两位10,符号位不变,结果是-2。
math.mininteger的二进制为除首位外全0,左移1位后首位被抛弃,结果是全0,取反加1仍为全0,所以结果是0。
math.maxinteger除首位外全1,相乘后得到除最后一位和首部外,中间全0,超过符号位以外的部分被抛弃,其余全为0,最后只剩最后一位的1,所以结果为1。
math.mininteger除首位外全0,超出符号位以外的数值均被抛弃,其余全为0,所以结果为0。
可以考虑从0开始往下倒,就可以更方便的分析负数取余的结果。
由于幂运算是右结合且优先级高于负号,所以均是从右往左运算。
- 练习 3.5:当分母是 10 的整数次幂时,数值 12.7 与表达式 127/10相等。能否认为当分母是2的整数次幂时,这是一种通用规律?对于数值5.5情况又会怎样呢?
- 练习3.6:请编写一个通过高、母线与轴线的夹角来计算正圆锥体体积的函数。
- 练习 3.7:利用函数
math.random()
写一个生成遵循正态分布的伪随机数发生器。
-- 标准正态分布随机数发生器