fibonacci_rng 1.2.5 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4999cbec6a694cd39c97612604da2d3aef472ebc
4
- data.tar.gz: 6615b8208ac015d76658f2b07cb4509832342e5c
3
+ metadata.gz: dff4345e5771a9194053e94d27556d1fee55e67c
4
+ data.tar.gz: 719c15db8a33d8308a41175ea371923e55d3352f
5
5
  SHA512:
6
- metadata.gz: 77e649c937622ba4b341ce2d2da7a98a46a030455f323a93fcf21382302ce5306fcb3135ef730fc83681abc2d888747124dd82ddae664602540c9f8b15094ede
7
- data.tar.gz: 43afbd3b1ae190f3c50f91ad01c41d238709bbbc456a9b46d77a91a98fb728a51339a69d69055286d0e47d7ef2a2c3866c43d5009798b70c968b2f1daa2a6f46
6
+ metadata.gz: 11c14fa2466aaffdc31e98f67c6d930c204e27dbc1c2c5f43efa7bfba111912f4ee24c993b7850ed0396697016aa1189704c0130cebadf1795bd49e8f1d6251c
7
+ data.tar.gz: dd5df2c9398baeb1fd6b25c5ee499895c5125fd910c03f2ad87dd7f47019b72fabe92939564b2db17ac361f7641eccb54088cef52cee6b0e94c0611c45793819
data/README.md CHANGED
@@ -268,6 +268,27 @@ TOP = 0x10000000
268
268
 
