xlua - number最大安全整数与64位整数
lua5.1默认只提供了number类型来存放整数,如果用它来计算比较大的整数值,需要注意number的最大安全整数,超过的话建议使用xlua提供的64位整数类型(uint64)来计算。
number最大安全整数
lua5.1中的number默认是按 IEEE 754 双精度浮点数标准来存放的,即:占用8个字节,总共64位,由1位符号位、11位指数位和52位尾数位组成。
63位:符号位(Sign)。正数为0,负数为1。
52~62位:指数部分(Exponent),共11位。
0~51位:尾数部分(Mantissa),共52位。
当尾数部分全部为1,指数部分为1075(即:1023+52)时,为number的最大安全整数,即:2^53-1=9007199254740991(9000多万亿)
超过最大安全整数会怎样呢?
溢出变为负数?还是变为PositiveInfinity?运行下面的代码看下
local a = 9007199254740991 for i=1,10 do print(string.format("%.0f", (a+i))) end print("----------") for i=1,10 do print(string.format("%.0f", (a-i))) end
可以看到,超过后会出现重复的结果,原因就是精度开始丢失,算出的结果不精确了。而最大数之前的数字,不会重复都是精确的。

最大安全数的位数部分全为1了,那是不是没有比最大安全数更大的数了?
不是,浮点数除了尾数,还有指数部分,比如:指数部分为1076,尾数部分为 0000...0001,就比最大安全整数大,只是精度不准。
uint64
lua5.1不支持64位整数,所以xlua增加了对64位整数的支持(uint64),源码在xLua/build/i64lib.c,LuaEnv.cs中默认就引用了这个库:LuaAPI.luaopen_i64lib(rawL);
它的最大值为9223372036854775807(9223372036854多万亿或922多亿亿)
---@param str string 注意: 传入科学计数法的number类型, 小数点后会丢失 ---@return uint64 function uint64.parse(str) ---@param a uint64 ---@param b number ---@return number function uint64.compare(a, b) ---除 ---@param a uint64 ---@param b number ---@return uint64 function unit64.divide(a, b) ---取模 ---@param a uint64 ---@param b number ---@return uint64 function unit64.remainder(a, b) ---@param num number|uint64 ---@return uint64 function unit64:__add(num) ---@param num number|uint64 ---@return uint64 function unit64:__sub(num) ---@param num number|uint64 ---@return uint64 function unit64:__mul(num) ---@param num number|uint64 ---@return uint64 function unit64:__div(num) ---@param num number|uint64 ---@return boolean function unit64:__eq(num) ---@param num number|uint64 ---@return uint64 function unit64:__mod(num) ---@param num number|uint64 ---@return uint64 function unit64:__pow(num) ---@return string function unit64:__tostring() function unit64:__unm()
超过最大安全数时的数值运算例子
local num = 9007199254740990 for i=1,10 do local temp = num + i if temp > 9007199254740991 then local uval = uint64.parse(string.format("%.0f", num)) for j=i,10 do temp = uval + j print(uint64.tostring(temp)) end break else print(string.format("%.0f", temp)) end end
运行结果


浙公网安备 33010602011771号