fork download
  1. # Random number generation based on code from GST-3.2.5 (2.02)
  2. # @see qmjAJh
  3.  
  4. class PiRandom
  5. def initialize
  6. self.seed(Time.now.to_f)
  7. end
  8.  
  9. def seed(value)
  10. @state = (value / 100000.0 + value) % 1.0
  11. self.rand
  12. self.rand
  13. end
  14.  
  15. def rand(*args)
  16. case args.size
  17. when 0
  18. @state = ((@state + Math::PI) ** 4) % 1.0
  19. when 1
  20. rand_with(args.first)
  21. else
  22. raise ArgumentError.new("wrong number of arguments "\
  23. "(given #{args.size}, expected 0..1)")
  24. end
  25. end
  26.  
  27. private def rand_with(arg)
  28. case arg
  29. when Float
  30. # [0, arg) exclusive.
  31. self.rand * [arg, 0].max
  32. when Integer
  33. # [0, arg] inclusive.
  34. rand_with(arg + 1.0).to_i
  35. when Range
  36. min = arg.min
  37. max = arg.max
  38. raise ArgumentError.new("invalid argument: #{arg}")\
  39. if min.nil? || max.nil?
  40. rand_with(max - min) + min
  41. else
  42. raise TypeError.new("no support for: #{arg.class}")
  43. end
  44. end
  45. end
  46.  
  47. # Test.
  48.  
  49. require "test/unit"
  50. extend Test::Unit::Assertions
  51.  
  52. def chi_square(n, r, prng)
  53. f = Array.new(r, 0)
  54. n.times do
  55. f[prng.rand(0...r)] += 1
  56. end
  57. t = f.sum {|x| x * x}
  58. r * t / n - n
  59. end
  60.  
  61. prng = PiRandom.new
  62.  
  63. # Distribution.
  64.  
  65. 5.times do
  66. p chi_square(1000, 100, prng)
  67. end
  68.  
  69. n = 100
  70.  
  71. # Canonical.
  72.  
  73. n.times do
  74. assert do
  75. t = prng.rand
  76. 0.0 <= t && t < 1.0
  77. end
  78. end
  79.  
  80. # Max.
  81.  
  82. n.times do
  83. assert do
  84. t = prng.rand(5)
  85. 0 <= t && t <= 5
  86. end
  87. assert do
  88. t = prng.rand(5.0)
  89. 0.0 <= t && t < 5.0
  90. end
  91. end
  92.  
  93. # Range.
  94.  
  95. n.times do
  96. assert do
  97. t = prng.rand(1..5)
  98. 1 <= t && t <= 5
  99. end
  100. assert do
  101. t = prng.rand(1...5)
  102. 1 <= t && t < 5
  103. end
  104. assert do
  105. t = prng.rand(1.0..5.0)
  106. 1.0 <= t && t < 5.0
  107. end
  108. end
Success #stdin #stdout 0.22s 13172KB
stdin
Standard input is empty
stdout
95
101
85
116
74