Dar*_*345 0 lisp clisp common-lisp
所以我使用这个函数(random 3)
在我猜测的 0 和 3 之间生成一个随机数,但是每次我运行程序时它每次都输出数字 3,当我尝试时(random 2)
它总是输出 1。我查找了我需要做什么和一个关于堆栈溢出的不同帖子说我需要初始化随机状态,我认为我需要这样做,所以我把这段代码放在我的程序的顶部,那是它出问题的时候。
(setf *random-state* (current-time))
Run Code Online (Sandbox Code Playgroud)
在我把这段代码放在顶部并运行程序后,我首先从控制台收到一个看起来像这样的错误。
*** - Program stack overflow. RESET
Run Code Online (Sandbox Code Playgroud)
我再次尝试运行该程序,但出现了这个超级古怪的错误。
*** - 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.
Run Code Online (Sandbox Code Playgroud)
然后我从 Windows 收到一条错误消息,该消息以 lisp.exe 结尾,我不确定我做了什么,但是当十六进制出现时,我吓坏了。我环顾了论坛,但找不到使我的随机状态代码工作的解决方案,有人可以帮助我。
解决方案:而不是使用(current-time)
我使用的(make-random-state t)
,它工作得很好,所以我的问题得到了解决。
“ ...每次我运行程序时,它都会输出数字 3.... ” 调用的代码在哪里(random 3)
?(random 3)
重复调用应该返回 0 到 2 之间的随机数,包括 0 和 2,并且永远不应该返回 3。每次开始新会话时,您将获得相同的模式,除非您更改random
.
random
接受一个可选的随机状态参数;您不需要手动设置全局*random-state*
变量,但它可以很方便。在学习 Common Lisp(或任何新语言)时不要依赖你从其他语言中知道的东西,当你有问题时阅读文档。在 Common Lisp 中,随机状态不是整数;它是一个随机状态对象,您可以通过调用make-random-state
.
发布的代码调用(current-time)
并设置*random-state*
为返回值。现在,current-time
不是 Common Lisp 函数;它特定于 Clisp,它打印当前时间作为副作用,返回nil
. 设置*random-state*
为调用current-time
( nil
)的结果后,*random-state*
不再绑定随机状态对象,调用random
不再有效。这可能就是您的程序“失控”的原因。
这是一个示例函数,它返回 0 和n
(下面n
)之间的随机数列表:
(defun random-list (n max)
(loop for i from 1 to n
collecting (random max)))
Run Code Online (Sandbox Code Playgroud)
从 REPL 运行它以创建一个包含 0 和 2 之间的 10 个随机数的列表,包括 0 和 2,并使用默认随机状态。第一行显示 的值*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)
Run Code Online (Sandbox Code Playgroud)
可以看到,每次调用该函数时,都会生成不同的列表。这是因为随机状态 ( *random-state*
) 在对 的调用之间尚未重置random
。重新启动 REPL 并再次运行程序将产生完全相同的结果,因为随机状态被重置为其初始值:
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)
Run Code Online (Sandbox Code Playgroud)
再次重新启动,我们可以尝试setf
使用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)
Run Code Online (Sandbox Code Playgroud)
这没有按预期工作!我们得到了与使用默认随机状态时完全相同的结果;这是因为make-random-state
带nil
参数或不带参数调用会返回当前随机状态对象的副本。您可以调用make-random-state
witht
作为其参数来返回一个新的随机状态对象。请注意,这里的 Clisp 在调用之后打印了随机状态对象setf
;在 SBCL 中做同样的事情将导致一个非常不同的随机状态对象,它需要更多的行来打印。
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)
Run Code Online (Sandbox Code Playgroud)
现在可以看到*random-state*
已经设置为一个新的随机状态对象,生成的列表与之前的列表不同。