Why is Lua loops slow? - performance

Lua is said to be a fast scripting language. But when I tested looping e.g.:
a = 0
while a < 1000000000 do
a = a + 1
end
It takes a lot of time (over 1 minute). Is it because Lua needs to copy and paste loop's content, and then evaluate?
I know that when evaluating you need to pop() items away from stack.
I tested this "speed-test" on Ruby too and it did the loop in about 20s.
EDIT:
Why is this so much faster on local variables? (~16 seconds to do same iteration but on local variable inside function)

Try the code below. It compares while vs for loops and globals vs local variables.
I get these numbers (with Lua 5.1.4, but they are similar for 5.3.2), which tell you the cost of using global variables in a loop:
WG 9.16 100
WL 1.96 467
FG 4.93 186
FL 1.18 776
Of course, these costs get diluted if you do real work inside the loop.
Here is the code:
local N=1e8
t0=os.clock()
a = 0
while a < N do
a = a + 1
end
t1=os.clock()-t0
print("WG",t1,math.floor(t1/t1*100+0.5))
t0=os.clock()
local a = 0
while a < N do
a = a + 1
end
t2=os.clock()-t0
print("WL",t2,math.floor(t1/t2*100+0.5))
t0=os.clock()
b = 0
for i=1,N do
b = b + 1
end
t3=os.clock()-t0
print("FG",t3,math.floor(t1/t3*100+0.5))
t0=os.clock()
local b = 0
for i=1,N do
b = b + 1
end
t4=os.clock()-t0
print("FL",t4,math.floor(t1/t4*100+0.5))

Your loop is inefficient and unpractical.
You're doing one billion iterations. That's not exactly "light".
Not to mention you're using a while loop to substitute a numeric for loop.

Related

Write a program that adds together all the integers from `1` to `250` (inclusive) and `puts`es the total

How would I do this using ruby and only using a while loop with if, elsif and else only?
sum = 0
i = 1
while i < 251
sum += i
i += 1
end
puts sum
You don’t need a while loop to implement this. But if they want a while loop…
n = 250
while true
puts ( n * (n + 1)) / 2
break
end
Some of the comments have alternatives that are interesting, but keeping this one because it has the flow of control at least pass through the while loop. Not sure if it counts as using a loop if control doesn't even enter the body of the loop.

Ruby: Program I wrote in JavaScript not working the same way in Ruby

I initially wrote this in JavaScript, and posted here asking for help (which I got). I then wrote it in Ruby, and it's not working as intended. It looks like the code is pretty much the same in Ruby.
Expected result: 29
Actual result: 2639
prime = 0
temp = 0
factor = 3
i = 3
num = 13195
while factor < num
if num % factor == 0
while i < factor
if factor % i == 0
temp = prime
break
else
temp = factor
end
i = i + 2
end
// i initializes back to 3
// so next factor can properly iterate through loop
i = 3
prime = temp
end
factor = factor + 2
end
i = 3
puts prime
And here's the link to the answer when I asked this as a JavaScript program:
https://stackoverflow.com/a/50970934/7217977
In Javascript, for (let i = 3; i < factor; i += 2) initializes i to 3 and then loops. But in your Ruby code you are initializing i only once at the very beginning, then each of your loops is reusing that one value of i without resetting it back to 3.
The Ruby way of translating that for loop is like this
(3...factor).step(2) do |i|
# loop code
end
this creates a block-local i that is reset for every iteration of the loop and cannot be interfered with by outer scopes.

For Loop in Visual Basic results wrong number of loops

I don't understand why I get x with a value of 6 while I think it should be 5.
Sub Main()
Dim x = 0
For x = 1 To 5
Next
Console.WriteLine(x)
Console.ReadLine()
End Sub
Result: 6
The reason that x equals 6 is because of the nature of a loop. You put no code inside the body of the loop. If you printed your code there you would see
1
2
3
4
5
Each time Next is reached, x is incremented. The fifth time you go through the loop, x is incremented to 6. In most cases it's best to not use loop variables outside of their loop. Using a C style loop what I mean is a bit more clear
for (int i=0; i<=5; i++){}
The loop runs until the condition i <= 5 is not true. Since each time through the loop i is increased by 1 this occurs first when i equals 6. I used the variable i here because i is a much more common loop variable name to see than x.

while-loop faster than for when returning iterator

