Lua:舍入数字然后截断

时间:2013-08-19 11:54:32

标签: lua rounding truncate

哪种方法可以最有效地对数字进行舍入然后将其截断(在舍入后删除小数位)?

例如,如果小数大于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)

10 个答案:

答案 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))

预期结果:

334255

答案 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 中这样做)这个解决方案很可能会返回问题中要求的结果。