srfi-27.scm 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. ;;; srfi-27.scm --- Sources of Random Bits
  2. ;; Copyright (C) 2010 Free Software Foundation, Inc.
  3. ;; This library is free software; you can redistribute it and/or
  4. ;; modify it under the terms of the GNU Lesser General Public
  5. ;; License as published by the Free Software Foundation; either
  6. ;; version 3 of the License, or (at your option) any later version.
  7. ;; This library is distributed in the hope that it will be useful,
  8. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  10. ;; Lesser General Public License for more details.
  11. ;; You should have received a copy of the GNU Lesser General Public
  12. ;; License along with this library. If not, see
  13. ;; <http://www.gnu.org/licenses/>.
  14. ;;; Commentary:
  15. ;; This module is fully documented in the Guile Reference Manual.
  16. ;;; Code:
  17. (define-module (srfi srfi-27)
  18. #:export (random-integer
  19. random-real
  20. default-random-source
  21. make-random-source
  22. random-source?
  23. random-source-state-ref
  24. random-source-state-set!
  25. random-source-randomize!
  26. random-source-pseudo-randomize!
  27. random-source-make-integers
  28. random-source-make-reals)
  29. #:use-module (srfi srfi-9))
  30. (cond-expand-provide (current-module) '(srfi-27))
  31. (define-record-type :random-source
  32. (%make-random-source state)
  33. random-source?
  34. (state random-source-state set-random-source-state!))
  35. (define (make-random-source)
  36. (%make-random-source (seed->random-state 0)))
  37. (define (random-source-state-ref s)
  38. (random-state->datum (random-source-state s)))
  39. (define (random-source-state-set! s state)
  40. (set-random-source-state! s (datum->random-state state)))
  41. (define (random-source-randomize! s)
  42. (let ((time (gettimeofday)))
  43. (set-random-source-state! s (seed->random-state
  44. (+ (* (car time) 1e6) (cdr time))))))
  45. (define (random-source-pseudo-randomize! s i j)
  46. (set-random-source-state! s (seed->random-state (i+j->seed i j))))
  47. (define (i+j->seed i j)
  48. (logior (ash (spread i 2) 1)
  49. (spread j 2)))
  50. (define (spread n amount)
  51. (let loop ((result 0) (n n) (shift 0))
  52. (if (zero? n)
  53. result
  54. (loop (logior result
  55. (ash (logand n 1) shift))
  56. (ash n -1)
  57. (+ shift amount)))))
  58. (define (random-source-make-integers s)
  59. (lambda (n)
  60. (random n (random-source-state s))))
  61. (define random-source-make-reals
  62. (case-lambda
  63. ((s)
  64. (lambda ()
  65. (let loop ()
  66. (let ((x (random:uniform (random-source-state s))))
  67. (if (zero? x)
  68. (loop)
  69. x)))))
  70. ((s unit)
  71. (or (and (real? unit) (< 0 unit 1))
  72. (error "unit must be real between 0 and 1" unit))
  73. (random-source-make-reals s))))
  74. (define default-random-source (make-random-source))
  75. (define random-integer (random-source-make-integers default-random-source))
  76. (define random-real (random-source-make-reals default-random-source))