In Lua 5.2.1, I tried to generate a random number with
num = math.random(9)
However, every time I run my program:
num = math.random(9)
print("The generated number is "..num..".")
I get the same number.
brendan#osiris:~$ lua number
The generated number is 8.
brendan#osiris:~$ lua number
The generated number is 8.
brendan#osiris:~$ lua number
The generated number is 8.
This is frustrating, because everytime I try to generate a new number and restart the program, I get the same sequence.
Is there a different way of generating a number?
Also, I've looked into
math.randomseed(os.time())
but I don't really get it. If this is indeed the solution could you explain how it works, what it does, and what number I'd get?
Thx,
Brendan
This is not particular to Lua. Pseudorandom generators usually work like that: they need a seed to start and the sequence they generate is not really random, but actually deterministic given a seed. This is a good thing for debugging but for production you need to alter the seed in a "random" way. An easy and typical way of doing that is to use the time to set the seed once at the start of the program.
In Lua this is the expected output. You are not guranteed to get different sequences across different sessions.
However, any subsequent calls to math.random will generate a new number:
>> lua
> =math.random(9)
1
>> lua
> =math.random(9)
1
>> lua
> =math.random(9)
1
> =math.random(9)
6
> =math.random(9)
2
math.randomseed() will change which sequence is replayed. If you set math.randomseed(3) for example, you will always get the same sequence, just like above:
>> lua
> math.randomseed(3)
> =math.random(9)
1
> =math.random(9)
2
> =math.random(9)
3
>> lua
> math.randomseed(3)
> =math.random(9)
1
> =math.random(9)
2
> =math.random(9)
3
If you however set math.randomseed() to a unique value each run, for example os.time(), you will ofcourse get an unique sequence each time.
First, you have to call 'math.randomseed()'
'Why?'
Because Lua generates pseudo random numbers.
--One of the best seeds for 'math.randomseed()' is the time.
So, you'll first write:
math.randomseed(os.time())
After this,
num = math.random(9)
print("The generated number is "..num..".")
However, there is a bug on Windows. Then if you just write 'num = math.random(9)' the generated number will be the same for 1 hour, i think.
'So how can I resolve this?'
It's easy, you need to do a for loop.
for n = 0, 5 do
num = math.random(9)
end
So, in Windows, the final code would be:
math.randomseed(os.time())
for n = 0, 5 do
num = math.random(9)
end
print("The generated number is "..num..".")
OBS: If 'for n = 0, 5 do' does not work perfectly, then replace 5 with 10.
Related
so I'm new to LUA and am writing a simple guess-the-number script, but I've found a weird quirk that happens with math.random and I would like to understand what's happening here.
So I create a random seed with math.randomseed(os.time()), but when I go to get a random number, like this:
correctNum = math.random(10)
print(correctNum),
it always gets the same random number everytime I run it, unless I do it twice (irrespective of arguments given):
random1 = math.random(10)
print(random1)
random2 = math.random(10)
print(random2),
in which case the first random number will never reroll on every execution, but the second one will.
Just confused about how randomization works in LUA and would appreciate some help.
Thanks,
-Electroshockist
Here is the full working code:
math.randomseed(os.time())
random1 = math.random(10)
print(random1)
random2 = math.random(10)
print(random2)
repeat
io.write "\nEnter your guess between 1 and 10: "
guess = io.read()
if tonumber(guess) ~= random2 then
print("Try again!")
end
print()
until tonumber(guess) == random2
print("Correct!")
I guess you are calling the script twice within the same second. The resolution of os.time() is one second, i.e. if you are calling the script twice in the same second, you start with the same seed.
os.time ([table])
Returns the current time when called without arguments, or a time representing the date and time specified by the given table. This table must have fields year, month, and day, and may have fields hour, min, sec, and isdst (for a description of these fields, see the os.date function).
The returned value is a number, whose meaning depends on your system. In POSIX, Windows, and some other systems, this number counts the number of seconds since some given start time (the "epoch"). In other systems, the meaning is not specified, and the number returned by time can be used only as an argument to date and difftime.
Furthermore you are rolling a number between 1 and 10, so there is a 0.1 chance that you are hitting 4 (which is not that small).
For better methods to seed random numbers, take a look here: https://stackoverflow.com/a/31083615
The official tour of Go gives the following code in the sandbox:
package main
import (
"fmt"
"math/rand"
)
func main() {
fmt.Println("My favorite number is", rand.Intn(10))
}
And this instruction:
Note: the environment in which these programs are executed is deterministic, so each time you run the example program rand.Intn will return the same number. (To see a different number, seed the number generator; see rand.Seed.)
After reading the entry under the official documentation for rand.Seed and reading this answer, I still can't correctly seed the random number generator.
Can someone please demonstrate how the rand.Seed function should be used to seed the random number generator?
Many thanks,
Jon
By default rand.Intn uses the globalRand.Intn. Its created internally, refer here. So when you set via rand.Seed
rand.Seed(time.Now().UTC().UnixNano())
Then globalRand uses the new seed value.
When needed you can create your own rand generator with seed value. Refer to godoc example.
Play Link (without seed): https://play.golang.org/p/2yg7xjvHoJ
Output:
My favorite number is 1
My favorite number is 7
My favorite number is 7
My favorite number is 9
My favorite number is 1
My favorite number is 8
My favorite number is 5
My favorite number is 0
My favorite number is 6
Play Link (with seed): https://play.golang.org/p/EpW6R5rvM4
Output:
My favorite number is 0
My favorite number is 8
My favorite number is 7
My favorite number is 2
My favorite number is 3
My favorite number is 9
My favorite number is 4
My favorite number is 7
My favorite number is 8
EDIT:
As #AlexanderTrakhimenok mentioned, in playground program execution is deterministic. However, the playground doesn't stop you from supplying rand.Seed value.
Remember Seed value is int64.
When you rand.Intn, it uses default seed value 1 for globalRand.
var globalRand = New(&lockedSource{src: NewSource(1).(Source64)})
And in playground time.Now().UTC().UnixNano() gives you same value 1257894000000000000 since the start time is locked to a constant. But it is different from default seed value, that's why second playground link produces the different result.
So above two would produce the same result always.
How should we change the result in playground?
Yes, we can. Let's supply UnixNano() value 1500909006430687579 to rand.Seed, which is generated from my machine.
Play Link: https://play.golang.org/p/-nTydej8YF
Output:
My favorite number is 3
My favorite number is 5
My favorite number is 3
My favorite number is 8
My favorite number is 0
My favorite number is 5
My favorite number is 4
My favorite number is 7
My favorite number is 1
As you quoted yourself:
the environment in which these programs are executed is deterministic.
So the Go Playground by design does not allow to create truly pseudo-random outputs.
This is done intentionally for purpose of caching results to minimize CPU/memory usage for consequent runs. So the engine can evaluate your program just once and serve the same cached output every time when you or anyone else run it again.
For the same purpose the start time is locked to a constant.
You may want to read a blog post on how and why it's implemented this way: https://blog.golang.org/playground
For anyone who really needs a pseudo-random seed in go playground, just don't use the constant timestamp. You can access the execution memory usage which is slightly different on each execution in go playground even in the sandbox. So your seed can very well be non-deterministic and actually somewhat pseudo-random like this:
package main
import (
"fmt"
"math/rand"
"strings"
"time"
"github.com/shirou/gopsutil/mem"
)
var extraSeed int64 = 1
func main() {
memStat, err := mem.VirtualMemory()
if err == nil {
extraSeed = (int64)(memStat.Used)
}
fmt.Println("extra seed : ", extraSeed)
rand.Seed(time.Now().UnixNano() + extraSeed) //<----
// extraSeed will work randomly even in go playground,
// since mem-Usage is eventually slightly different each time we execute it
// do something random, for example shuffle
orderedList := []string{"a","b","c","d","e"}
rand.Shuffle(len(orderedList), func(i, j int) {
orderedList[i], orderedList[j] = orderedList[j], orderedList[i]
})
fmt.Println("This should be random shuffeled: ", orderedList)
}
Maybe this is also a good idea if you fear that someone is tempering with your system clock to break your randomness... However that is just a more safe but still a pseudo-randomness.
If you have this kind of thoughts you might want to use cryptography safe random numbers instead :)
Hope that helps
I'm writing a project that firstly designates the root process to read a large data file and do some calculations, and secondly broadcast the calculated results to all other processes. Here is my code: (1) it reads random numbers from a txt file with nsample=30000 (2) generate dens_ent matrix by some rule (3) broadcast to other processes. Btw, I'm using OpenMPI with gfortran.
IF (myid==0) THEN
OPEN(UNIT=8,FILE='rnseed_ent20.txt')
DO i=1,n_sample
DO j=1,3
READ(8,*) rn(i,j)
END DO
END DO
CLOSE(8)
END IF
dens_ent=0.0d0
DO i=1,n_sample
IF (myid==0) THEN
!Random draws of productivity and savings
rn_zb=MC_JOINT_SAMPLE((/-0.1d0,mu_b0/),var,rn(i,1:2))
iz=minloc(abs(log(zgrid)-rn_zb(1)),dim=1)
ib=minloc(abs(log(bgrid(1:nb/2))-rn_zb(2)),dim=1) !Find the closest saving grid
CALL SUB2IND(j,(/nb,nm,nk,nxi,nz/),(/ib,1,1,1,iz/))
DO iixi=1,nxi
DO iiz=1,nz
CALL SUB2IND(jj,(/nb,nm,nk,nxi,nz/),(/policybmk_2_statebmk_index(j,:),iixi,iiz/))
dens_ent(jj)=dens_ent(jj)+1.0d0/real(nxi)*markovian(iz,iiz)*merge(1.0d0,0.0d0,vent(j) .GE. -bgrid(ib)+ce)
!Density only recorded if the value of entry is greater than b0+ce
END DO
END DO
END IF
END DO
PRINT *, 'dingdongdingdong',myid
IF (myid==0) dens_ent=dens_ent/real(n_sample)*Mpo
IF (myid==0) PRINT *, 'sum_density by joint normal distribution',sum(dens_ent)
PRINT *, 'BLBLALALALALALA',myid
CALL MPI_BCAST(dens_ent,N,MPI_DOUBLE_PRECISION,0,MPI_COMM_WORLD,ierr)
Problem arises:
(1) IF (myid==0) PRINT *, 'sum_density by joint normal distribution',sum(dens_ent) seems not executed, as there is no print out.
(2) I then verify this by adding PRINT *, 'BLBLALALALALALA',myid etc messages. Again no print out for root process myid=0.
It seems like root process is not working? How can this be true? I'm quite confused. Is it because I'm not using MPI_BARRIER before PRINT *, 'dingdongdingdong',myid?
Is it possible that you miss the following statement just at the very beginning of your code?
CALL MPI_COMM_RANK (MPI_COMM_WORLD, myid, ierr)
IF (ierr /= MPI_SUCCESS) THEN
STOP "MPI_COMM_RANK failed!"
END IF
The MPI_COMM_RANK returns into myid (if succeeds) the identifier of the process within the MPI_COMM_WORLD communicator (i.e a value within 0 and NP, where NP is the total number of MPI ranks).
Thanks for contributions from #cw21 #Harald and #Hristo Iliev.
The failure lies in unit numbering. One reference says:
unit number : This must be present and takes any integer type. Note this ‘number’ identifies the
file and must be unique so if you have more than one file open then you must specify a different
unit number for each file. Avoid using 0,5 or 6 as these UNITs are typically picked to be used by
Fortran as follows.
– Standard Error = 0 : Used to print error messages to the screen.
– Standard In = 5 : Used to read in data from the keyboard.
– Standard Out = 6 : Used to print general output to the screen.
So I changed all numbering i into 1i, not working; then changed into 10i. It starts to work. Mysteriously, as correctly pointed out by #Hristo Iliev, as long as the numbering is not 0,5,6, the code should behave properly. I cannot explain to myself why 1i not working. But anyhow, the root process is now printing out results.
I encountered a strange bug in julia. Essentially, adding a print("") statement somewhere sensibly changes the behavior of the following code (in a positive way). I am quite puzzled. Why?
xs = [1,2,3,4,5,6,7,8]
cmds = [`sleep $x` for x in xs]
f = open("results.txt", "w")
i = 1
nb_cmds = length(cmds)
max_running_ps = 3
nb_running_ps = 0
ps = Dict()
while true
# launching new processes if possible
if nb_running_ps < max_running_ps
if i <= nb_cmds && !(i in keys(ps))
print("spawn:")
println(i)
p = spawn(cmds[i], Base.DevNull, f, f)
setindex!(ps,p,i)
nb_running_ps = nb_running_ps + 1
i = i+1
end
end
# detecting finished processes to be able to launch new ones
for j in keys(ps)
if process_exited(ps[j])
print("endof:")
println(j)
delete!(ps,j)
nb_running_ps = nb_running_ps - 1
else
print("")
# why do I need that ????
end
end
# nothing runs and there is nothing to run
if nb_running_ps <= 0 && i > nb_cmds
break
end
end
close(f)
println("finished")
(Indeed, the commands are in fact more useful than sleep.)
If the print("") is removed or commented, the content of the conditional "if process_exited(ps[j])" seems to never run, and the program runs into an infinite while loop even though the first max_running_ps processes have finished.
Some background: I need to run a piece of code which takes quite a long time to run (and uses a lot of memory), for different values of a set of parameters (represented here by x). As they take a long time, I want to run them in parallel. On the other hand, there is nearly nothing to share between the different runs, so the usual parallel tools are not really relevant. Finally, I want to avoid a simple pmap, first in order to avoid loosing everything if there is a failure, and second because it may be useful to have partial results during the run. Hence this code (written in julia because the main code doing actual computations is in julia).
This is not a bug, though it might be surprising if you are not used to this kind of asynchronous programming.
Julia is single-threaded by default and only one task will run at once. And for a task to finish, Julia needs to switch to it. Tasks are switched whenever the current task yields.
print is also an asynchronous operation and so it will yield for you, but a simpler way to do it is yield(), which achieves the same result. For more information on asynchronous programming, see the documentation.
os.time() in Luaj returns time in milliseconds, but according to lua documentation, it should return time in seconds.
Is this a bug in Luaj?
And Can you suggest a workaround that will work with Luaj(for java) and real Lua(c/c++)? because i have to use the same lua source for both applications.(cant simply divide it with 1000, as they both have return different time scale)
example in my lua file:
local start = os.time()
while(true) do
print(os.time() - start)
end
in c++ , i received output:
1
1
1
...(1 seconds passed)
2
2
2
in java (using Luaj), i got:
1
...(terminate in eclipse as fast as my finger can)
659
659
659
659
fyi, i try this on windows
Yes there's a bug in luaj.
The implementation just returns System.currentTimeMillis() when you call os.time(). It should really return something like (long)(System.currentTimeMillis()/1000.)
It's also worth pointing out that the os.date and os.time handling in luaj is almost completely missing. I would recommend that you assume that they've not been implemented yet.
Lua manual about os.time():
The returned value is a number, whose meaning depends on your system. In POSIX, Windows, and some other systems, this number counts the number of seconds since some given start time (the "epoch"). In other systems, the meaning is not specified, and the number returned by time can be used only as an argument to os.date and os.difftime.
So, any Lua implementation could freely change the meaning of os.time() value.
It appears like you've already confirmed that it's a bug in LuaJ; as for the workaround you can replace os.time() with your own version:
if (runningunderluaj) then
local ostime = os.time
os.time = function(...) return ostime(...)/1000 end
end
where runningunderluaj can check for some global variable that is only set under luaj. If that's not available, you can probably come up with your own check by comparing the results from calls to os.clock and os.time that measure time difference:
local s = os.clock()
local t = os.time()
while true do
if os.clock()-s > 0.1 then break end
end
-- (at least) 100ms has passed
local runningunderluaj = os.time() - t > 1
Note: It's possible that os.clock() is "broken" as well. I don't have access to luaj to test this...
In luaj-3.0-beta2, this has been fixed to return time in seconds.
This was a bug in all versions of luaj up to and including luaj-3.0-beta1.