4
0.4
4.57e-3
0.3e12
5E+20
type()函數
- 使用type()函數可以獲取整型值和浮點型值的型別,返回的都是number(表示數值型別)
type(3) type(3.5) type(3.14e3)
math.type()函數
- 如果想要區分整型值和浮點型值,可以使用這個函數
math.type(3) math.type(3.5) math.type(3.14e3)
0xff
0x1A3
0x0.2
0x1p-1
0xa.bp2
string.format("%a", 419)
string.format("%a", 0.1)
整型值和浮點型值之間的算術運算
- 如果兩個運算元都是整型值,則結果也是整型值;否則就是浮點型值
- 當兩個運算元的型別不同時,運算之前會先將整型值轉換爲浮點型值
- 例如:
13 + 15 13.0 + 15 13 + 15.0 13.0 + 15.0 1 * 2 1 * 2.0
除法的注意事項
- 由於兩個整數相處並不一定是整數,因此當兩個數進行相除時,interger都會轉換爲浮點數(即使兩個運算元都是整數液轉換)
- 並且除法運算的結果也是浮點數
- 例如:
3.0 / 2.0 3 / 2
floor除法
- floor除法會對得到的商向負無窮取整,從而保證結果是一個整數
- 這樣,floor除法就可以與其他算術運算一樣遵循同樣的規則:如果運算元都是整型值,那麼結果就是整型值,否則就是浮點數型別
- 例如:
3 // 2 3.0 // 2 6 // 2 6.0 // 2.0 -9 // 2 1.5 // 0.5
取負數運算
- 返回一個值的負數
- 使用的時候注意,對要操作的表達式的結果要加上括號,否則有點像是定義一個負數的感覺
- 例如:
-1.0 -1 -(-1) -- 這個是註釋, 而不是兩次取負 --1 - (3 * 6.0)
取模運算
- 取模運算的結果型別與上面介紹的一樣,如果兩個運算元都是整型值則返回整型;否則返回浮點數
- 例如:
a = 10 b = 2 a % b == a - ((a // b) * b)
- 對於實數型別(浮點數)而言,取模運算有一些不同,例如x-x%0.01恰好是x保留2位小數的結果,x-x%0.001恰好是x保留3位小數的結果
x = math.pi x - x%0.01 x - x%0.001
- 演示案例:我們可以使用取模運算檢查某輛車在拐過指定的角度後是否能夠原路返回。假設使用度作爲角度的單位,那麼我們可以使用下面 下麪的函數
local tolerance = 10 function isturnback(angle) angle = angle % 360 return (math.abs(angle - 180) < tolerance) end print(isturnback(-180)) print(isturnback(90))
- 使用弧度作爲角度的單位,那麼只需要簡單的修改一下常數的定義就可以了
local tolerance = 0.17 function isturnback(angle) -- 這一條語句實現了將任意範圍的角度歸一化到[0,2π)之間 angle = angle % (2*math.pi) return (math.abs(angle - math.pi) < tolerance) end print(isturnback(-180)) print(isturnback(90))
冪運算
- Lua也支援冪運算,使用符號^表示
- 像除法一樣,冪運算的運算元和結果也永遠是浮點型別(整型型別在冪運算時不能整除,例如,的結果不是整型值)
- 我們可以使用x^0.5來計算x的平方根,使用x^(1/3)來計算x的立方根
x = 4 x ^ 0.5 x = 27 x ^ (1 / 3)
1 == 2
1 == 1
-- 型別不同, 直接返回false, 根本不進行比較
1 == "1"
"1" == "1"
"1" == "2"
1.0 == 1
1 == 1
1.1 == 1
亂數發生器
- 函數math.random()用於生成僞亂數
- 一共有3中呼叫方式:
- 不帶參數呼叫時:函數返回一個在[0,1)範圍內的均勻分佈的僞隨機實數
- 當使用帶有一個整型值n的參數呼叫時:函數返回一個在[1, n]範圍內的僞隨機整數
- 使用兩個整型值l和u的參數呼叫時:函數返回在[l, u]範圍內的僞隨機整數
- 例如:
math.random() -- 可以模擬擲骰子的結果 math.random(6) math.random(10, 50)
- 函數randomseed()用於設定僞亂數發生器的種子,該函數的唯一參數就是數值型別的種子
- 在一個程式啓動時,系統固定使用1爲種子初始化僞隨機發生器;如果不設定其他的種子,那麼每次程式執行時都會生成相同的僞亂數序列
- 從偵錯的角度看,這是一個不錯的特性,然而,對於一個遊戲來說卻會導致相同的場景重複不斷的出現。爲了解決這個問題,通常呼叫math.randomseed(os.time())來使用當前系統時間作爲種子初始化亂數發生器(os.time()在後面文章介紹)
取整函數
- 數學庫提供了三個取整函數:
- floor:向負無窮取整
- ceil:向正無窮取整
- modf:向零取整
- 當取整的結果能用整數表示時,返回結果爲整型值,否則返回浮點型值
- modf除了返回取整後的值之外,還會返回小數部分作爲第二個結果(Lua支援一個函數返回多個值)
- 例如:
math.floor(3.3) math.floor(-3.3) math.ceil(3.3) math.ceil(-3.3) math.modf(3.3) math.modf(-3.3) math.floor(2^70)
- 如果參數本身是一個整型值,那麼它將原樣返回
math.floor(1) math.floor(-1) math.floor(0) math.ceil(1) math.ceil(-1) math.ceil(0) math.modf(1) math.modf(-1) math.modf(0)
- 如果想將數值x向最近的整數取整,可以對x+0.5呼叫floor函數
- 不過,當參數是一個很大的整數時,簡單的加法可能導致錯誤,考慮下面 下麪的程式碼
- +1.5的浮點值表示是不精確的,因爲內部會以我們不可控制的方式取整
x = 2^52 + 1 print(string.format("%d %d", x, math.floor(x + 0.5)))
- 爲了避免上面出現的問題,可以單獨地處理整數值。例如:
function round(x) local f = math.floor(x) if x == f then return f else return math.floor(x + 0.5) end end
- 上面的函數總是會向上取整半個證書(例如2.5會被取整爲3)。如果想進行無偏取整,即向距離最近的偶數取整半個整數,上述公佈在x+0.5是奇數的情況下會產生不正確的結果
-- ok math.floor(3.5 + 0.5) -- wrong math.floor(2.5 + 0.5)
- 這時,還可以利用取整操作來解決上述公式中存在的問題:表達式(x%2.0==0.5)只有在x+0.5爲奇數時(也就是我們的公式會出錯的情況)爲真。基於這些情況,定義一個無偏取整函數就很簡單了:
function round(x) local f = math.floor(x) if(x == f) or (x % 2.0 == 0.5) then return f else return math.floor(x + 0.5) end end print(round(2.5)) print(round(3.5)) print(round(-2.5)) print(round(-1.5))
整型取值範圍
- 標準Lua使用64個位元位來儲存整型值,其最大值爲,約等於
- 數學庫中的math.maxinteger和math.mininteger常數分別定義了整型值的最大值和最小值
迴環:當數值很大或者很小發生溢位時,就會發生迴環。迴環的意思就是結果只能在maxinteger和mininteger之間,也就是對取模的算術結果。例如:
math.maxinteger + 1 == math.mininteger math.mininteger - 1 == math.maxinteger -math.mininteger == math.mininteger math.mininteger // -1 == math.mininteger
- 最大可以表示的整數是0x7fffffffffffffff(15個f),即處最高位(符號位,0位非負數值)外其餘位元位均爲1。當我們對0x7fffffffffffffff加1時,其結果就變爲0x8000000000000000,即最小可表示的整數。最小整數比最大整數的表示幅度加1
math.maxinteger 0x7fffffffffffffff math.mininteger 0x8000000000000000
浮點型別取值範圍
- 對於浮點數而言,標準Lua使用雙精度。標準Lua使用64個位元位表示所有數值,其中11位爲指數。雙精度浮點數可以表示具有大致16個有效十進制位的數,範圍從到
- 雙精度浮點數對於大多數實際應用而言是足夠大的,但是我們必須瞭解精度的限制。如果我們使用十位表示一個數,那麼1/7會被取整到0.142857142。如果我們使用十位計算1/7*7,結果會是0.999999994而不是1。此外,用十進制表示的有限小數在用二進制表示時可能是無限小數。例如,12.7-20+7.3即便使用雙精度表示也不是0,這是由於12.7和7.3的二進制表示不是有限小數
math.maxinteger + 2
math.maxinteger + 2.0
math.maxinteger + 2.0 == math.maxinteger + 1.0
a + i < b/2+1 -- 等價於 (a+i) < ((b/2)+1)
5+x^2*8 -- 等價於 5+((x^2)*8)
a < y and y <= z -- 等價於 (a<y) and (y<=z)
-x^2 -- 等價於-(x^2)
x^y^z -- 等價於 x^(y^z)
整數轉浮點數
- 我們可以通過將整型值加上0.0將其轉換爲浮點型:
-3 + 0.0 0x7fffffffffffffff + 0.0
- 小於(即9007199254740992)的所有整型值的表示與雙精度浮點型值的表示一樣,對於絕對值超過了這個值的整型值而言,在將其強制轉換爲浮點型值時可能導致精度損失
9007199254740991 + 0.0 == 9007199254740991 9007199254740992 + 0.0 == 9007199254740992 -- 9007199254740992 + 1被取整爲9007199254740992,因此不相等 9007199254740993 + 0.0 == 9007199254740993
浮點數轉整數
- 通過與0進行按位元或運算,可以把浮點型值轉換爲整型值
-- 浮點型值 2^53 -- 整型值 2^53 | 0
- 在將浮點數強制轉換爲整數時,Lua會檢查數值是否與整型值表示完全一致(即沒有小數部分且其值在整型值的表示範圍內)。如果不滿足條件則會拋出異常。例如
-- 有小數部分 3.2 | 0 -- 超出範圍 2^64 | 0 -- 數值沒有用整型表示 math.random(1, 3.5)
- 對小數取整必須顯式地呼叫取整函數
- 另一種把浮點數轉換爲整型值的方式是使用math.tointeger(),該函數會在輸入參數無法轉換爲整型值時返回nil:
math.tointeger(-258.0) math.tointeger(2^30) -- 不是整數值 math.tointeger(5.01) -- 超出範圍 math.tointeger(2^64)
- 這個函數在需要檢查一個數字能夠被轉換成整型值時尤其有用。例如,以下函數在可能時會將輸入參數轉換爲整型值,否則保持原來的值不變:
function cond2int(x) return math.tointeger(x) or x end