Page 1 of 1
Can this simple rounding function be more efficient?
Posted: Mon Dec 12, 2022 4:46 am
by togFox
I've been told that operating on a string and then converting to number is inefficient and yeah - I get it - but I can't think of a fast way to do this and still be robust:
Code: Select all
function round(num, idp)
--Input: number to round; decimal places required
assert(num ~= nil, "Can't ROUND a nil value")
return tonumber(string.format("%." .. (idp or 0) .. "f", num))
end
Do you guys have a faster rounding function? I'm normally blasé about fractions of seconds but I use this to round thousands of rows in a data-set so performance matters in this case.
Thanks.
Re: Can this simple rounding function be more efficient?
Posted: Mon Dec 12, 2022 6:21 am
by zorg
why use string functions when this kind of thing is perfectly doable with math?
Code: Select all
function truncateToDecimal(num, dec) -- assume num is a number by default, assume dec is a number or nil by default
dec = dec or 0 -- default value
return num > 0 and math.floor(num * 10^dec)/10^dec or math.ceil(num * 10^dec)/10^dec -- works for both positives and negatives
end
Truncation simpler than rounding btw; if you want to have the dec-1th value affect the end, that'll be an excercise left to the reader.
Re: Can this simple rounding function be more efficient?
Posted: Mon Dec 12, 2022 1:40 pm
by Jasoco
I was using this code below, which on second glance is pretty much exactly the same as zorg's code formatted differently.
Code: Select all
function math_round(val, decimal)
if not val then return 0 end
if (decimal) then
return math.floor( (val * 10^decimal) + 0.5) / (10^decimal)
else
return math.floor(val+0.5)
end
end
Re: Can this simple rounding function be more efficient?
Posted: Mon Dec 12, 2022 4:08 pm
by zorg
not exactly; your special-case of decimal not specified does a simpler branch, and the +.5 thing is in fact the rounding i left out.
Re: Can this simple rounding function be more efficient?
Posted: Wed Dec 14, 2022 3:22 am
by Bigfoot71
I did some tests and it seems to be the fastest one (tests carried out on the phone, to try again on your side):
Code: Select all
function round(n, mult)
mult = mult or 1
return math.floor((n+mult/2)/mult) * mult
end
I found it here:
http://lua-users.org/wiki/SimpleRound
My script for comparison tests :
Code: Select all
local n = -.4
function round_1(num, idp)
--Input: number to round; decimal places required
assert(num ~= nil, "Can't ROUND a nil value")
return tonumber(string.format("%." .. (idp or 0) .. "f", num))
end
function round_2(num, dec) -- assume num is a number by default, assume dec is a number or nil by default
dec = dec or 0 -- default value
return num > 0 and math.floor(num * 10^dec)/10^dec or math.ceil(num * 10^dec)/10^dec -- works for both positives and negatives
end
function round(n, mult)
mult = mult or 1
return math.floor((n+mult/2)/mult) * mult
end
local timeTest = function(f, ...)
local t1, r, t2 = os.clock(), f(...), os.clock()
print(string.format("The function took %0.6f seconds to run", t2 - t1))
return r
end
print("\nOriginal function:\n")
for i = 1, 10 do
timeTest(round_1, n)
end
print("\nZorg's function:\n")
for i = 1, 10 do
timeTest(round_2, n)
end
print("\nLast function:\n")
for i = 1, 10 do
timeTest(round, n)
end
My results :
I always came across the same thing in terms of results, it's up to you to see if it suits you or not now
Re: Can this simple rounding function be more efficient?
Posted: Wed Dec 14, 2022 4:57 am
by togFox
This is great guys. As I said, I rarely care about micro-seconds but on this one application - micro-seconds * thousands of datasets = performance gains.