哪种方法可以最有效地对数字进行舍入然后将其截断(在舍入后删除小数位)?
例如,如果小数大于0.5(即0.6,0.7等),我想向上舍入然后截断(情况1)。否则,我想截断(案例2)
for example:
232.98266601563 => after rounding and truncate = 233 (case 1)
232.49445450000 => after rounding and truncate = 232 (case 2)
232.50000000000 => after rounding and truncate = 232 (case 2)
答案 0 :(得分:24)
Lua中没有内置的math.round()函数,但您可以执行以下操作:
print(math.floor(a+0.5))
。
答案 1 :(得分:11)
对于除整数之外的十进制数字舍入有用的技巧是通过格式化的ASCII文本传递值,并使用%f
格式字符串指定所需的舍入。例如
mils = tonumber(string.format("%.3f", exact))
将exact
中的任意值四舍五入为0.001的倍数。
在使用math.floor()
或math.ceil()
之一之前和之后进行缩放时,可以得到类似的结果,但根据您对边缘情况处理的期望来获取详细信息可能会非常棘手。并不是说这不是string.format()
的问题,但是已经做了很多工作来使它产生“预期的”结果。
舍入到10的幂以外的其他数字仍将需要缩放,并且仍然具有所有棘手的边缘情况。一种易于表达且具有稳定行为的方法是编写
function round(exact, quantum)
local quant,frac = math.modf(exact/quantum)
return quantum * (quant + (frac > 0.5 and 1 or 0))
end
并调整frac
上的确切条件(可能还有exact
的符号)以获取您想要的边缘情况。
答案 2 :(得分:8)
要同时支持负数,请使用:
function round(x)
return x>=0 and math.floor(x+0.5) or math.ceil(x-0.5)
end
答案 3 :(得分:3)
应math.ceil(a-0.5)
正确处理半整数
答案 4 :(得分:3)
这是一个舍入到任意位数的数字(如果未定义,则为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
答案 5 :(得分:1)
对于糟糕的舍入(切断结束):
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
答案 6 :(得分:1)
我喜欢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
答案 7 :(得分:1)
这是一个灵活的函数,可以四舍五入到不同的位置。我用负数、大数、小数和各种边缘情况对其进行了测试,它有用且可靠:
function Round(num, dp)
--[[
round a number to so-many decimal of places, which can be negative,
e.g. -1 places rounds to 10's,
examples
173.2562 rounded to 0 dps is 173.0
173.2562 rounded to 2 dps is 173.26
173.2562 rounded to -1 dps is 170.0
]]--
local mult = 10^(dp or 0)
return math.floor(num * mult + 0.5)/mult
end
答案 8 :(得分:0)
如果您的Lua像大多数一样使用双精度IEC-559(aka IEEE-754)浮点数,并且您的数字相对较小(保证该方法适用于-2 50 之间的输入和2 50 ),以下有效代码将使用您的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 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^50-0.5, 2^50)
test(2^50-1.5, 2^50-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
答案 9 :(得分:0)
为了四舍五入到给定的小数位数(也可以是负数),我建议采用以下解决方案,该解决方案结合了已经作为答案提供的调查结果,尤其是 the inspiring one given by Pedro Gimeno。我测试了一些我感兴趣的极端情况,但不能声称这使此功能 100% 可靠:
function round(number, decimals)
local scale = 10^decimals
local c = 2^52 + 2^51
return ((number * scale + c ) - c) / scale
end
这些案例说明了 round-halfway-to-even 属性(这应该是大多数机器上的默认值):
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
being the default 设置的当前舍入模式。这就是为什么在设置 FE_TOWARDZERO
之后(但是您可以在 Lua 中这样做)这个解决方案很可能会返回问题中要求的结果。