Lua中检测32位序号环绕的方法

lua
--[[
判断32位无符号序号a是否比b新(处理环绕)
返回 true 表示a比b新,false 表示a比b旧或相等
--]]
--- 32位无符号时间戳升序比较器(处理回绕)
--- 判断 a 是否应该排在 b 前面,即 a 是否比 b 旧
--- @param a number 32位无符号整数
--- @param b number 32位无符号整数
--- @return boolean true 表示 a 比 b 旧,应排在前面
local function TimeComparator_Asc(a, b)
if a == b then
return false
end
-- 确保作为32位无符号数处理
local a32 = a & 0xFFFFFFFF
local b32 = b & 0xFFFFFFFF
-- 计算 (a - b) mod 2^32
local diff = (a32 - b32) & 0xFFFFFFFF
-- 升序排序条件:如果 a 比 b 旧,则 (a - b) 的差值落在 [2^31, 2^32)
-- 此时 diff >= 2^31
return diff >= 0x80000000 -- 0x80000000 = 2^31
end
-- 方法一:取模运算(兼容 Lua 5.1+)
function is_newer_mod(a, b)
local diff = (a - b) % 2^32
return diff > 0 and diff < 2^31 -- 排除相等情况
end
-- 方法二:位运算(Lua 5.3+,效率更高)
function is_newer_bit(a, b)
local a32 = a & 0xFFFFFFFF
local b32 = b & 0xFFFFFFFF
local diff = (a32 - b32) & 0xFFFFFFFF
return diff ~= 0 and diff < 0x80000000 -- 0x80000000 = 2^31
end
-- 测试代码
local tests = {
{100, 50, true}, -- 正常:100 > 50
{50, 100, false}, -- 正常:50 < 100
{1, 2^32-1, true}, -- 环绕:1 比 4294967295 新
{2^32-1, 1, false}, -- 环绕:4294967295 比 1 旧
{500, 500, false}, -- 相等
}
print("测试 is_newer_mod:")
for _, t in ipairs(tests) do
local a, b, expected = t[1], t[2], t[3]
local result = is_newer_mod(a, b)
print(string.format("a=%u, b=%u → %s (期望 %s) %s",
a, b, tostring(result), tostring(expected),
(result == expected) and "✓" or "✗"))
end
print("\n测试 is_newer_bit:")
for _, t in ipairs(tests) do
local a, b, expected = t[1], t[2], t[3]
local result = is_newer_bit(a, b)
print(string.format("a=%u, b=%u → %s (期望 %s) %s",
a, b, tostring(result), tostring(expected),
(result == expected) and "✓" or "✗"))
end
原理简述
32位无符号序号范围 0~4,294,967,295,当达到最大值后归零。判断新旧的标准:
- 计算差值
diff = (a - b) mod 2^32,结果落在 [0, 2^32)。 - 若
diff < 2^31,说明 a 在 b 之后(新);否则 a 在 b 之前(旧)。 - 若
diff == 0表示相等。
该算法利用"半个区间"规则,在环形空间内确定前进方向。