Lua: Rounding numbers and then truncate

青春壹個敷衍的年華 提交于 2020-02-17 22:28:30

问题


Which is the best efficient way to round up a number and then truncate it (remove decimal places after rounding up)?

for example if decimal is above 0.5 (that is, 0.6, 0.7, and so on), I want to round up and then truncate (case 1). Otherwise, I would like to truncate (case 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)

回答1:


There is no build-in math.round() function in Lua, but you can do the following: print(math.floor(a+0.5)).




回答2:


A trick that is useful for rounding at decimal digits other than whole integers is to pass the value through formatted ASCII text, and use the %f format string to specify the rounding desired. For example

mils = tonumber(string.format("%.3f", exact))

will round the arbitrary value in exact to a multiple of 0.001.

A similar result can be had with scaling before and after using one of math.floor() or math.ceil(), but getting the details right according to your expectations surrounding the treatment of edge cases can be tricky. Not that this isn't an issue with string.format(), but a lot of work has gone into making it produce "expected" results.

Rounding to a multiple of something other than a power of ten will still require scaling, and still has all the tricky edge cases. One approach that is simple to express and has stable behavior is to write

function round(exact, quantum)
    local quant,frac = math.modf(exact/quantum)
    return quantum * (quant + (frac > 0.5 and 1 or 0))
end

and tweak the exact condition on frac (and possibly the sign of exact) to get the edge cases you wanted.




回答3:


To also support negative numbers, use this:

function round(x)
  return x>=0 and math.floor(x+0.5) or math.ceil(x-0.5)
end



回答4:


Should be math.ceil(a-0.5) to correctly handle half-integer numbers




回答5:


Here's one to round to an arbitrary number of digits (0 if not defined):

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



回答6:


For bad rounding (cutting the end off):

function round(number)
  return number - (number % 1)
end

Well, if you want, you can expand this for good rounding.

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

Expected results:

3, 3, 42, 5, 5




回答7:


I like the response above by RBerteig: mils = tonumber(string.format("%.3f", exact)). Expanded it to a function call and added a precision value.

function round(number, precision)
   local fmtStr = string.format('%%0.%sf',precision)
   number = string.format(fmtStr,number)
   return number
end



回答8:


If your Lua uses double precision IEC-559 (aka IEEE-754) floats, as most do, and your numbers are relatively small (the method is guaranteed to work for inputs between -250 and 250), the following efficient code will perform rounding using your FPU's current rounding mode, which is usually round to nearest, ties to even:

local function round(num)
  return num + (2^52 + 2^51) - (2^52 + 2^51)
end

For example, when the FPU is set to round to nearest or even, this unit test prints "All tests passed":

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")

Here's another (less efficient, of course) algorithm that performs the same FPU rounding but works for all numbers:

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


来源:https://stackoverflow.com/questions/18313171/lua-rounding-numbers-and-then-truncate

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!