srfi-27.scm 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598
  1. ; MODULE DEFINITION FOR SRFI-27, C/SCHEME-IMPLEMENTATION
  2. ; ======================================================
  3. ;
  4. ; Copyright (C) Sebastian Egner (2002). All Rights Reserved.
  5. ;
  6. ; Permission is hereby granted, free of charge, to any person
  7. ; obtaining a copy of this software and associated documentation
  8. ; files (the "Software"), to deal in the Software without
  9. ; restriction, including without limitation the rights to use, copy,
  10. ; modify, merge, publish, distribute, sublicense, and/or sell copies
  11. ; of the Software, and to permit persons to whom the Software is
  12. ; furnished to do so, subject to the following conditions:
  13. ;
  14. ; The above copyright notice and this permission notice shall be
  15. ; included in all copies or substantial portions of the Software.
  16. ;
  17. ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  18. ; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  19. ; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  20. ; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  21. ; BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  22. ; ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  23. ; CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  24. ; SOFTWARE.
  25. ; Sebastian.Egner@philips.com, Mar-2002, in Scheme 48 0.57
  26. ;
  27. ; This file contains the top-level definition for the C-code
  28. ; implementation of SRFI-27 for the Scheme 48 0.57 system.
  29. ;
  30. ; 1. The core generator is implemented in 'mrg32k3a-b.c'.
  31. ; 2. The generic parts of the interface are in 'mrg32k3a.scm'.
  32. ; (they have now been merged into this file)
  33. ; 3. The non-generic parts (record type, time, error, C-bindings) are here.
  34. ;
  35. ; creating the module:
  36. ; copy mrg32k3a-b.c into $SCHEME48/c/srfi-27/mrg32k3a-b.c
  37. ; edit $SCHEME48/Makefile.in
  38. ; add c/srfi-27/mrg32k3a-b.o to EXTERNAL_OBJECTS
  39. ; add mrg32k3a_init to EXTERNAL_INITIALIZERS
  40. ; add the make line c/srfi-27/mrg32k3a-b.o: c/scheme48.h
  41. ; cd $SCHEME48
  42. ; make clean
  43. ; configure
  44. ; make
  45. ; cd $SRFI27
  46. ; ,config ,load srfi-27-b.scm
  47. ;
  48. ; loading the module, once created:
  49. ; ,open srfi-27
  50. ;
  51. ; history of this file:
  52. ; SE, 22-Mar-2002: initial version
  53. ; SE, 25-Mar-2002: initial version
  54. ; MG, September 2002: merged in mrg32k2a.scm, move package definitons to
  55. ; more-packages.scm, renamed from srfi-27-b.scm to srfi-27.scm
  56. (import-dynamic-externals "=scheme48external/srfi-27")
  57. (define-record-type :random-source
  58. (:random-source-make
  59. state-ref
  60. state-set!
  61. randomize!
  62. pseudo-randomize!
  63. make-integers
  64. make-reals)
  65. :random-source?
  66. (state-ref :random-source-state-ref)
  67. (state-set! :random-source-state-set!)
  68. (randomize! :random-source-randomize!)
  69. (pseudo-randomize! :random-source-pseudo-randomize!)
  70. (make-integers :random-source-make-integers)
  71. (make-reals :random-source-make-reals))
  72. (define (:random-source-current-time)
  73. (current-time))
  74. ;; interface to core generator
  75. (import-lambda-definition-2 mrg32k3a-pack-state1 (state))
  76. (import-lambda-definition-2 mrg32k3a-unpack-state1 (state))
  77. (import-lambda-definition-2 mrg32k3a-random-range ())
  78. (import-lambda-definition-2 mrg32k3a-random-integer (state range))
  79. (import-lambda-definition-2 mrg32k3a-random-real (state))
  80. (import-lambda-definition-2 current-time ())
  81. (define (mrg32k3a-pack-state state)
  82. (mrg32k3a-pack-state1
  83. (list->vector
  84. (apply append
  85. (map (lambda (x)
  86. (list (modulo x 65536)
  87. (quotient x 65536)))
  88. (vector->list state))))))
  89. (define (mrg32k3a-unpack-state state)
  90. (let ((s (mrg32k3a-unpack-state1 state)) (w 65536))
  91. (vector
  92. (+ (vector-ref s 0) (* (vector-ref s 1) w))
  93. (+ (vector-ref s 2) (* (vector-ref s 3) w))
  94. (+ (vector-ref s 4) (* (vector-ref s 5) w))
  95. (+ (vector-ref s 6) (* (vector-ref s 7) w))
  96. (+ (vector-ref s 8) (* (vector-ref s 9) w))
  97. (+ (vector-ref s 10) (* (vector-ref s 11) w)))))
  98. ; Start of former file mrg32k3a.scm
  99. ;
  100. ; GENERIC PART OF MRG32k3a-GENERATOR FOR SRFI-27
  101. ; ==============================================
  102. ;
  103. ; Sebastian.Egner@philips.com, 2002.
  104. ;
  105. ; This is the generic R5RS-part of the implementation of the MRG32k3a
  106. ; generator to be used in SRFI-27. It is based on a separate implementation
  107. ; of the core generator (presumably in native code) and on code to
  108. ; provide essential functionality not available in R5RS (see below).
  109. ;
  110. ; compliance:
  111. ; Scheme R5RS with integer covering at least {-2^53..2^53-1}.
  112. ; In addition,
  113. ; SRFI-23: error
  114. ;
  115. ; history of this file:
  116. ; SE, 22-Mar-2002: refactored from earlier versions
  117. ; SE, 25-Mar-2002: pack/unpack need not allocate
  118. ; SE, 27-Mar-2002: changed interface to core generator
  119. ; SE, 10-Apr-2002: updated spec of mrg32k3a-random-integer
  120. ; Generator
  121. ; =========
  122. ;
  123. ; Pierre L'Ecuyer's MRG32k3a generator is a Combined Multiple Recursive
  124. ; Generator. It produces the sequence {(x[1,n] - x[2,n]) mod m1 : n}
  125. ; defined by the two recursive generators
  126. ;
  127. ; x[1,n] = ( a12 x[1,n-2] + a13 x[1,n-3]) mod m1,
  128. ; x[2,n] = (a21 x[2,n-1] + a23 x[2,n-3]) mod m2,
  129. ;
  130. ; where the constants are
  131. ; m1 = 4294967087 = 2^32 - 209 modulus of 1st component
  132. ; m2 = 4294944443 = 2^32 - 22853 modulus of 2nd component
  133. ; a12 = 1403580 recursion coefficients
  134. ; a13 = -810728
  135. ; a21 = 527612
  136. ; a23 = -1370589
  137. ;
  138. ; The generator passes all tests of G. Marsaglia's Diehard testsuite.
  139. ; Its period is (m1^3 - 1)(m2^3 - 1)/2 which is nearly 2^191.
  140. ; L'Ecuyer reports: "This generator is well-behaved in all dimensions
  141. ; up to at least 45: ..." [with respect to the spectral test, SE].
  142. ;
  143. ; The period is maximal for all values of the seed as long as the
  144. ; state of both recursive generators is not entirely zero.
  145. ;
  146. ; As the successor state is a linear combination of previous
  147. ; states, it is possible to advance the generator by more than one
  148. ; iteration by applying a linear transformation. The following
  149. ; publication provides detailed information on how to do that:
  150. ;
  151. ; [1] P. L'Ecuyer, R. Simard, E. J. Chen, W. D. Kelton:
  152. ; An Object-Oriented Random-Number Package With Many Long
  153. ; Streams and Substreams. 2001.
  154. ; To appear in Operations Research.
  155. ;
  156. ; Arithmetics
  157. ; ===========
  158. ;
  159. ; The MRG32k3a generator produces values in {0..2^32-209-1}. All
  160. ; subexpressions of the actual generator fit into {-2^53..2^53-1}.
  161. ; The code below assumes that Scheme's "integer" covers this range.
  162. ; In addition, it is assumed that floating point literals can be
  163. ; read and there is some arithmetics with inexact numbers.
  164. ;
  165. ; However, for advancing the state of the generator by more than
  166. ; one step at a time, the full range {0..2^32-209-1} is needed.
  167. ; Required: Backbone Generator
  168. ; ============================
  169. ;
  170. ; At this point in the code, the following procedures are assumed
  171. ; to be defined to execute the core generator:
  172. ;
  173. ; (mrg32k3a-pack-state unpacked-state) -> packed-state
  174. ; (mrg32k3a-unpack-state packed-state) -> unpacked-state
  175. ; pack/unpack a state of the generator. The core generator works
  176. ; on packed states, passed as an explicit argument, only. This
  177. ; allows native code implementations to store their state in a
  178. ; suitable form. Unpacked states are #(x10 x11 x12 x20 x21 x22)
  179. ; with integer x_ij. Pack/unpack need not allocate new objects
  180. ; in case packed and unpacked states are identical.
  181. ;
  182. ; (mrg32k3a-random-range) -> m-max
  183. ; (mrg32k3a-random-integer packed-state range) -> x in {0..range-1}
  184. ; advance the state of the generator and return the next random
  185. ; range-limited integer.
  186. ; Note that the state is not necessarily advanced by just one
  187. ; step because we use the rejection method to avoid any problems
  188. ; with distribution anomalies.
  189. ; The range argument must be an exact integer in {1..m-max}.
  190. ; It can be assumed that range is a fixnum if the Scheme system
  191. ; has such a number representation.
  192. ;
  193. ; (mrg32k3a-random-real packed-state) -> x in (0,1)
  194. ; advance the state of the generator and return the next random
  195. ; real number between zero and one (both excluded). The type of
  196. ; the result should be a flonum if possible.
  197. ; Required: Record Data Type
  198. ; ==========================
  199. ;
  200. ; At this point in the code, the following procedures are assumed
  201. ; to be defined to create and access a new record data type:
  202. ;
  203. ; (:random-source-make a0 a1 a2 a3 a4 a5) -> s
  204. ; constructs a new random source object s consisting of the
  205. ; objects a0 .. a5 in this order.
  206. ;
  207. ; (:random-source? obj) -> bool
  208. ; tests if a Scheme object is a :random-source.
  209. ;
  210. ; (:random-source-state-ref s) -> a0
  211. ; (:random-source-state-set! s) -> a1
  212. ; (:random-source-randomize! s) -> a2
  213. ; (:random-source-pseudo-randomize! s) -> a3
  214. ; (:random-source-make-integers s) -> a4
  215. ; (:random-source-make-reals s) -> a5
  216. ; retrieve the values in the fields of the object s.
  217. ; Required: Current Time as an Integer
  218. ; ====================================
  219. ;
  220. ; At this point in the code, the following procedure is assumed
  221. ; to be defined to obtain a value that is likely to be different
  222. ; for each invokation of the Scheme system:
  223. ;
  224. ; (:random-source-current-time) -> x
  225. ; an integer that depends on the system clock. It is desired
  226. ; that the integer changes as fast as possible.
  227. ; Accessing the State
  228. ; ===================
  229. (define (mrg32k3a-state-ref packed-state)
  230. (cons 'lecuyer-mrg32k3a
  231. (vector->list (mrg32k3a-unpack-state packed-state))))
  232. (define (mrg32k3a-state-set external-state)
  233. (define (check-value x m)
  234. (if (and (integer? x)
  235. (exact? x)
  236. (<= 0 x (- m 1)))
  237. #t
  238. (error "illegal value" x)))
  239. (if (and (list? external-state)
  240. (= (length external-state) 7)
  241. (eq? (car external-state) 'lecuyer-mrg32k3a))
  242. (let ((s (cdr external-state)))
  243. (check-value (list-ref s 0) mrg32k3a-m1)
  244. (check-value (list-ref s 1) mrg32k3a-m1)
  245. (check-value (list-ref s 2) mrg32k3a-m1)
  246. (check-value (list-ref s 3) mrg32k3a-m2)
  247. (check-value (list-ref s 4) mrg32k3a-m2)
  248. (check-value (list-ref s 5) mrg32k3a-m2)
  249. (if (or (zero? (+ (list-ref s 0) (list-ref s 1) (list-ref s 2)))
  250. (zero? (+ (list-ref s 3) (list-ref s 4) (list-ref s 5))))
  251. (error "illegal degenerate state" external-state))
  252. (mrg32k3a-pack-state (list->vector s)))
  253. (error "malformed state" external-state)))
  254. ; Pseudo-Randomization
  255. ; ====================
  256. ;
  257. ; Reference [1] above shows how to obtain many long streams and
  258. ; substream from the backbone generator.
  259. ;
  260. ; The idea is that the generator is a linear operation on the state.
  261. ; Hence, we can express this operation as a 3x3-matrix acting on the
  262. ; three most recent states. Raising the matrix to the k-th power, we
  263. ; obtain the operation to advance the state by k steps at once. The
  264. ; virtual streams and substreams are now simply parts of the entire
  265. ; periodic sequence (which has period around 2^191).
  266. ;
  267. ; For the implementation it is necessary to compute with matrices in
  268. ; the ring (Z/(m1*m1)*Z)^(3x3). By the Chinese-Remainder Theorem, this
  269. ; is isomorphic to ((Z/m1*Z) x (Z/m2*Z))^(3x3). We represent such a pair
  270. ; of matrices
  271. ; [ [[x00 x01 x02],
  272. ; [x10 x11 x12],
  273. ; [x20 x21 x22]], mod m1
  274. ; [[y00 y01 y02],
  275. ; [y10 y11 y12],
  276. ; [y20 y21 y22]] mod m2]
  277. ; as a vector of length 18 of the integers as writen above:
  278. ; #(x00 x01 x02 x10 x11 x12 x20 x21 x22
  279. ; y00 y01 y02 y10 y11 y12 y20 y21 y22)
  280. ;
  281. ; As the implementation should only use the range {-2^53..2^53-1}, the
  282. ; fundamental operation (x*y) mod m, where x, y, m are nearly 2^32,
  283. ; is computed by breaking up x and y as x = x1*w + x0 and y = y1*w + y0
  284. ; where w = 2^16. In this case, all operations fit the range because
  285. ; w^2 mod m is a small number. If proper multiprecision integers are
  286. ; available this is not necessary, but pseudo-randomize! is an expected
  287. ; to be called only occasionally so we do not provide this implementation.
  288. (define mrg32k3a-m1 4294967087) ; modulus of component 1
  289. (define mrg32k3a-m2 4294944443) ; modulus of component 2
  290. (define mrg32k3a-initial-state ; 0 3 6 9 12 15 of A^16, see below
  291. '#( 1062452522
  292. 2961816100
  293. 342112271
  294. 2854655037
  295. 3321940838
  296. 3542344109))
  297. (define mrg32k3a-generators #f) ; computed when needed
  298. (define (mrg32k3a-pseudo-randomize-state i j)
  299. (define (product A B) ; A*B in ((Z/m1*Z) x (Z/m2*Z))^(3x3)
  300. (define w 65536) ; wordsize to split {0..2^32-1}
  301. (define w-sqr1 209) ; w^2 mod m1
  302. (define w-sqr2 22853) ; w^2 mod m2
  303. (define (lc i0 i1 i2 j0 j1 j2 m w-sqr) ; linear combination
  304. (let ((a0h (quotient (vector-ref A i0) w))
  305. (a0l (modulo (vector-ref A i0) w))
  306. (a1h (quotient (vector-ref A i1) w))
  307. (a1l (modulo (vector-ref A i1) w))
  308. (a2h (quotient (vector-ref A i2) w))
  309. (a2l (modulo (vector-ref A i2) w))
  310. (b0h (quotient (vector-ref B j0) w))
  311. (b0l (modulo (vector-ref B j0) w))
  312. (b1h (quotient (vector-ref B j1) w))
  313. (b1l (modulo (vector-ref B j1) w))
  314. (b2h (quotient (vector-ref B j2) w))
  315. (b2l (modulo (vector-ref B j2) w)))
  316. (modulo
  317. (+ (* (+ (* a0h b0h)
  318. (* a1h b1h)
  319. (* a2h b2h))
  320. w-sqr)
  321. (* (+ (* a0h b0l)
  322. (* a0l b0h)
  323. (* a1h b1l)
  324. (* a1l b1h)
  325. (* a2h b2l)
  326. (* a2l b2h))
  327. w)
  328. (* a0l b0l)
  329. (* a1l b1l)
  330. (* a2l b2l))
  331. m)))
  332. (vector
  333. (lc 0 1 2 0 3 6 mrg32k3a-m1 w-sqr1) ; (A*B)_00 mod m1
  334. (lc 0 1 2 1 4 7 mrg32k3a-m1 w-sqr1) ; (A*B)_01
  335. (lc 0 1 2 2 5 8 mrg32k3a-m1 w-sqr1)
  336. (lc 3 4 5 0 3 6 mrg32k3a-m1 w-sqr1) ; (A*B)_10
  337. (lc 3 4 5 1 4 7 mrg32k3a-m1 w-sqr1)
  338. (lc 3 4 5 2 5 8 mrg32k3a-m1 w-sqr1)
  339. (lc 6 7 8 0 3 6 mrg32k3a-m1 w-sqr1)
  340. (lc 6 7 8 1 4 7 mrg32k3a-m1 w-sqr1)
  341. (lc 6 7 8 2 5 8 mrg32k3a-m1 w-sqr1)
  342. (lc 9 10 11 9 12 15 mrg32k3a-m2 w-sqr2) ; (A*B)_00 mod m2
  343. (lc 9 10 11 10 13 16 mrg32k3a-m2 w-sqr2)
  344. (lc 9 10 11 11 14 17 mrg32k3a-m2 w-sqr2)
  345. (lc 12 13 14 9 12 15 mrg32k3a-m2 w-sqr2)
  346. (lc 12 13 14 10 13 16 mrg32k3a-m2 w-sqr2)
  347. (lc 12 13 14 11 14 17 mrg32k3a-m2 w-sqr2)
  348. (lc 15 16 17 9 12 15 mrg32k3a-m2 w-sqr2)
  349. (lc 15 16 17 10 13 16 mrg32k3a-m2 w-sqr2)
  350. (lc 15 16 17 11 14 17 mrg32k3a-m2 w-sqr2)))
  351. (define (power A e) ; A^e
  352. (cond
  353. ((zero? e)
  354. '#(1 0 0 0 1 0 0 0 1 1 0 0 0 1 0 0 0 1))
  355. ((= e 1)
  356. A)
  357. ((even? e)
  358. (power (product A A) (quotient e 2)))
  359. (else
  360. (product (power A (- e 1)) A))))
  361. (define (power-power A b) ; A^(2^b)
  362. (if (zero? b)
  363. A
  364. (power-power (product A A) (- b 1))))
  365. (define A ; the MRG32k3a recursion
  366. '#( 0 1403580 4294156359
  367. 1 0 0
  368. 0 1 0
  369. 527612 0 4293573854
  370. 1 0 0
  371. 0 1 0))
  372. ; check arguments
  373. (if (not (and (integer? i)
  374. (exact? i)
  375. (integer? j)
  376. (exact? j)))
  377. (error "i j must be exact integer" i j))
  378. ; precompute A^(2^127) and A^(2^76) only once
  379. (if (not mrg32k3a-generators)
  380. (set! mrg32k3a-generators
  381. (list (power-power A 127)
  382. (power-power A 76)
  383. (power A 16))))
  384. ; compute M = A^(16 + i*2^127 + j*2^76)
  385. (let ((M (product
  386. (list-ref mrg32k3a-generators 2)
  387. (product
  388. (power (list-ref mrg32k3a-generators 0)
  389. (modulo i (expt 2 28)))
  390. (power (list-ref mrg32k3a-generators 1)
  391. (modulo j (expt 2 28)))))))
  392. (mrg32k3a-pack-state
  393. (vector
  394. (vector-ref M 0)
  395. (vector-ref M 3)
  396. (vector-ref M 6)
  397. (vector-ref M 9)
  398. (vector-ref M 12)
  399. (vector-ref M 15)))))
  400. ; True Randomization
  401. ; ==================
  402. ;
  403. ; The value obtained from the system time is feed into a very
  404. ; simple pseudo random number generator. This in turn is used
  405. ; to obtain numbers to randomize the state of the MRG32k3a
  406. ; generator, avoiding period degeneration.
  407. (define (mrg32k3a-randomize-state state)
  408. ;; G. Marsaglia's simple 16-bit generator with carry
  409. (let* ((m 65536)
  410. (x (modulo (:random-source-current-time) m)))
  411. (define (random-m)
  412. (let ((y (modulo x m)))
  413. (set! x (+ (* 30903 y) (quotient x m)))
  414. y))
  415. (define (random n) ; m < n < m^2
  416. (modulo (+ (* (random-m) m) (random-m)) n))
  417. ; modify the state
  418. (let ((m1 mrg32k3a-m1)
  419. (m2 mrg32k3a-m2)
  420. (s (mrg32k3a-unpack-state state)))
  421. (mrg32k3a-pack-state
  422. (vector
  423. (+ 1 (modulo (+ (vector-ref s 0) (random (- m1 1))) (- m1 1)))
  424. (modulo (+ (vector-ref s 1) (random m1)) m1)
  425. (modulo (+ (vector-ref s 2) (random m1)) m1)
  426. (+ 1 (modulo (+ (vector-ref s 3) (random (- m2 1))) (- m2 1)))
  427. (modulo (+ (vector-ref s 4) (random m2)) m2)
  428. (modulo (+ (vector-ref s 5) (random m2)) m2))))))
  429. ; Large Integers
  430. ; ==============
  431. ;
  432. ; To produce large integer random deviates, for n > m-max, we first
  433. ; construct large random numbers in the range {0..m-max^k-1} for some
  434. ; k such that m-max^k >= n and then use the rejection method to choose
  435. ; uniformly from the range {0..n-1}.
  436. (define mrg32k3a-m-max
  437. (mrg32k3a-random-range))
  438. (define (mrg32k3a-random-power state k) ; n = m-max^k, k >= 1
  439. (if (= k 1)
  440. (mrg32k3a-random-integer state mrg32k3a-m-max)
  441. (+ (* (mrg32k3a-random-power state (- k 1)) mrg32k3a-m-max)
  442. (mrg32k3a-random-integer state mrg32k3a-m-max))))
  443. (define (mrg32k3a-random-large state n) ; n > m-max
  444. (do ((k 2 (+ k 1))
  445. (mk (* mrg32k3a-m-max mrg32k3a-m-max) (* mk mrg32k3a-m-max)))
  446. ((>= mk n)
  447. (let* ((mk-by-n (quotient mk n))
  448. (a (* mk-by-n n)))
  449. (do ((x (mrg32k3a-random-power state k)
  450. (mrg32k3a-random-power state k)))
  451. ((< x a) (quotient x mk-by-n)))))))
  452. ; Multiple Precision Reals
  453. ; ========================
  454. ;
  455. ; To produce multiple precision reals we produce a large integer value
  456. ; and convert it into a real value. This value is then normalized.
  457. ; The precision goal is unit <= 1/(m^k + 1), or 1/unit - 1 <= m^k.
  458. ; If you know more about the floating point number types of the
  459. ; Scheme system, this can be improved.
  460. (define (mrg32k3a-random-real-mp state unit)
  461. (do ((k 1 (+ k 1))
  462. (u (- (/ 1 unit) 1) (/ u mrg32k3a-m1)))
  463. ((<= u 1)
  464. (/ (exact->inexact (+ (mrg32k3a-random-power state k) 1))
  465. (exact->inexact (+ (expt mrg32k3a-m-max k) 1))))))
  466. ; Provide the Interface as Specified in the SRFI
  467. ; ==============================================
  468. ;
  469. ; An object of type random-source is a record containing the procedures
  470. ; as components. The actual state of the generator is stored in the
  471. ; binding-time environment of make-random-source.
  472. (define (make-random-source)
  473. (let ((state (mrg32k3a-pack-state ; make a new copy
  474. (list->vector (vector->list mrg32k3a-initial-state)))))
  475. (:random-source-make
  476. (lambda ()
  477. (mrg32k3a-state-ref state))
  478. (lambda (new-state)
  479. (set! state (mrg32k3a-state-set new-state)))
  480. (lambda ()
  481. (set! state (mrg32k3a-randomize-state state)))
  482. (lambda (i j)
  483. (set! state (mrg32k3a-pseudo-randomize-state i j)))
  484. (lambda ()
  485. (lambda (n)
  486. (cond
  487. ((not (and (integer? n) (exact? n) (positive? n)))
  488. (error "range must be exact positive integer" n))
  489. ((<= n mrg32k3a-m-max)
  490. (mrg32k3a-random-integer state n))
  491. (else
  492. (mrg32k3a-random-large state n)))))
  493. (lambda args
  494. (cond
  495. ((null? args)
  496. (lambda ()
  497. (mrg32k3a-random-real state)))
  498. ((null? (cdr args))
  499. (let ((unit (car args)))
  500. (cond
  501. ((not (and (real? unit) (< 0 unit 1)))
  502. (error "unit must be real in (0,1)" unit))
  503. ((<= (- (/ 1 unit) 1) mrg32k3a-m1)
  504. (lambda ()
  505. (mrg32k3a-random-real state)))
  506. (else
  507. (lambda ()
  508. (mrg32k3a-random-real-mp state unit))))))
  509. (else
  510. (error "illegal arguments" args)))))))
  511. (define random-source?
  512. :random-source?)
  513. (define (random-source-state-ref s)
  514. ((:random-source-state-ref s)))
  515. (define (random-source-state-set! s state)
  516. ((:random-source-state-set! s) state))
  517. (define (random-source-randomize! s)
  518. ((:random-source-randomize! s)))
  519. (define (random-source-pseudo-randomize! s i j)
  520. ((:random-source-pseudo-randomize! s) i j))
  521. ; ---
  522. (define (random-source-make-integers s)
  523. ((:random-source-make-integers s)))
  524. (define (random-source-make-reals s . unit)
  525. (apply (:random-source-make-reals s) unit))
  526. ; ---
  527. (define default-random-source
  528. (make-random-source))
  529. (define random-integer
  530. (random-source-make-integers default-random-source))
  531. (define random-real
  532. (random-source-make-reals default-random-source))