So I was using the function (random 3)
to make a random number between I guess 0 and 3 but every time I ran the program it outputted the number 3 every time and when I tried (random 2)
it always outputs 1. I looked up what I needed to do and a different post on stack overflow said I needed to initialize the random-state which I assumed I would need to do so I put this code at the top of my program and that's when it went haywire.
(setf *random-state* (current-time))
After I put this code at the top and ran the program I first got an error that looked like this from the console.
*** - Program stack overflow. RESET
I tried running the program again and I got this super wacky error.
*** - handle_fault error2 ! address = 0x137c9500 not in [0x1a920000,0x1aaa7acc) !
SIGSEGV cannot be cured. Fault address = 0x137c9500.
GC count: 0
Space collected by GC: 0 0
Run time: 0 625000
Real time: 0 543820
GC time: 0 0
Permanently allocated: 92512 bytes.
Currently in use: 2734320 bytes.
Free space: 5 bytes.
I then got an error message from Windows that ended lisp.exe and I'm not sure what I did but when the hexadecimal came up I got freaked out. I've looked around the forums and I cannot find a solution to make my random-state code work can someone please help me.
Solution:
Instead of using (current-time)
I used (make-random-state t)
which works perfectly fine so my problem is fixed.
"... every time I ran the program it outputted the number 3...." Where is the code that calls (random 3)
? Calling (random 3)
repeatedly should return random numbers between 0 and 2, inclusive, and should never return 3. You will get the same pattern each time you start a new session unless you change the random state used by random
.
random
accepts an optional random state argument; you don't need to manually set the global *random-state*
variable, but it can be convenient. Don't rely on things you know from other languages when learning Common Lisp (or any new language), read the documentation when you have a question. In Common Lisp a random state is not an integer; it is a random state object, and you can create a new one by calling make-random-state
.
The posted code calls (current-time)
and sets *random-state*
to the returned value. Now, current-time
is not a Common Lisp function; it is specific to Clisp, where it prints the current time as a side-effect, returning nil
. After setting *random-state*
to the result of calling current-time
(nil
), *random-state*
is no longer bound to a random state object, and the call to random
is no longer valid. This is probably why your program "went haywire."
Here is an example function which returns a list of random numbers between 0 and n
(below n
):
(defun random-list (n max)
(loop for i from 1 to n
collecting (random max)))
Running this from the REPL to create a list of 10 random numbers between 0 and 2, inclusive, and using the default random state. The first line shows the value of *random-state*
:
CL-USER> *random-state*
#S(RANDOM-STATE #*0101001111100011110111001111101110101101110011101101001010001101)
CL-USER> (random-list 10 3)
(2 1 1 0 2 2 0 1 1 0)
CL-USER> (random-list 10 3)
(0 2 2 2 2 1 1 2 0 2)
CL-USER> (random-list 10 3)
(2 0 2 1 0 0 2 2 1 1)
You can see that each time the function is called, a different list is generated. This is because the random state (*random-state*
) has not been reset between calls to random
. Restarting the REPL and running the program again will produce exactly the same results because the random state is reset to its initial value:
CL-USER> *random-state*
#S(RANDOM-STATE #*0101001111100011110111001111101110101101110011101101001010001101)
CL-USER> (random-list 10 3)
(2 1 1 0 2 2 0 1 1 0)
CL-USER> (random-list 10 3)
(0 2 2 2 2 1 1 2 0 2)
CL-USER> (random-list 10 3)
(2 0 2 1 0 0 2 2 1 1)
Restarting again, we can try setf
with make-random-state
:
CL-USER> (setf *random-state* (make-random-state))
#S(RANDOM-STATE #*0101001111100011110111001111101110101101110011101101001010001101)
CL-USER> (random-list 10 3)
(2 1 1 0 2 2 0 1 1 0)
CL-USER> (random-list 10 3)
(0 2 2 2 2 1 1 2 0 2)
CL-USER> (random-list 10 3)
(2 0 2 1 0 0 2 2 1 1)
This did not work as expected! We got exactly the same results as when we used the default random state; this is because calling make-random-state
with a nil
argument or no argument returns a copy of the current random state object. You can call make-random-state
with t
as its argument to return a new random state object. Note that here Clisp has printed the random state object after the call to setf
; doing the same thing in SBCL will result in a very different random state object that takes significantly more lines to print.
CL-USER> (setf *random-state* (make-random-state t))
#S(RANDOM-STATE #*0101101000011011111101010101100110010101010100001011001111101100)
CL-USER> (random-list 10 3)
(0 1 0 0 1 1 1 2 2 1)
CL-USER> (random-list 10 3)
(0 0 2 2 0 2 1 0 2 1)
CL-USER> (random-list 10 3)
(1 2 1 2 0 0 1 0 2 0)
Now you can see that *random-state*
has been set to a new random state object, and the resulting lists are different from the previous lists.