fibonacci_rng 1.2.5 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: