Lua:对数字进行四舍五入,然后截断。
什么是最有效的四舍五入并截断(在进行四舍五入后删除小数位)的方法?
例如,如果小数超过0.5(即0.6、0.7等),我想要进行四舍五入并截断(情况1)。否则,我想要进行截断(情况2)。
例如:
232.98266601563 => 四舍五入并截断后 = 233(情况1)
232.49445450000 => 四舍五入并截断后 = 232(情况2)
232.50000000000 => 四舍五入并截断后 = 232(情况2)
应该使用 math.ceil(a-0.5) 来正确处理半整数。
一个有用的小技巧,在除整数以外的小数位上取整是传递该值通过格式化ASCII文本,并使用%f格式串来指定所需的舍入。例如:
mils = tonumber(string.format("%.3f", exact))
将会将exact中的任意值舍入为0.001的倍数。
类似的结果可以在使用math.floor()或math.ceil()之前和之后进行缩放时获得,但根据您对边缘情况的期望得到正确的细节可能会很棘手。不是说string.format()不涉及到这个问题,而是说它在产生“预期”结果方面花费了很多精力。
将某个数舍入为除十的倍数仍需要缩放,并且还有所有棘手的边缘情况。一种表达简单且行为稳定的方法是编写:
function round(exact, quantum)
local quant,frac = math.modf(exact/quantum)
return quantum * (quant + (frac > 0.5 and 1 or 0))
end
并调整关于frac的确切条件(以及可能的exact符号)来获取您想要的边缘情况。
为了支持负数,可以使用以下代码:
function round(x)
return x>=0 and math.floor(x+0.5) or math.ceil(x-0.5)
end
针对不好的四舍五入(舍去小数点后的数):
function round(number)
return number - (number % 1)
end
嗯,如果你想,你可以将此扩展为好的四舍五入。
function round(number)
if (number - (number % 0.1)) - (number - (number % 1)) < 0.5 then
number = number - (number % 1)
else
number = (number - (number % 1)) + 1
end
return number
end
print(round(3.1))
print(round(math.pi))
print(round(42))
print(round(4.5))
print(round(4.6))
预期结果:
3,3,42,5,5
以下是将数字舍入到任意位数(如果没有定义则为0)的函数:
function round(x, n)
n = math.pow(10, n or 0)
x = x * n
if x >= 0 then x = math.floor(x + 0.5) else x = math.ceil(x - 0.5) end
return x / n
end
我喜欢 RBerteig 上面的回答:mils = tonumber(string.format("%.3f", exact))。
我将其扩展为函数调用并添加了精度值。
function round(number, precision)
local fmtStr = string.format('%%0.%sf',precision)
number = string.format(fmtStr,number)
return number
end
如果您的 Lua 使用 double precision IEC-559 (也称为 IEEE-754)的浮点数,大多数情况下,如果您的数字相对较小(该方法可保证适用于 -251 至 251 之间的输入),则以下高效的代码将使用您的 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)
-- 大多数在网络上找到的舍入算法,包括 Ola M 的答案,
-- 都无法通过此测试:
test(0.49999999999999994, 0)
-- 平局时选择偶数进行舍入,而不是总是向上:
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
以下是一个灵活的函数,可以将数字四舍五入到不同的小数位数。我用负数、大数、小数以及各种边缘情况进行了测试,它非常有用且可靠:
function Round(num, dp)
--[[
将数字四舍五入到指定的小数位数,可以是负数,
例如,-1 表示四舍五入到十位数,
举例:
173.2562 四舍五入为 0 位小数为 173.0
173.2562 四舍五入为 2 位小数为 173.26
173.2562 四舍五入为 -1 位小数为 170.0
]]--
local mult = 10^(dp or 0)
return math.floor(num * mult + 0.5)/mult
end
对于保留给定小数位数(也可以为负数)的四舍五入,我建议采用如下解决方案,该方案结合了已有答案中的发现,特别是Pedro Gimeno提供的鼓舞人心的答案。 我测试了一些我感兴趣的边角案例,但不能声称这使得此函数100%可靠:
function round(number, decimals)
local scale = 10^decimals
local c = 2^52 + 2^51
return ((number * scale + c ) - c) / scale
end
这些案例说明了四舍五入到最近偶数的属性(应该是大多数计算机的默认值):
assert(round(0.5, 0) == 0)
assert(round(-0.5, 0) == 0)
assert(round(1.5, 0) == 2)
assert(round(-1.5, 0) == -2)
assert(round(0.05, 1) == 0)
assert(round(-0.05, 1) == 0)
assert(round(0.15, 1) == 0.2)
assert(round(-0.15, 1) == -0.2)
我知道我的答案没有处理实际问题的第三种情况,但是为了符合IEEE-754标准,我的方法是有意义的。 因此,我期望结果取决于FPU中设置的当前舍入模式,其中FE_TONEAREST是默认值。 这就是为什么似乎很有可能在设置FE_TOWARDZERO之后(但是您可以在Lua中这样做)该解决方案将精确地返回问题中要求的结果。
尝试使用math.ceil(number + 0.5),这是根据这个 Wikipedia 页面。如果我没错的话,这只是对正整数进行四舍五入。如果是负数,需要进行math.floor(number - 0.5)。
如果有用的话,我已经用哈希值生成了一个通用版本的 LUA 逻辑,但这次是针对 truncate():
** 强调的文本预先道歉我不熟悉 lua 语法,所以这是在 AWK/lua 混合中,但希望这应该是直观的
-- 由于 lua-magic 已经在 2^(52-to-53) 区域内,因此必须使用
-- 比真正的 IEEE754 双倍机器 epsilon 更粗粒度的 delta
-- 2^-52。
function trunc_lua(x,s) {
return \
((x*(s=(-1)^(x<-x)) \
- 2^-1 + 2^-50 \ -- 也可以写成 2^-50-5^0/2
- _LUAMAGIC \ -- 如果你喜欢对称的代码,就这样
\ --
+ _LUAMAGIC \
) *(s) };
本质上与四舍五入相同,但强制将所有输入处理在正值区域,并带有 -1*(0.5-delta) 偏移量。最小的 delta 值我能够达到是 2^-52 ~ 2.222e-16。
Lua-magic 值必须在所有这些预处理步骤之后出现,否则可能会发生精度丢失。最后,恢复原始输入的符号。
这两个 "乘法" 只是低成本的符号翻转。对于最初的负值,符号翻转 4 次(2 次手动翻转和往返于尾数末尾),而任何 x >= 0,包括 -0.0 的值,只翻转两次。避免了所有三元函数调用、浮点除法和整数模除,只有一个检查 x<0 的条件。
使用说明:
- (1)不检查输入的有效性或恶意负载。
- (2)不使用快速检查零。
- (3)不检查可能使此逻辑无意义的极限输入。
- (4)不尝试美化值的格式。
如果 math.round 不存在,则:
function math.round(x, n)
return tonumber(string.format("%." .. n .. "f", x))
end
- 如何将两个不同的lua文件合成一个 东西有点长 大佬请耐心看完 我是小白研究几天了都没搞定
- 如何在roblox studio中1:1导入真实世界的地形?
- 求解,lua_resume的第二次调用继续执行协程问题。
- 【上海普陀区】内向猫网络招募【Skynet游戏框架Lua后端程序员】
- SF爱好求教:如何用lua实现游戏内调用数据库函数实现账号密码注册?
- Lua实现网站后台开发
- LUA错误显式返回,社区常见的规约是怎么样的
- lua5.3下载库失败
- 请问如何实现文本框内容和某个网页搜索框内容连接,并把网页输出来的结果反馈到另外一个文本框上
- lua lanes多线程使用
- 一个kv数据库
- openresty 有没有比较轻量的 docker 镜像
- 想问一下,有大佬用过luacurl吗
- 在Lua执行过程中使用Load函数出现问题
- 为什么 neovim 里没有显示一些特殊字符?
- Lua比较两个表的值(不考虑键的顺序)
- 有个lua简单的项目,外包,有意者加微信 liuheng600456详谈,最好在成都
- 如何在 Visual Studio 2022 中运行 Lua 代码?
- addEventListener 返回 nil Lua
- Lua中获取用户配置主目录的跨平台方法
在 Lua 中没有内置的
math.round()函数,但是你可以使用以下语句:print(math.floor(a+0.5))。