Home:ALL Converter>Lua: Rounding numbers and then truncate

Lua: Rounding numbers and then truncate

Ask Time:2013-08-19T19:54:32         Author:Willy

Json Formatter

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)

Author:Willy,eproduced under the CC 4.0 BY-SA copyright license with a link to the original source and this disclaimer.
Link to original article:https://stackoverflow.com/questions/18313171/lua-rounding-numbers-and-then-truncate
RBerteig :

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\n\nmils = tonumber(string.format(\"%.3f\", exact))\n\n\nwill round the arbitrary value in exact to a multiple of 0.001.\n\nA 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.\n\nRounding 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\n\nfunction round(exact, quantum)\n local quant,frac = math.modf(exact/quantum)\n return quantum * (quant + (frac > 0.5 and 1 or 0))\nend\n\n\nand tweak the exact condition on frac (and possibly the sign of exact) to get the edge cases you wanted.",
2013-08-19T20:30:36
ggVGc :

To also support negative numbers, use this:\n\nfunction round(x)\n return x>=0 and math.floor(x+0.5) or math.ceil(x-0.5)\nend\n",
2014-11-06T11:04:46
Pedro Gimeno :

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 -251 and 251), the following efficient code will perform rounding using your FPU's current rounding mode, which is usually round to nearest, ties to even:\nlocal function round(num)\n return num + (2^52 + 2^51) - (2^52 + 2^51)\nend\n\n(Note that the numbers in parentheses are calculated at compilation time; they don't affect runtime).\nFor example, when the FPU is set to round to nearest or even, this unit test prints "All tests passed":\nlocal function testnum(num, expected)\n if round(num) ~= expected then\n error(("Failure rounding %.17g, expected %.17g, actual %.17g")\n :format(num+0, expected+0, round(num)+0))\n end\nend\n\nlocal function test(num, expected)\n testnum(num, expected)\n testnum(-num, -expected)\nend\n\ntest(0, 0)\ntest(0.2, 0)\ntest(0.4, 0)\n-- Most rounding algorithms you find on the net, including Ola M's answer,\n-- fail this one:\ntest(0.49999999999999994, 0)\n-- Ties are rounded to the nearest even number, rather than always up:\ntest(0.5, 0)\ntest(0.5000000000000001, 1)\ntest(1.4999999999999998, 1)\ntest(1.5, 2)\ntest(2.5, 2)\ntest(3.5, 4)\ntest(2^51-0.5, 2^51)\ntest(2^51-0.75, 2^51-1)\ntest(2^51-1.25, 2^51-1)\ntest(2^51-1.5, 2^51-2)\nprint("All tests passed")\n\nHere's another (less efficient, of course) algorithm that performs the same FPU rounding but works for all numbers:\nlocal function round(num)\n local ofs = 2^52\n if math.abs(num) > ofs then\n return num\n end\n return num < 0 and num - ofs + ofs or num + ofs - ofs\nend\n",
2019-10-16T10:56:03
toma91 :

Here's one to round to an arbitrary number of digits (0 if not defined):\n\nfunction round(x, n)\n n = math.pow(10, n or 0)\n x = x * n\n if x >= 0 then x = math.floor(x + 0.5) else x = math.ceil(x - 0.5) end\n return x / n\nend\n",
2016-06-13T14:51:52
Hastumer :

For bad rounding (cutting the end off): \n\nfunction round(number)\n return number - (number % 1)\nend\n\n\nWell, if you want, you can expand this for good rounding.\n\nfunction round(number)\n if (number - (number % 0.1)) - (number - (number % 1)) < 0.5 then\n number = number - (number % 1)\n else\n number = (number - (number % 1)) + 1\n end\n return number\nend\n\nprint(round(3.1))\nprint(round(math.pi))\nprint(round(42))\nprint(round(4.5))\nprint(round(4.6))\n\n\nExpected results:\n\n3, 3, 42, 5, 5",
2016-04-22T15:53:53
Dan :

I like the response above by RBerteig: mils = tonumber(string.format(\"%.3f\", exact)).\nExpanded it to a function call and added a precision value.\n\nfunction round(number, precision)\n local fmtStr = string.format('%%0.%sf',precision)\n number = string.format(fmtStr,number)\n return number\nend\n",
2019-07-31T21:23:45
Egor Skriptunoff :

Should be math.ceil(a-0.5) to correctly handle half-integer numbers",
2013-08-19T20:18:39
George Williams :

Here is a flexible function to round to different number of places. I tested it with negative numbers, big numbers, small numbers, and all manner of edge cases, and it is useful and reliable:\nfunction Round(num, dp)\n --[[\n round a number to so-many decimal of places, which can be negative, \n e.g. -1 places rounds to 10's, \n \n examples\n 173.2562 rounded to 0 dps is 173.0\n 173.2562 rounded to 2 dps is 173.26\n 173.2562 rounded to -1 dps is 170.0\n ]]--\n local mult = 10^(dp or 0)\n return math.floor(num * mult + 0.5)/mult\nend\n",
2021-06-10T08:40:32
Wolf :

For rounding to a given amount of decimals (which can also be negative), I'd suggest the following solution that is combined from the findings already presented as answers, especially the inspiring one given by Pedro Gimeno. I tested a few corner cases I'm interested in but cannot claim that this makes this function 100% reliable:\nfunction round(number, decimals)\n local scale = 10^decimals\n local c = 2^52 + 2^51\n return ((number * scale + c ) - c) / scale\nend\n\nThese cases illustrate the round-halfway-to-even property (which should be the default on most machines):\nassert(round(0.5, 0) == 0)\nassert(round(-0.5, 0) == 0)\nassert(round(1.5, 0) == 2)\nassert(round(-1.5, 0) == -2)\nassert(round(0.05, 1) == 0)\nassert(round(-0.05, 1) == 0)\nassert(round(0.15, 1) == 0.2)\nassert(round(-0.15, 1) == -0.2)\n\nI'm aware that my answer doesn't handle the third case of the actual question, but in favor of being IEEE-754 compliant, my approach makes sense. So I'd expect that the results depend on the current rounding mode set in the FPU with FE_TONEAREST being the default. And that's why it seems high likely that after setting FE_TOWARDZERO (however you can do that in Lua) this solution would return exactly the results that were asked for in the question.",
2021-06-14T19:18:29
Ola M :

There is no build-in math.round() function in Lua, but you can do the following:\nprint(math.floor(a+0.5)).",
2013-08-19T12:10:40
Alvin-He :

Try using math.ceil(number + 0.5) This is according to this Wikipedia page. If I'm correct, this is only rounding positive integers. you need to do math.floor(number - 0.5) for negatives.",
2021-08-27T05:16:37
yy