I'm trying to oversimplify this as much as possible.
functions f1and f2 implement a very simplified version of a roulette wheel selection over a Vector R. The only difference between them is that f1 uses a for and f2 a while. Both functions return the index of the array where the condition was met.
R=rand(100)
function f1(X::Vector)
l = length(X)
r = rand()*X[l]
for i = 1:l
if r <= X[i]
return i
end
end
end
function f2(X::Vector)
l = length(X)
r = rand()*X[l]
i = 1
while true
if r <= X[i]
return i
end
i += 1
end
end
now I created a couple of test functions...
M is the number of times we repeat the function execution.
Now this is critical... I want to store the values I get from the functions because I need them later... To oversimplify the code I just created a new variable r where I sum up the returns from the functions.
function test01(M,R)
cumR = cumsum(R)
r = 0
for i = 1:M
a = f1(cumR)
r += a
end
return r
end
function test02(M,R)
cumR = cumsum(R)
r = 0
for i = 1:M
a = f2(cumR)
r += a
end
return r
end
So, next I get:
#time test01(1e7,R)
elapsed time: 1.263974802 seconds (320000832 bytes allocated, 15.06% gc time)
#time test02(1e7,R)
elapsed time: 0.57086421 seconds (1088 bytes allocated)
So, for some reason I can't figure out f1 allocates a lot of memory and its even greater the larger M gets.
I said the line r += a was critical, because if I remove it from both test functions, I get the same result with both tests, so no problems! So I thought there was a problem with the type of a being returned by the functions (because f1 returns the iterator of the for loop, and f2 uses its own variable i "manually declared" inside the function).
But...
aa = f1(cumsum(R))
bb = f2(cumsum(R))
typeof(aa) == typeof(bb)
true
So... what that hell is going on???
I apologize if this is some sort of basic question but, I've been going over this for over 3 hours now and couldn't find an answer... Even though the functions are fixed by using a while loop I hate not knowing what's going on.
Thanks.
When you see lots of surprising allocations like that, a good first thing to check is type-stability. The #code_warntype macro is very helpful here:
julia> #code_warntype f1(R)
# … lots of annotated code, but the important part is this last line:
end::Union{Int64,Void}
Compare that to f2:
julia> #code_warntype f2(R)
# ...
end::Int64
So, why are the two different? Julia thinks that f1 might sometimes return nothing (which is of type Void)! Look again at your f1 function: what would happen if the last element of X is NaN? It'll just fall off the end of the function with no explicit return statement. In f2, however, you'll end up indexing beyond the bounds of X and get an error instead. Fix this type-instabillity by deciding what to do if the loop completes without finding the answer and you'll see more similar timings.
As I stated in the comment, your functions f1 and f2 both contain random numbers inside it, and you are using the random numbers as stopping criterion. Thus, there is no deterministic way to measure which of the functions is faster (doesn't depend in the implementation).
You can replace f1 and f2 functions to accept r as a parameter:
function f1(X::Vector, r)
for i = 1:length(X)
if r <= X[i]
return i
end
end
end
function f2(X::Vector, r)
i = 1
while i <= length(X)
if r <= X[i]
return i
end
i += 1
end
end
And then measure the time properly with the same R and r for both functions:
>>> R = cumsum(rand(100))
>>> r = rand(1_000_000) * R[end] # generate 1_000_000 random thresholds
>>> #time for i=1:length(r); f1(R, r[i]); end;
0.177048 seconds (4.00 M allocations: 76.278 MB, 2.70% gc time)
>>> #time for i=1:length(r); f2(R, r[i]); end;
0.173244 seconds (4.00 M allocations: 76.278 MB, 2.76% gc time)
As you can see, the timings are now nearly identical. Any difference will be caused for external factors (warming or processor busy with other tasks).

R code: Efficiency Issue

I have a vector of length 14 and I would like to check in sets of 5 in this manner:
compare = c(rep(1,4),rep(0,10)) # Vector
g.test = matrix(0,5,10)
for (i in 5:14){
g.test[,i-4] = head(tail(compare,i),5)
}
if (sum(colSums(g.test) >= 3 & colSums(g.test) < 5 ) > 0){yield = T}
I am running through the vector
compare[c(10:14)] to compare[c(9:13)] to ... to compare[c(1:5)] and checking if any of it has a sum >= 3 and < 5.
BUT, compare is just 1 such vector; I've 100,000 such vector of different permutations of 1's and 0's but all of length 14. running my code like that took my computer 100 seconds to run through. Is there a better way to do this?
I'm actually running a simulation test for Texas poker. This portion of the code is used to check for incomplete straight draws.
Try this:
g.sums <- rowSums(embed(compare, 5))
yield <- any(g.sums >= 3 & g.sums < 5)
100,000 iterations on my machine:
# user system elapsed
# 2.438 0.052 2.493

Resources