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

运行结果

 

posted @ 2025-07-08 23:06  yanghui01  阅读(120)  评论(0)    收藏  举报