将FNV-1a算法从C#移植到Lua时乘法运算结果不匹配问题求助
问题根因
- 字节序问题需要优先修正:C#
Buffer.BlockCopy在x86/x64设备上默认按小端序写入字节数组,你当前Lua实现提取字节是大端序,首先要调整字节提取顺序和C#对齐。 - 更核心的原因是:C# 中
UInt32的乘法运算会自动截断到32位无符号整数范围,而Lua的乘法默认不会做这个截断,且bit库运算默认返回有符号32位整数,溢出后会出现符号位错误,导致结果不匹配。
修正步骤
- 调整整数转字节的逻辑,按小端序提取每个字节
- 每次乘法运算后,手动将结果截断为32位无符号整数
- 保证
bit.bxor的操作数是8位字节值,不要直接传入二进制字符串
修正后代码(兼容Lua 5.2+/LuaJIT)
local bit = require("bit") local FNV_32_PRIME = 0x01000193 local FNV_32_INIT = 0x811C9DC5 -- 和C#定义的2166136261完全等价 -- 辅助函数:将32位整数按小端序拆分为4个字节 local function int32_to_bytes_le(n) local b1 = bit.band(n, 0xFF) local b2 = bit.band(bit.rshift(n, 8), 0xFF) local b3 = bit.band(bit.rshift(n, 16), 0xFF) local b4 = bit.band(bit.rshift(n, 24), 0xFF) return {b1, b2, b3, b4} end local function FNV32Buffer(buffer) local bytes = {} -- 按小端序拆分所有输入整数到字节数组 for _, v in ipairs(buffer) do local bs = int32_to_bytes_le(v) for _, b in ipairs(bs) do bytes[#bytes + 1] = b end end local hash = FNV_32_INIT for _, b in ipairs(bytes) do hash = bit.bxor(hash, b) hash = hash * FNV_32_PRIME -- 手动截断为32位无符号整数 hash = bit.band(hash, 0xFFFFFFFF) -- 有符号负数转无符号值 if hash < 0 then hash = hash + 0x100000000 end end return hash end -- 对应C#的HashCoordinates方法 local function HashCoordinates(x, y, seed) return FNV32Buffer({x, y, seed}) end
验证说明
修正后输入{0,0,300}的第一次迭代结果就会和C#对齐:初始hash值2166136261异或0后乘以0x01000193,截断为32位无符号整数的结果就是84696351,和你给出的C#第一次运算结果完全一致。
内容的提问来源于stack exchange,提问作者Wolfgang Schreurs
相关产品推荐
相关产品推荐

