#code optimization

1 messages · Page 1 of 1 (latest)

steep nova
#

There's 1 real optimization & 3 micro-optimizations I can spot.

Real optimization:

  • Dynamically store the results of each unique radius, this should be feasible considering they'll always run the loop on integers.

Micro-optimizations:

  • Create a variable for radius^2 so it's only calculated once instead of twice.
  • Use table.insert for arrays instead of manually setting the index-value.
  • Have dx & dy set at the same time so there isn't a need for the variable temp.
local CachedResults = {}
function spiral(radius)
    local resoult = CachedResults[radius]
    if resoult ~= nil then
        return resoult
    end

    local radius2 = radius ^ 2
    resoult = table.create(radius2)
    local dx, dy = 1,0
    local x, y = 0, 0
    local segmentLength = 1
    local segmentPassed = 0

    for i = 1, radius2 do
        table.insert(resoult, Vector2.new(x, y))
        x += dx
        y += dy
        segmentPassed += 1
        if segmentPassed == segmentLength then
            segmentPassed = 0
            
            dx, dy = -dy, dx
            
            if dy == 0 then
                segmentLength += 1
            end
        end
    end
    
    CachedResults[radius] = resoult
    
    return resoult
end
tired flame
#

what is the purpose of adding the function result to CachedResults?

steep nova
tired flame
#

Ok. So it's like an extension if I needed the result of this function a second time

steep nova
# tired flame Ok. So it's like an extension if I needed the result of this function a second t...

Btw you do need to clone it if you plan on changing anything in the result table though, you can ignore this otherwise.

-- Changing any of the indices from the result WILL affect the original table.
local resoult = spiral(25)
resoult[3] = nil
local resoult2 = spiral(25)
print(resoult2[3]) -- nil

-- So you will need to clone the cached result if that's the case.
function spiral(radius)
    local resoult = CachedResults[radius]
    if resoult ~= nil then
        return table.clone(resoult)
    end
    ...
    CachedResults[radius] = table.clone(resoult) -- Don't forget here.
end
local resoult = spiral(25)
resoult[3] = nil
local resoult2 = spiral(25)
print(resoult2[3]) -- 1, 1
tired flame
#

I also used an O(1) complexity approach. How do you rate this approach? Which one should I choose? function spiralIndex(n)
if n == 1 then
return 0, 0
end

local k = math.ceil((math.sqrt(n) - 1) / 2)
local t = 2 * k + 1
local m = t * t

    t = t - 1

    if n >= m - t then
        return k - (m - n), -k
    end

    m = m - t

    if n >= m - t then
        return -k, -k + (m - n)
    end

    m = m - t

    if n >= m - t then
        return -k + (m - n), k
    end

    return k, k - (m - n - t)

end

#

for i = 1, radius * radius do
local x, y = spiralIndex(i)
local chunkX = x + playerChunkX
local chunkY = y + playerChunkY
local key = chunkX .. "," .. chunkY
if not generated[key] then
generated[key] = true
local part = Instance.new("Part")
part.Anchored = true
part.Size = vector.create(64, 1, 64)
part.Position = vector.create(chunkX * 16 + 32, 5, chunkY * 16 + 32)
part.Parent = workspace
end
end

steep nova
steep nova
# tired flame I also used an O(1) complexity approach. How do you rate this approach? Which on...

Anyways, this is better because you can dynamically calculate & retrieve precalculated indices of a result, instead of being forced to calculate all of the result.
I made a function for ya that works the same as the original Spiral function, except even & more optimized.

local CachedResults_Radius = {}
local CachedResults_i = {}
local function spiral2(radius)
    local result = CachedResults_Radius[radius]
    if result then return result end
    
    local radius2 = radius^2
    result = table.create(radius2)
    
    for i = 1, radius2 do
        local iResult = CachedResults_i[i]
        if not iResult then
            iResult = Vector2.new(spiralIndex(i))
            CachedResults_i[i] = iResult
        end
        table.insert(result, iResult)
    end
    
    CachedResults_Radius[radius] = result
    
    return result
end
tired flame
#

What I sent with the second attempt no longer matters, I checked using os.clock, and the first attempt won—it’s about 200% faster.

#

And one more question, is it worth converting vector2 into a table with {x, y}?

steep nova
steep nova
tired flame
#

Which plugin or program is this chart from? I want to have one too (:

steep nova
tired flame
#

Why is vector2 faster? I personally would think that creating a regular Lua table would be faster.

steep nova
#
local function A()
    local value = Vector2.new(0,0)
end
local function B()
    local value = {X = 0, Y = 0}
end
primal quiverBOT
# steep nova ```lua local function A() local value = Vector2.new(0,0) end ``` ```lua loca...

Results For https://discord.com/channels/@me/1449165093215666379/1449476096520228985:

OptimizeLevel: 2
DebugLevel: 0
-------------------
Function 0 (??):
GETIMPORT R0 2 [Vector2.new]
LOADN R1 0
LOADN R2 0
CALL R0 2 1
RETURN R0 0

Function 1 (??):
REMARK allocation: table template 2
DUPTABLE R0 2
LOADN R1 0
SETTABLEKS R1 R0 K0 ['X']
LOADN R1 0
SETTABLEKS R1 R0 K1 ['Y']
RETURN R0 0

Function 2 (??):
DUPCLOSURE R0 K0 []
DUPCLOSURE R1 K1 []
RETURN R0 0


steep nova
#

This according to ChatGPT (because idk engine stuff nor anything outside of Luau):
F0 is better because it creates a native userdata in C++, while F1 creates and mutates a Lua table.

Someone correct this if it's wrong 🙏

tired flame
#

It makes sense overall, C++ is fast. I'll do some tests and let's see