标准方案不提供随机数生成器,虽然大多数Scheme实现提供了一个,但它们的细节往往不同.如果你想编写一个便携式的Scheme程序,很容易建立你自己的随机数生成器; 这是Knuth的方法:
(define random
(let ((a 69069) (c 1) (m (expt 2 32)) (seed 19380110))
(lambda new-seed
(if (pair? new-seed)
(set! seed (car new-seed))
(set! seed (modulo (+ (* seed a) c) m)))
(/ seed m))))
Run Code Online (Sandbox Code Playgroud)
调用(random)返回0(包括)和1(不包括)之间的随机分数.随机分数以周期m循环.调用(random seed)重置随机数生成器的种子,使得从相同种子开始的两个随机序列将是相同的; YYYYMMDD形式的日期是好种子(那是Knuth的生日).如果你想翻转硬币,请说:(if (< (random) 1/2) 'heads 'tails).
有时你想要一个范围内的随机整数.下面randint显示的函数返回范围lo(包括)到hi(不包括)的随机整数; lo默认为0:
(define (randint . args)
(cond ((= (length args) 1)
(floor (* (random) (car args))))
((= (length args) 2)
(+ (car args) (floor (* (random) (- (cadr args) (car args))))))
(else (error 'randint "usage: (randint [lo] hi)"))))
Run Code Online (Sandbox Code Playgroud)
诸如此类的随机数对于简单模拟来说足够好,但要注意它们不适用于加密应用程序.如果您有兴趣,我的博客上有几个随机数生成器,包括一些适用于加密应用程序的生成器.
令人惊讶的是,该过程被调用了random- 虽然确切的语法可能会有所不同,具体取决于使用的Scheme解释器(阅读文档!),但总体思路如下:
(random)
=> 0.9113789707345018
Run Code Online (Sandbox Code Playgroud)
要返回两个可能值中的一个,这将在Racket中完成:
(define (random-choice a b)
(if (zero? (random 2)) a b))
Run Code Online (Sandbox Code Playgroud)
请注意,2传递的参数random强制它随机返回两个可能的值之一:0或1.所以,如果(random 2)到求值0,然后a返回,否则b返回.
(random-choice 4 2)
=> 4
(random-choice 4 2)
=> 2
Run Code Online (Sandbox Code Playgroud)