269
269
  ```
270
270
 
271
+ ## Error Detection
272
+
273
+ Like all systems, the fibonacci random number generator has a failure mode. If
274
+ it should happen that all the internal data registers have a value of zero, the
275
+ generator will be trapped in an endless state of zero output. It will cease to
276
+ operate as a pseudo random number generator.
277
+
278
+ While it is possible to show that this cannot occur in small generators, the
279
+ case for larger ones is more difficult to analyze. To this end, the code now
280
+ incorporates a test that at least one non-zero register is present. If this
281
+ test should fail an exception "InvalidFibonacciRngState" is raised so that
282
+ the application can take appropriate action.
283
+
284
+ To date, torture testing of the generator has yielded no failures, but this is
285
+ not a proof that one cannot happen.
286
+
287
+ The test scans the registers until it finds a non-zero value. This means that
288
+ it almost always only needs to look at one register, saving a great deal of
289
+ execution time.
290
+
291
+
271
292
  ## Contributing
272
293
 
273
294
  Creating a good pseudo random number generator is quite an undertaking. For
@@ -9,10 +9,9 @@ Gem::Specification.new do |spec|
9
9
  spec.authors = ["Peter Camilleri"]
10
10
  spec.email = ["peter.c.camilleri@gmail.com"]
11
11
  spec.homepage = "https://github.com/PeterCamilleri/fibonacci_rng"
12
- spec.description = "A Fibonacci inspired pseudo random number generator. " +
13
- "[Updated] The algorithm is changed to use bit rotate " +
14
- "instead of bit shift."
15
- spec.summary = "[Updated] A Fibonacci inspired pseudo random number generator."
12
+ spec.description = "A Fibonacci inspired pseudo random number generator " +
13
+ "with error detection."
14
+ spec.summary = "A Fibonacci inspired pseudo random number generator."
16
15
  spec.license = "MIT"
17
16
 
18
17
  raw_list = `git ls-files`.split($/)
@@ -20,7 +19,7 @@ Gem::Specification.new do |spec|
20
19
 
21
20
  spec.files = raw_list
22
21
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
23
- spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
22
+ spec.test_files = spec.files.grep(%r{^(test)/})
24
23
  spec.require_paths = ["lib"]
25
24
 
26
25
  spec.required_ruby_version = '>= 1.9.3'
@@ -4,6 +4,7 @@ require_relative "fibonacci_rng/seeder"
4
4
  require_relative "fibonacci_rng/hasher"
5
5
  require_relative "fibonacci_rng/spinner"
6
6
  require_relative "fibonacci_rng/generator"
7
+ require_relative "fibonacci_rng/validate"
7
8
  require_relative "fibonacci_rng/version"
8
9
 
9
10
  #The class of Fibonacci inspired random number generators.
@@ -25,12 +25,14 @@ class FibonacciRng
25
25
  do_spin
26
26
  end until (value = @buffer[0]) < limit
27
27
 
28
+ validate
28
29
  value % sides
29
30
  end
30
31
 
31
32
  #Get a pseudo random byte
32
33
  def byte
33
34
  do_spin
35
+ validate
34
36
  @buffer[0] & BYTE
35
37
  end
36
38
 
@@ -44,12 +46,14 @@ class FibonacciRng
44
46
  #Get a pseudo random word
45
47
  def word
46
48
  do_spin
49
+ validate
47
50
  @buffer[0] & WORD
48
51
  end
49
52
 
50
53
  #Get a pseudo random float
51
54
  def float
52
55
  do_spin
56
+ validate
53
57
  raw_float / BASE
54
58
  end
55
59
 
@@ -58,6 +62,7 @@ class FibonacciRng
58
62
  do_spin
59
63
  part_one = raw_float * BASE
60
64
  do_spin
65
+ validate
61
66
  (part_one + raw_float) / DOUBLE
62
67
  end
63
68
 
@@ -22,6 +22,7 @@ class FibonacciRng
22
22
  end
23
23
 
24
24
  do_spin if str.empty?
25
+ validate
25
26
  end
26
27
 
27
28
  private
@@ -32,6 +33,7 @@ class FibonacciRng
32
33
  do_spin
33
34
  @buffer[index] += value
34
35
  do_spin
36
+ validate
35
37
  end
36
38
 
37
39
  end
@@ -8,6 +8,8 @@ class FibonacciRng
8
8
  count.times do
9
9
  do_spin
10
10
  end
11
+
12
+ validate
11
13
  end
12
14
 
13
15
  private
@@ -0,0 +1,18 @@
1
+ # coding: utf-8
2
+
3
+ # The class of RNG errors.
4
+ class InvalidFibonacciRngState < RuntimeError; end
5
+
6
+ #The class of Fibonacci inspired random number generators.
7
+ class FibonacciRng
8
+
9
+ #Validate the sanity of the generator.
10
+ def validate
11
+ @buffer.each do |element|
12
+ return true unless element.zero?
13
+ end
14
+
15
+ fail InvalidFibonacciRngState
16
+ end
17
+
18
+ end
@@ -2,5 +2,5 @@
2
2
 
3
3
  #The class of Fibonacci inspired random number generators.
4
4
  class FibonacciRng
5
- VERSION = "1.2.5"
5
+ VERSION = "2.0.0"
6
6
  end
data/prng.rb CHANGED
@@ -21,7 +21,7 @@ module PrngTestSuite
21
21
  puts "Where:"
22
22
  puts " <locn> fib code location, either 'gem' or 'local'"
23
23
  puts " <gen> select a generator, either 'fib' or 'int'"
24
- puts " <test> select a test, either 'chisq', 'auto', or 'scatter'"
24
+ puts " <test> select one of 'chisq', 'auto', 'scatter', or 'torture'"
25
25
  puts " <max> the number of bins to test (2..65535)"
26
26
  puts " <count> the number of samples to test (1..1000000)"
27
27
  puts
@@ -45,6 +45,7 @@ require_relative 'tools/internal_rng'
45
45
  require_relative 'tools/chi_squared'
46
46
  require_relative 'tools/auto_corr'
47
47
  require_relative 'tools/scatter_plot'
48
+ require_relative 'tools/torture_test'
48
49
 
49
50
  module PrngTestSuite
50
51
 
@@ -63,6 +64,8 @@ module PrngTestSuite
63
64
  tester = AutoCorrelator.new
64
65
  elsif ARGV[2] == 'scatter'
65
66
  tester = ScatterPlot.new
67
+ elsif ARGV[2] == 'torture'
68
+ tester = TortureTest.new
66
69
  else
67
70
  PrngTestSuite.usage "Error: missing or invalid test parameter."
68
71
  end
@@ -1,251 +1,289 @@
1
- # coding: utf-8
2
-
3
- require_relative '../lib/fibonacci_rng'
4
- gem 'minitest'
5
- require 'minitest/autorun'
6
- require 'minitest_visible'
7
-
8
- #Test the monkey patches applied to the Object class.
9
- class FibonacciRngTester < Minitest::Test
10
-
11
- #Track mini-test progress.
12
- include MinitestVisible
13
-
14
- def test_how_we_build_generators
15
- gen = FibonacciRng.new
16
- assert_equal(8, gen.depth)
17
- assert_equal(String, gen.seed.class)
18
- assert_equal(1024, gen.init)
19
-
20
- gen = FibonacciRng.new('seed')
21
- assert_equal(8, gen.depth)
22
- assert_equal('seed', gen.seed)
23
- assert_equal(1024, gen.init)
24
-
25
- gen = FibonacciRng.new('seed', 12)
26
- assert_equal(12, gen.depth)
27
- assert_equal('seed', gen.seed)
28
- assert_equal(1152, gen.init)
29
-
30
- gen = FibonacciRng.new('seed', 12, 2048)
31
- assert_equal(12, gen.depth)
32
- assert_equal('seed', gen.seed)
33
- assert_equal(2048, gen.init)
34
- end
35
-
36
- def test_building_with_keywords
37
- gen = FibonacciRng.new(seed: 'seed')
38
- assert_equal(8, gen.depth)
39
- assert_equal('seed', gen.seed)
40
- assert_equal(1024, gen.init)
41
-
42
- gen = FibonacciRng.new(depth: 12)
43
- assert_equal(12, gen.depth)
44
- assert_equal(String, gen.seed.class)
45
- assert_equal(1152, gen.init)
46
-
47
- gen = FibonacciRng.new(seed: 'seed', depth: 12)
48
- assert_equal(12, gen.depth)
49
- assert_equal('seed', gen.seed)
50
- assert_equal(1152, gen.init)
51
-
52
- gen = FibonacciRng.new(depth: 12, seed: 'seed')
53
- assert_equal(12, gen.depth)
54
- assert_equal('seed', gen.seed)
55
- assert_equal(1152, gen.init)
56
-
57
- gen = FibonacciRng.new(seed: 'seed', init: 2048)
58
- assert_equal('seed', gen.seed)
59
- assert_equal(2048, gen.init)
60
- end
61
-
62
- def test_that_rejects_bad_parms
63
- assert_raises { FibonacciRng.new('seed', 1) }
64
- assert_raises { FibonacciRng.new('seed', 65536) }
65
- end
66
-
67
- def test_that_it_creates_dice_rolls
68
- prng = FibonacciRng.new
69
-
70
- 100.times do
71
- assert((0...6) === prng.dice(6))
72
- end
73
- end
74
-
75
- def test_that_it_creates_bytes
76
- prng = FibonacciRng.new
77
-
78
- 100.times do
79
- assert((0...256) === prng.byte)
80
- end
81
- end
82
-
83
- def test_that_it_creates_words
84
- prng = FibonacciRng.new
85
-
86
- 100.times do
87
- assert((0...65536) === prng.word)
88
- end
89
- end
90
-
91
- def test_that_it_creates_floats
92
- prng = FibonacciRng.new
93
-
94
- 100.times do
95
- value = prng.float
96
- assert((value >= 0.0) && (value < 1.0))
97
- end
98
- end
99
-
100
- def test_compatible_global_dice_rolls
101
- 100.times do
102
- assert((0...6) === FibonacciRng.rand(6))
103
- end
104
- end
105
-
106
- def test_compatible_global_dice_rolls_range
107
- 100.times do
108
- assert((0...6) === FibonacciRng.rand(0...6))
109
- end
110
- end
111
-
112
- def test_compatible_global_floats
113
- 100.times do
114
- value = FibonacciRng.rand(0)
115
- assert((value >= 0.0) && (value < 1.0))
116
- end
117
- end
118
-
119
- def test_random_string
120
- prng = FibonacciRng.new
121
-
122
- rs = prng.bytes(10)
123
-
124
- assert(rs.is_a?(String))
125
- assert_equal(10, rs.length)
126
- end
127
-
128
- def test_that_it_makes_unique_sequences
129
- prnga = FibonacciRng.new
130
- prngb = FibonacciRng.new
131
-
132
- buffa = []
133
- buffb = []
134
-
135
- 100.times do
136
- buffa << prnga.dice(6)
137
- buffb << prngb.dice(6)
138
- end
139
-
140
- assert(buffa != buffb)
141
- end
142
-
143
- def test_that_it_makes_repeatable_sequences
144
- prnga = FibonacciRng.new(0)
145
- prngb = FibonacciRng.new(0)
146
-
147
- buffa = []
148
- buffb = []
149
-
150
- 100.times do
151
- buffa << prnga.dice(6)
152
- buffb << prngb.dice(6)
153
- end
154
-
155
- assert(buffa == buffb)
156
- end
157
-
158
- def test_that_it_creates_unique_seeds
159
- result = []
160
- 10_000.times do
161
- result << FibonacciRng.new_seed
162
- end
163
-
164
- result.uniq!
165
- assert_equal(10_000, result.length)
166
- end
167
-
168
- def test_building_strings
169
- rng = FibonacciRng.new(0)
170
- assert_equal("c}l'(q@g\\z", rng.string(10))
171
- assert_equal('2727573312', rng.string(10, '0123456789'))
172
- assert_equal('khto lk si', rng.string(10, 'Always look on the bright side of life.'))
173
-
174
- rng = FibonacciRng.new("%s*08^_Tg{NnirtZ-94)q9z2l+~bB5")
175
- assert_equal(",-+Idi6~ ~", rng.string(10))
176
- assert_equal('5901964804', rng.string(10, '0123456789'))
177
- end
178
-
179
- def test_for_data_stability
180
- #Make sure incompatibilities do not creep in.
181
- expected = [184, 93, 0, 240, 34, 184, 4, 220, 126, 132,
182
- 13, 67, 166, 107, 165, 66, 68, 120, 102, 110,
183
- 212, 99, 80, 167, 9, 56, 47, 167, 127, 195,
184
- 169, 34, 184, 97, 136, 176, 214, 104, 218, 103,
185
- 180, 16, 83, 204, 128, 81, 63, 56, 237, 165,
186
- 0, 88, 129, 40, 152, 44, 189, 35, 205, 249,
187
- 77, 94, 142, 18, 60, 248, 49, 172, 235, 83,
188
- 84, 65, 181, 117, 16, 170, 222, 97, 130, 217]
189
-
190
- prng = FibonacciRng.new("%s*08^_Tg{NnirtZ-94)q9z2l+~bB5")
191
- result = Array.new(80) { prng.byte }
192
- assert_equal(expected, result)
193
-
194
- prng.reseed("%s*08^_Tg{NnirtZ-94)q9z2l+~bB5")
195
- result = Array.new(80) { prng.byte }
196
- assert_equal(expected, result)
197
-
198
-
199
- expected = [0.466758593916893, 0.8060004059225321,
200
- 0.8063845634460449, 0.8676037490367889,
201
- 0.350975576788187, 0.2556227296590805,
202
- 0.4873242452740669, 0.07484667748212814,
203
- 0.2968141995370388, 0.5417192056775093,
204
- 0.4288134817034006, 0.26460993848741055,
205
- 0.13613684102892876, 0.27074786089360714,
206
- 0.11685592867434025, 0.814235333353281,
207
- 0.6137734726071358, 0.9152738898992538,
208
- 0.6325213424861431, 0.22782298550009727,
209
- 0.6877559795975685, 0.9354030545800924,
210
- 0.18385234475135803, 0.5579136144369841,
211
- 0.7501311469823122, 0.04208622872829437,
212
- 0.31922253780066967, 0.6471036206930876,
213
- 0.4305369835346937, 0.2239683922380209,
214
- 0.9770196247845888, 0.3727417625486851]
215
-
216
- prng.reseed("%s*08^_Tg{NnirtZ-94)q9z2l+~bB5")
217
- result = Array.new(32) { prng.float }
218
- #assert_equal(expected, result)
219
-
220
- (0...32).each do |i|
221
- assert_in_delta(expected[i], result[i], 1.0e-16)
222
- end
223
-
224
- expected = [0.46675859541818576, 0.8063845650620829,
225
- 0.3509755772643215, 0.48732424541347974,
226
- 0.29681420054606944, 0.428813482196275,
227
- 0.13613684153323594, 0.11685593019097174,
228
- 0.6137734743119663, 0.6325213429104964,
229
- 0.6877559813398925, 0.18385234579055312,
230
- 0.7501311470607039, 0.31922253900599407,
231
- 0.43053698395186735, 0.9770196254788744,
232
- 0.105776653432334, 0.17992045162625886,
233
- 0.7068137351637119, 0.09374992924495854,
234
- 0.4741257221497737, 0.2717329622804037,
235
- 0.6427948478921109, 0.048162101812947195,
236
- 0.649627174383166, 0.27438020721066836,
237
- 0.9478733559036244, 0.6199505789910625,
238
- 0.8043054302444751, 0.9363898295339244,
239
- 0.6613804354420972, 0.5876014495519649]
240
-
241
- prng.reseed("%s*08^_Tg{NnirtZ-94)q9z2l+~bB5")
242
- result = Array.new(32) { prng.double }
243
- #assert_equal(expected, result)
244
-
245
- (0...32).each do |i|
246
- assert_in_delta(expected[i], result[i], 1.0e-16)
247
- end
248
-
249
- end
250
-
251
- end
1
+ # coding: utf-8
2
+
3
+ require_relative '../lib/fibonacci_rng'
4
+ gem 'minitest'
5
+ require 'minitest/autorun'
6
+ require 'minitest_visible'
7
+
8
+ #Test the monkey patches applied to the Object class.
9
+ class FibonacciRngTester < Minitest::Test
10
+
11
+ #Track mini-test progress.
12
+ include MinitestVisible
13
+
14
+ def test_how_we_build_generators
15
+ gen = FibonacciRng.new
16
+ assert(gen.validate)
17
+ assert_equal(8, gen.depth)
18
+ assert_equal(String, gen.seed.class)
19
+ assert_equal(1024, gen.init)
20
+ assert(gen.validate)
21
+
22
+ gen = FibonacciRng.new('seed')
23
+ assert(gen.validate)
24
+ assert_equal(8, gen.depth)
25
+ assert_equal('seed', gen.seed)
26
+ assert_equal(1024, gen.init)
27
+ assert(gen.validate)
28
+
29
+ gen = FibonacciRng.new('seed', 12)
30
+ assert(gen.validate)
31
+ assert_equal(12, gen.depth)
32
+ assert_equal('seed', gen.seed)
33
+ assert_equal(1152, gen.init)
34
+ assert(gen.validate)
35
+
36
+ gen = FibonacciRng.new('seed', 12, 2048)
37
+ assert(gen.validate)
38
+ assert_equal(12, gen.depth)
39
+ assert_equal('seed', gen.seed)
40
+ assert_equal(2048, gen.init)
41
+ assert(gen.validate)
42
+ end
43
+
44
+ def test_building_with_keywords
45
+ gen = FibonacciRng.new(seed: 'seed')
46
+ assert(gen.validate)
47
+ assert_equal(8, gen.depth)
48
+ assert_equal('seed', gen.seed)
49
+ assert_equal(1024, gen.init)
50
+ assert(gen.validate)
51
+
52
+ gen = FibonacciRng.new(depth: 12)
53
+ assert(gen.validate)
54
+ assert_equal(12, gen.depth)
55
+ assert_equal(String, gen.seed.class)
56
+ assert_equal(1152, gen.init)
57
+ assert(gen.validate)
58
+
59
+ gen = FibonacciRng.new(seed: 'seed', depth: 12)
60
+ assert(gen.validate)
61
+ assert_equal(12, gen.depth)
62
+ assert_equal('seed', gen.seed)
63
+ assert_equal(1152, gen.init)
64
+ assert(gen.validate)
65
+
66
+ gen = FibonacciRng.new(depth: 12, seed: 'seed')
67
+ assert(gen.validate)
68
+ assert_equal(12, gen.depth)
69
+ assert_equal('seed', gen.seed)
70
+ assert_equal(1152, gen.init)
71
+ assert(gen.validate)
72
+
73
+ gen = FibonacciRng.new(seed: 'seed', init: 2048)
74
+ assert(gen.validate)
75
+ assert_equal('seed', gen.seed)
76
+ assert_equal(2048, gen.init)
77
+ assert(gen.validate)
78
+ end
79
+
80
+ def test_that_it_detects_fatal_conditions
81
+ gen = FibonacciRng.new
82
+ assert(gen.validate)
83
+
84
+ gen.define_singleton_method(:kill) do
85
+ @buffer = Array.new(@buffer.length, 0)
86
+ end
87
+
88
+ gen.kill #Force a fatal error condition.
89
+
90
+ assert_raises(InvalidFibonacciRngState) {gen.validate}
91
+ assert_raises(InvalidFibonacciRngState) {gen.spin(6)}
92
+ assert_raises(InvalidFibonacciRngState) {gen.dice(6)}
93
+ assert_raises(InvalidFibonacciRngState) {gen.byte}
94
+ assert_raises(InvalidFibonacciRngState) {gen.word}
95
+ assert_raises(InvalidFibonacciRngState) {gen.float}
96
+ assert_raises(InvalidFibonacciRngState) {gen.double}
97
+
98
+ end
99
+
100
+ def test_that_rejects_bad_parms
101
+ assert_raises { FibonacciRng.new('seed', 1) }
102
+ assert_raises { FibonacciRng.new('seed', 65536) }
103
+ end
104
+
105
+ def test_that_it_creates_dice_rolls
106
+ prng = FibonacciRng.new
107
+
108
+ 100.times do
109
+ assert((0...6) === prng.dice(6))
110
+ end
111
+ end
112
+
113
+ def test_that_it_creates_bytes
114
+ prng = FibonacciRng.new
115
+
116
+ 100.times do
117
+ assert((0...256) === prng.byte)
118
+ end
119
+ end
120
+
121
+ def test_that_it_creates_words
122
+ prng = FibonacciRng.new
123
+
124
+ 100.times do
125
+ assert((0...65536) === prng.word)
126
+ end
127
+ end
128
+
129
+ def test_that_it_creates_floats
130
+ prng = FibonacciRng.new
131
+
132
+ 100.times do
133
+ value = prng.float
134
+ assert((value >= 0.0) && (value < 1.0))
135
+ end
136
+ end
137
+
138
+ def test_compatible_global_dice_rolls
139
+ 100.times do
140
+ assert((0...6) === FibonacciRng.rand(6))
141
+ end
142
+ end
143
+
144
+ def test_compatible_global_dice_rolls_range
145
+ 100.times do
146
+ assert((0...6) === FibonacciRng.rand(0...6))
147
+ end
148
+ end
149
+
150
+ def test_compatible_global_floats
151
+ 100.times do
152
+ value = FibonacciRng.rand(0)
153
+ assert((value >= 0.0) && (value < 1.0))
154
+ end
155
+ end
156
+
157
+ def test_random_string
158
+ prng = FibonacciRng.new
159
+
160
+ rs = prng.bytes(10)
161
+
162
+ assert(rs.is_a?(String))
163
+ assert_equal(10, rs.length)
164
+ end
165
+
166
+ def test_that_it_makes_unique_sequences
167
+ prnga = FibonacciRng.new
168
+ prngb = FibonacciRng.new
169
+
170
+ buffa = []
171
+ buffb = []
172
+
173
+ 100.times do
174
+ buffa << prnga.dice(6)
175
+ buffb << prngb.dice(6)
176
+ end
177
+
178
+ assert(buffa != buffb)
179
+ end
180
+
181
+ def test_that_it_makes_repeatable_sequences
182
+ prnga = FibonacciRng.new(0)
183
+ prngb = FibonacciRng.new(0)
184
+
185
+ buffa = []
186
+ buffb = []
187
+
188
+ 100.times do
189
+ buffa << prnga.dice(6)
190
+ buffb << prngb.dice(6)
191
+ end
192
+
193
+ assert(buffa == buffb)
194
+ end
195
+
196
+ def test_that_it_creates_unique_seeds
197
+ result = []
198
+ 10_000.times do
199
+ result << FibonacciRng.new_seed
200
+ end
201
+
202
+ result.uniq!
203
+ assert_equal(10_000, result.length)
204
+ end
205
+
206
+ def test_building_strings
207
+ rng = FibonacciRng.new(0)
208
+ assert_equal("c}l'(q@g\\z", rng.string(10))
209
+ assert_equal('2727573312', rng.string(10, '0123456789'))
210
+ assert_equal('khto lk si', rng.string(10, 'Always look on the bright side of life.'))
211
+
212
+ rng = FibonacciRng.new("%s*08^_Tg{NnirtZ-94)q9z2l+~bB5")
213
+ assert_equal(",-+Idi6~ ~", rng.string(10))
214
+ assert_equal('5901964804', rng.string(10, '0123456789'))
215
+ end
216
+
217
+ def test_for_data_stability
218
+ #Make sure incompatibilities do not creep in.
219
+ expected = [184, 93, 0, 240, 34, 184, 4, 220, 126, 132,
220
+ 13, 67, 166, 107, 165, 66, 68, 120, 102, 110,
221
+ 212, 99, 80, 167, 9, 56, 47, 167, 127, 195,
222
+ 169, 34, 184, 97, 136, 176, 214, 104, 218, 103,
223
+ 180, 16, 83, 204, 128, 81, 63, 56, 237, 165,
224
+ 0, 88, 129, 40, 152, 44, 189, 35, 205, 249,
225
+ 77, 94, 142, 18, 60, 248, 49, 172, 235, 83,
226
+ 84, 65, 181, 117, 16, 170, 222, 97, 130, 217]
227
+
228
+ prng = FibonacciRng.new("%s*08^_Tg{NnirtZ-94)q9z2l+~bB5")
229
+ result = Array.new(80) { prng.byte }
230
+ assert_equal(expected, result)
231
+
232
+ prng.reseed("%s*08^_Tg{NnirtZ-94)q9z2l+~bB5")
233
+ result = Array.new(80) { prng.byte }
234
+ assert_equal(expected, result)
235
+
236
+
237
+ expected = [0.466758593916893, 0.8060004059225321,
238
+ 0.8063845634460449, 0.8676037490367889,
239
+ 0.350975576788187, 0.2556227296590805,
240
+ 0.4873242452740669, 0.07484667748212814,
241
+ 0.2968141995370388, 0.5417192056775093,
242
+ 0.4288134817034006, 0.26460993848741055,
243
+ 0.13613684102892876, 0.27074786089360714,
244
+ 0.11685592867434025, 0.814235333353281,
245
+ 0.6137734726071358, 0.9152738898992538,
246
+ 0.6325213424861431, 0.22782298550009727,
247
+ 0.6877559795975685, 0.9354030545800924,
248
+ 0.18385234475135803, 0.5579136144369841,
249
+ 0.7501311469823122, 0.04208622872829437,
250
+ 0.31922253780066967, 0.6471036206930876,
251
+ 0.4305369835346937, 0.2239683922380209,
252
+ 0.9770196247845888, 0.3727417625486851]
253
+
254
+ prng.reseed("%s*08^_Tg{NnirtZ-94)q9z2l+~bB5")
255
+ result = Array.new(32) { prng.float }
256
+ #assert_equal(expected, result)
257
+
258
+ (0...32).each do |i|
259
+ assert_in_delta(expected[i], result[i], 1.0e-16)
260
+ end
261
+
262
+ expected = [0.46675859541818576, 0.8063845650620829,
263
+ 0.3509755772643215, 0.48732424541347974,
264
+ 0.29681420054606944, 0.428813482196275,
265
+ 0.13613684153323594, 0.11685593019097174,
266
+ 0.6137734743119663, 0.6325213429104964,
267
+ 0.6877559813398925, 0.18385234579055312,
268
+ 0.7501311470607039, 0.31922253900599407,
269
+ 0.43053698395186735, 0.9770196254788744,
270
+ 0.105776653432334, 0.17992045162625886,
271
+ 0.7068137351637119, 0.09374992924495854,
272
+ 0.4741257221497737, 0.2717329622804037,
273
+ 0.6427948478921109, 0.048162101812947195,
274
+ 0.649627174383166, 0.27438020721066836,
275
+ 0.9478733559036244, 0.6199505789910625,
276
+ 0.8043054302444751, 0.9363898295339244,
277
+ 0.6613804354420972, 0.5876014495519649]
278
+
279
+ prng.reseed("%s*08^_Tg{NnirtZ-94)q9z2l+~bB5")
280
+ result = Array.new(32) { prng.double }
281
+ #assert_equal(expected, result)
282
+
283
+ (0...32).each do |i|
284
+ assert_in_delta(expected[i], result[i], 1.0e-16)
285
+ end
286
+
287
+ end
288
+
289
+ end
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+
3
+ #A Scatter Plot tester
4
+ class TortureTest
5
+
6
+ #Run a scatter plot test on the random number generator.
7
+ def run(gen, max, count)
8
+ max *=1000
9
+ count *=1000
10
+
11
+ puts "Starting torture test with #{max} loops of #{count} tests."
12
+
13
+ max.times do |i|
14
+ gen.spin(count)
15
+ print (i+1).to_s.rjust(8)
16
+ end
17
+
18
+ puts
19
+ puts "No errors were detected."
20
+ return
21
+
22
+ rescue InvalidFibonacciRngState
23
+ puts
24
+ puts "InvalidFibonacciRngState detected."
25
+ end
26
+
27
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fibonacci_rng
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.5
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter Camilleri
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-02-15 00:00:00.000000000 Z
11
+ date: 2018-09-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -94,8 +94,7 @@ dependencies:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
96
  version: '4.5'
97
- description: A Fibonacci inspired pseudo random number generator. [Updated] The algorithm
98
- is changed to use bit rotate instead of bit shift.
97
+ description: A Fibonacci inspired pseudo random number generator with error detection.
99
98
  email:
100
99
  - peter.c.camilleri@gmail.com
101
100
  executables: []
@@ -115,6 +114,7 @@ files:
115
114
  - lib/fibonacci_rng/hasher.rb
116
115
  - lib/fibonacci_rng/seeder.rb
117
116
  - lib/fibonacci_rng/spinner.rb
117
+ - lib/fibonacci_rng/validate.rb
118
118
  - lib/fibonacci_rng/version.rb
119
119
  - prng.rb
120
120
  - rakefile.rb
@@ -125,6 +125,7 @@ files:
125
125
  - tools/chi_squared.rb
126
126
  - tools/internal_rng.rb
127
127
  - tools/scatter_plot.rb
128
+ - tools/torture_test.rb
128
129
  homepage: https://github.com/PeterCamilleri/fibonacci_rng
129
130
  licenses:
130
131
  - MIT
@@ -145,9 +146,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
145
146
  version: '0'
146
147
  requirements: []
147
148
  rubyforge_project:
148
- rubygems_version: 2.2.3
149
+ rubygems_version: 2.5.2
149
150
  signing_key:
150
151
  specification_version: 4
151
- summary: "[Updated] A Fibonacci inspired pseudo random number generator."
152
+ summary: A Fibonacci inspired pseudo random number generator.
152
153
  test_files: []
153
- has_rdoc: