do
local conv = {}
for i = 0, 7 do
conv[tostring(i)] = ("%i%i%i"):format(i%8/4, i%4/2, i%2/1)
end
function tobinary(n)
return (("%o"):format(n):gsub(".", conv):match("1.+$")) or "0"
end
end
print(tobinary(4713))
Too much math.floor
for i, person inipairs(everybody) do [tab]ifnot person.obey then person:setObey(true) end end
love.system.openURL(github.com/pablomayobre)
Yeah I just happened to remember there was that %i format, glad I could be useful and thank you for reformatting my code, I had totally forgotten you could do the same with octal
time thief wrote:stop the madness
Yeah we should stop hahaha
Anyway is this method (the string.format + string.gsub) any faster than the loop division methods? I can see it would take slightly more memory because of the look up table but that could be ignored, speed would make the difference but I'm not sure of how slow string.format and gsub are so it could end up being slower
for i, person inipairs(everybody) do [tab]ifnot person.obey then person:setObey(true) end end
love.system.openURL(github.com/pablomayobre)
I'm still not sure why a tobinary function is useful, though. I wonder if your approach could be generalized to arbitrary bases somehow?
Nope, just base 2, 4, 8 (octal), and 16 (hexa), the later two can already be done with the use of string format so the weird one would be base 4, but basically powers of two. For the rest you need to use the division method
And I see that "bartbes" performs better than "Positive and bartbes" when the function is the exact same thing hahaha weird
Also when measuring performance it is better to keep the number of operations static and measure total time (the opposite of what you do) because otherwise the performance of getTime gets in the way and changes the overall result, do this instead:
local getTime = love.timer.getTime
local perf = function (name)
collectgarbage()
print(name)
local f = toBinary[name]
local start = getTime()
for i=1, 100000 do
f(i)
end
local finish = getTime()
print(('%d ops per second'):format(100000 / (finish - start)))
end
for i, person inipairs(everybody) do [tab]ifnot person.obey then person:setObey(true) end end
love.system.openURL(github.com/pablomayobre)
Positive07 wrote:Also when measuring performance it is better to keep the number of operations static and measure total time (the opposite of what you do) because otherwise the performance of getTime gets in the way and changes the overall result
I don't agree with this. getTime and anything else inside the loop does take time, but it affects all test cases equally. The goal isn't to test how performant any one solution is, but to compare solutions with one another. Other comparative performance testing tools take a similar approach (for example, jsPerf uses a strategy like this). Even if the goal were to measure the performance of each solution independently, tests could be compared against a no-op loop to get a more accurate reading. I prefer this approach because the amount of time the tests take is predictable and long-running scripts can't bog the test harness down indefinitely.
love.timer.getTime (and most other love functions) will cause the JIT compiler to avoid compilation of any code "around" it. If calls to getTime are around, but not in, a loop, then the JIT compiler may be able to compile the code in the loop (provided nothing else in the loop prevents it.)
Ahh, well that changes things. Do you know if using a socket as a timer would also prevent JIT compilation? I've run into cases where a perf will hang a build process if allowed to run for an unknown amount of time, so I'd really rather use this approach when possible.
Thinkng about it more, does that really matter? The JIT doesn't really need to compile the loop, just the function being tested (called from within the loop). I don't care about the performance of the loop, just the function being tested. The performance of the loop can be tested separately and the results can be adjusted for it. I'm not really sure why it would matter whether the stuff in the loop gets compiled.
I've been running this with LuaJIT's dump.on() and as far as I can tell all of the solutions fall back to the interpreter for various reasons (string.format, table.concat, "inner loop in root trace" and so on). I haven't messed with LuaJIT much before, but it seems to fall back to the interpreter quite a bit. Now I'd like to see a solution to this that can be completely compiled.
time thief wrote:Ahh, well that changes things. Do you know if using a socket as a timer would also prevent JIT compilation?
luasocket uses the classic Lua C API for its functions, which will prevent JIT compilation in the same manner as LÖVE's functions do.
time thief wrote:Thinkng about it more, does that really matter? The JIT doesn't really need to compile the loop, just the function being tested (called from within the loop). I don't care about the performance of the loop, just the function being tested.
LuaJIT doesn't specifically compile individual functions, it looks at what is actually being executed at runtime (without being restricted to specific blocks of scope like functions) and determines what to compile from there. Functions may be inlined (or not, depending), among a large amount of other potential optimizations.