如果您的 Lua 使用双精度 IEC-559(又名 IEEE-754)浮点数,就像大多数人一样,并且您的数字相对较小(该方法保证适用于 -2 51和 2 51之间的输入),则以下有效代码将使用 FPU 的当前舍入模式执行舍入,该模式通常舍入到最接近的值,与偶数相关:
local function round(num)
return num + (2^52 + 2^51) - (2^52 + 2^51)
end
(请注意,括号中的数字是在编译时计算的;它们不影响运行时)。
例如,当 FPU 设置为最接近或偶数时,此单元测试会打印“所有测试通过”:
local function testnum(num, expected)
if round(num) ~= expected then
error(("Failure rounding %.17g, expected %.17g, actual %.17g")
:format(num+0, expected+0, round(num)+0))
end
end
local function test(num, expected)
testnum(num, expected)
testnum(-num, -expected)
end
test(0, 0)
test(0.2, 0)
test(0.4, 0)
-- Most rounding algorithms you find on the net, including Ola M's answer,
-- fail this one:
test(0.49999999999999994, 0)
-- Ties are rounded to the nearest even number, rather than always up:
test(0.5, 0)
test(0.5000000000000001, 1)
test(1.4999999999999998, 1)
test(1.5, 2)
test(2.5, 2)
test(3.5, 4)
test(2^51-0.5, 2^51)
test(2^51-0.75, 2^51-1)
test(2^51-1.25, 2^51-1)
test(2^51-1.5, 2^51-2)
print("All tests passed")
这是另一种(当然效率较低)算法,它执行相同的 FPU 舍入但适用于所有数字:
local function round(num)
local ofs = 2^52
if math.abs(num) > ofs then
return num
end
return num < 0 and num - ofs + ofs or num + ofs - ofs
end