fibonacci_rng 1.2.4 → 2.0.3

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
- SHA1:
3
- metadata.gz: a2b0f346f2a84fffa599f7e59d56266af1071c36
4
- data.tar.gz: a81bb2464457c39090b48e6898d76c906c25487a
2
+ SHA256:
3
+ metadata.gz: 7c333d0cc63992b91586c7fb9abef10006b0aeaa066ec31b8825d082a7403f13
4
+ data.tar.gz: 88ad1c6b6c06f60472dbaa4ad36c711227ecb02d8b31c6e1a938904e0e15c7ba
5
5
  SHA512:
6
- metadata.gz: 714b087512536b6bf85d4dea7b92b2b3ff6c0f6f7b9aee66465a9872808b07a7b51b8cca4f24c1ab8cdbaac78c09992c52eb0f91fcf72ec18ce0ed093d644dbc
7
- data.tar.gz: a1ab955cdc11a4fdd9b922dba0345de7421b869db980e270661b31065f0525306f538f705478fc7eef4b9c0fbc2640370d55b7757c4f4522e017391f54a999df
6
+ metadata.gz: c6b1293e091193497ba2444ce770fcc641c9416c8227cdd835000e505e2f529d71307fcc2d44813d2b641e28e4dfe2a8e887a2e57168be10ee2e3da2559cd5b3
7
+ data.tar.gz: da35671c49f688fd5aa38f1729792afb5aa762a8951e528cfc80e230b21dde904af801246489396ef4369aae9ab5379bcf3075ef5b55b966919fef710f5fbfaf
@@ -0,0 +1,49 @@
1
+ # Contributor Code of Conduct
2
+
3
+ As contributors and maintainers of this project, and in the interest of
4
+ fostering an open and welcoming community, we pledge to respect all people who
5
+ contribute through reporting issues, posting feature requests, updating
6
+ documentation, submitting pull requests or patches, and other activities.
7
+
8
+ We are committed to making participation in this project a harassment-free
9
+ experience for everyone, regardless of level of experience, gender, gender
10
+ identity and expression, sexual orientation, disability, personal appearance,
11
+ body size, race, ethnicity, age, religion, or nationality.
12
+
13
+ Examples of unacceptable behavior by participants include:
14
+
15
+ * The use of sexualized language or imagery
16
+ * Personal attacks
17
+ * Trolling or insulting/derogatory comments
18
+ * Public or private harassment
19
+ * Publishing other's private information, such as physical or electronic
20
+ addresses, without explicit permission
21
+ * Other unethical or unprofessional conduct
22
+
23
+ Project maintainers have the right and responsibility to remove, edit, or
24
+ reject comments, commits, code, wiki edits, issues, and other contributions
25
+ that are not aligned to this Code of Conduct, or to ban temporarily or
26
+ permanently any contributor for other behaviors that they deem inappropriate,
27
+ threatening, offensive, or harmful.
28
+
29
+ By adopting this Code of Conduct, project maintainers commit themselves to
30
+ fairly and consistently applying these principles to every aspect of managing
31
+ this project. Project maintainers who do not follow or enforce the Code of
32
+ Conduct may be permanently removed from the project team.
33
+
34
+ This code of conduct applies both within project spaces and in public spaces
35
+ when an individual is representing the project or its community.
36
+
37
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
38
+ reported by contacting a project maintainer at peter.c.camilleri@gmail.com. All
39
+ complaints will be reviewed and investigated and will result in a response that
40
+ is deemed necessary and appropriate to the circumstances. Maintainers are
41
+ obligated to maintain confidentiality with regard to the reporter of an
42
+ incident.
43
+
44
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage],
45
+ version 1.3.0, available at
46
+ [http://contributor-covenant.org/version/1/3/0/][version]
47
+
48
+ [homepage]: http://contributor-covenant.org
49
+ [version]: http://contributor-covenant.org/version/1/3/0/
data/README.md CHANGED
@@ -212,6 +212,7 @@ N is shown below:
212
212
  <br>Notes:
213
213
  * The last two elements are copies of the first two elements before
214
214
  the array was transformed.
215
+ * The notation ror(x) above signifies a 29 bit rotate right of the argument.
215
216
  * Not shown above for brevity, the result of each addition is masked with the
216
217
  value 0x1FFFFFFF before being stored. This masks off any data beyond the low
217
218
  29 bits.
@@ -267,6 +268,27 @@ TOP = 0x10000000
267
268
 
268
269
  ```
269
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
+
270
292
  ## Contributing
271
293
 
272
294
  Creating a good pseudo random number generator is quite an undertaking. For
@@ -285,3 +307,14 @@ this can be accomplished.
285
307
 
286
308
  Go to the GitHub repository and raise an issue calling attention to some
287
309
  aspect that could use some TLC or a suggestion or an idea.
310
+
311
+ ## License
312
+
313
+ The gem is available as open source under the terms of the
314
+ [MIT License](./LICENSE.txt).
315
+
316
+ ## Code of Conduct
317
+
318
+ Everyone interacting in the fully_freeze project’s codebases, issue trackers,
319
+ chat rooms and mailing lists is expected to follow the
320
+ [code of conduct](./CODE_OF_CONDUCT.md).
data/fibonacci.reek CHANGED
@@ -24,6 +24,9 @@ DuplicateMethodCall:
24
24
  FeatureEnvy:
25
25
  enabled: true
26
26
  exclude: []
27
+ InstanceVariableAssumption:
28
+ enabled: false
29
+ exclude: []
27
30
  IrresponsibleModule:
28
31
  enabled: true
29
32
  exclude: []
@@ -57,6 +60,8 @@ TooManyInstanceVariables:
57
60
  enabled: true
58
61
  exclude: []
59
62
  max_instance_variables: 9
63
+ TooManyConstants:
64
+ max_constants: 10
60
65
  TooManyMethods:
61
66
  enabled: true
62
67
  exclude: []
@@ -8,11 +8,10 @@ Gem::Specification.new do |spec|
8
8
  spec.version = FibonacciRng::VERSION
9
9
  spec.authors = ["Peter Camilleri"]
10
10
  spec.email = ["peter.c.camilleri@gmail.com"]
11
- spec.homepage = "http://teuthida-technologies.com/"
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."
11
+ spec.homepage = "https://github.com/PeterCamilleri/fibonacci_rng"
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,15 +19,15 @@ 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'
27
26
 
28
- spec.add_development_dependency 'minitest_visible', ">= 0.1.1"
29
- spec.add_development_dependency "bundler", "~> 1.3"
30
- spec.add_development_dependency "rake"
31
- spec.add_development_dependency 'reek', "~> 1.3.8"
32
- spec.add_development_dependency 'minitest', "~> 4.7.5"
33
- spec.add_development_dependency 'rdoc', "~> 4.0.1"
27
+ spec.add_development_dependency "rake", ">= 12.3.3"
28
+ spec.add_development_dependency "bundler", ">= 2.1.0"
29
+ spec.add_development_dependency 'minitest', "~> 5.7"
30
+ spec.add_development_dependency 'rdoc', "~> 5.0"
31
+ spec.add_development_dependency 'reek', "~> 4.5"
32
+
34
33
  end
data/lib/fibonacci_rng.rb CHANGED
@@ -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,21 +46,24 @@ 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
53
- @buffer[0].to_f / BASE
56
+ validate
57
+ raw_float / BASE
54
58
  end
55
59
 
56
60
  #Get a better pseudo random float
57
61
  def double
58
62
  do_spin
59
- part_one = @buffer[0].to_f * BASE
63
+ part_one = raw_float * BASE
60
64
  do_spin
61
- (part_one + @buffer[0].to_f) / DOUBLE
65
+ validate
66
+ (part_one + raw_float) / DOUBLE
62
67
  end
63
68
 
64
69
  #The printable seven bit ASCII characters.
@@ -74,4 +79,11 @@ class FibonacciRng
74
79
  result
75
80
  end
76
81
 
82
+ private
83
+
84
+ #Get a float value.
85
+ def raw_float
86
+ @buffer[0].to_f
87
+ end
88
+
77
89
  end
@@ -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.4"
5
+ VERSION = "2.0.3"
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,285 @@
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
+
7
+ #Test the monkey patches applied to the Object class.
8
+ class FibonacciRngTester < Minitest::Test
9
+
10
+ def test_how_we_build_generators
11
+ gen = FibonacciRng.new
12
+ assert(gen.validate)
13
+ assert_equal(8, gen.depth)
14
+ assert_equal(String, gen.seed.class)
15
+ assert_equal(1024, gen.init)
16
+ assert(gen.validate)
17
+
18
+ gen = FibonacciRng.new('seed')
19
+ assert(gen.validate)
20
+ assert_equal(8, gen.depth)
21
+ assert_equal('seed', gen.seed)
22
+ assert_equal(1024, gen.init)
23
+ assert(gen.validate)
24
+
25
+ gen = FibonacciRng.new('seed', 12)
26
+ assert(gen.validate)
27
+ assert_equal(12, gen.depth)
28
+ assert_equal('seed', gen.seed)
29
+ assert_equal(1152, gen.init)
30
+ assert(gen.validate)
31
+
32
+ gen = FibonacciRng.new('seed', 12, 2048)
33
+ assert(gen.validate)
34
+ assert_equal(12, gen.depth)
35
+ assert_equal('seed', gen.seed)
36
+ assert_equal(2048, gen.init)
37
+ assert(gen.validate)
38
+ end
39
+
40
+ def test_building_with_keywords
41
+ gen = FibonacciRng.new(seed: 'seed')
42
+ assert(gen.validate)
43
+ assert_equal(8, gen.depth)
44
+ assert_equal('seed', gen.seed)
45
+ assert_equal(1024, gen.init)
46
+ assert(gen.validate)
47
+
48
+ gen = FibonacciRng.new(depth: 12)
49
+ assert(gen.validate)
50
+ assert_equal(12, gen.depth)
51
+ assert_equal(String, gen.seed.class)
52
+ assert_equal(1152, gen.init)
53
+ assert(gen.validate)
54
+
55
+ gen = FibonacciRng.new(seed: 'seed', depth: 12)
56
+ assert(gen.validate)
57
+ assert_equal(12, gen.depth)
58
+ assert_equal('seed', gen.seed)
59
+ assert_equal(1152, gen.init)
60
+ assert(gen.validate)
61
+
62
+ gen = FibonacciRng.new(depth: 12, seed: 'seed')
63
+ assert(gen.validate)
64
+ assert_equal(12, gen.depth)
65
+ assert_equal('seed', gen.seed)
66
+ assert_equal(1152, gen.init)
67
+ assert(gen.validate)
68
+
69
+ gen = FibonacciRng.new(seed: 'seed', init: 2048)
70
+ assert(gen.validate)
71
+ assert_equal('seed', gen.seed)
72
+ assert_equal(2048, gen.init)
73
+ assert(gen.validate)
74
+ end
75
+
76
+ def test_that_it_detects_fatal_conditions
77
+ gen = FibonacciRng.new
78
+ assert(gen.validate)
79
+
80
+ gen.define_singleton_method(:kill) do
81
+ @buffer = Array.new(@buffer.length, 0)
82
+ end
83
+
84
+ gen.kill #Force a fatal error condition.
85
+
86
+ assert_raises(InvalidFibonacciRngState) {gen.validate}
87
+ assert_raises(InvalidFibonacciRngState) {gen.spin(6)}
88
+ assert_raises(InvalidFibonacciRngState) {gen.dice(6)}
89
+ assert_raises(InvalidFibonacciRngState) {gen.byte}
90
+ assert_raises(InvalidFibonacciRngState) {gen.word}
91
+ assert_raises(InvalidFibonacciRngState) {gen.float}
92
+ assert_raises(InvalidFibonacciRngState) {gen.double}
93
+
94
+ end
95
+
96
+ def test_that_rejects_bad_parms
97
+ assert_raises { FibonacciRng.new('seed', 1) }
98
+ assert_raises { FibonacciRng.new('seed', 65536) }
99
+ end
100
+
101
+ def test_that_it_creates_dice_rolls
102
+ prng = FibonacciRng.new
103
+
104
+ 100.times do
105
+ assert((0...6) === prng.dice(6))
106
+ end
107
+ end
108
+
109
+ def test_that_it_creates_bytes
110
+ prng = FibonacciRng.new
111
+
112
+ 100.times do
113
+ assert((0...256) === prng.byte)
114
+ end
115
+ end
116
+
117
+ def test_that_it_creates_words
118
+ prng = FibonacciRng.new
119
+
120
+ 100.times do
121
+ assert((0...65536) === prng.word)
122
+ end
123
+ end
124
+
125
+ def test_that_it_creates_floats
126
+ prng = FibonacciRng.new
127
+
128
+ 100.times do
129
+ value = prng.float
130
+ assert((value >= 0.0) && (value < 1.0))
131
+ end
132
+ end
133
+
134
+ def test_compatible_global_dice_rolls
135
+ 100.times do
136
+ assert((0...6) === FibonacciRng.rand(6))
137
+ end
138
+ end
139
+
140
+ def test_compatible_global_dice_rolls_range
141
+ 100.times do
142
+ assert((0...6) === FibonacciRng.rand(0...6))
143
+ end
144
+ end
145
+
146
+ def test_compatible_global_floats
147
+ 100.times do
148
+ value = FibonacciRng.rand(0)
149
+ assert((value >= 0.0) && (value < 1.0))
150
+ end
151
+ end
152
+
153
+ def test_random_string
154
+ prng = FibonacciRng.new
155
+
156
+ rs = prng.bytes(10)
157
+
158
+ assert(rs.is_a?(String))
159
+ assert_equal(10, rs.length)
160
+ end
161
+
162
+ def test_that_it_makes_unique_sequences
163
+ prnga = FibonacciRng.new
164
+ prngb = FibonacciRng.new
165
+
166
+ buffa = []
167
+ buffb = []
168
+
169
+ 100.times do
170
+ buffa << prnga.dice(6)
171
+ buffb << prngb.dice(6)
172
+ end
173
+
174
+ assert(buffa != buffb)
175
+ end
176
+
177
+ def test_that_it_makes_repeatable_sequences
178
+ prnga = FibonacciRng.new(0)
179
+ prngb = FibonacciRng.new(0)
180
+
181
+ buffa = []
182
+ buffb = []
183
+
184
+ 100.times do
185
+ buffa << prnga.dice(6)
186
+ buffb << prngb.dice(6)
187
+ end
188
+
189
+ assert(buffa == buffb)
190
+ end
191
+
192
+ def test_that_it_creates_unique_seeds
193
+ result = []
194
+ 10_000.times do
195
+ result << FibonacciRng.new_seed
196
+ end
197
+
198
+ result.uniq!
199
+ assert_equal(10_000, result.length)
200
+ end
201
+
202
+ def test_building_strings
203
+ rng = FibonacciRng.new(0)
204
+ assert_equal("c}l'(q@g\\z", rng.string(10))
205
+ assert_equal('2727573312', rng.string(10, '0123456789'))
206
+ assert_equal('khto lk si', rng.string(10, 'Always look on the bright side of life.'))
207
+
208
+ rng = FibonacciRng.new("%s*08^_Tg{NnirtZ-94)q9z2l+~bB5")
209
+ assert_equal(",-+Idi6~ ~", rng.string(10))
210
+ assert_equal('5901964804', rng.string(10, '0123456789'))
211
+ end
212
+
213
+ def test_for_data_stability
214
+ #Make sure incompatibilities do not creep in.
215
+ expected = [184, 93, 0, 240, 34, 184, 4, 220, 126, 132,
216
+ 13, 67, 166, 107, 165, 66, 68, 120, 102, 110,
217
+ 212, 99, 80, 167, 9, 56, 47, 167, 127, 195,
218
+ 169, 34, 184, 97, 136, 176, 214, 104, 218, 103,
219
+ 180, 16, 83, 204, 128, 81, 63, 56, 237, 165,
220
+ 0, 88, 129, 40, 152, 44, 189, 35, 205, 249,
221
+ 77, 94, 142, 18, 60, 248, 49, 172, 235, 83,
222
+ 84, 65, 181, 117, 16, 170, 222, 97, 130, 217]
223
+
224
+ prng = FibonacciRng.new("%s*08^_Tg{NnirtZ-94)q9z2l+~bB5")
225
+ result = Array.new(80) { prng.byte }
226
+ assert_equal(expected, result)
227
+
228
+ prng.reseed("%s*08^_Tg{NnirtZ-94)q9z2l+~bB5")
229
+ result = Array.new(80) { prng.byte }
230
+ assert_equal(expected, result)
231
+
232
+
233
+ expected = [0.466758593916893, 0.8060004059225321,
234
+ 0.8063845634460449, 0.8676037490367889,
235
+ 0.350975576788187, 0.2556227296590805,
236
+ 0.4873242452740669, 0.07484667748212814,
237
+ 0.2968141995370388, 0.5417192056775093,
238
+ 0.4288134817034006, 0.26460993848741055,
239
+ 0.13613684102892876, 0.27074786089360714,
240
+ 0.11685592867434025, 0.814235333353281,
241
+ 0.6137734726071358, 0.9152738898992538,
242
+ 0.6325213424861431, 0.22782298550009727,
243
+ 0.6877559795975685, 0.9354030545800924,
244
+ 0.18385234475135803, 0.5579136144369841,
245
+ 0.7501311469823122, 0.04208622872829437,
246
+ 0.31922253780066967, 0.6471036206930876,
247
+ 0.4305369835346937, 0.2239683922380209,
248
+ 0.9770196247845888, 0.3727417625486851]
249
+
250
+ prng.reseed("%s*08^_Tg{NnirtZ-94)q9z2l+~bB5")
251
+ result = Array.new(32) { prng.float }
252
+ #assert_equal(expected, result)
253
+
254
+ (0...32).each do |i|
255
+ assert_in_delta(expected[i], result[i], 1.0e-16)
256
+ end
257
+
258
+ expected = [0.46675859541818576, 0.8063845650620829,
259
+ 0.3509755772643215, 0.48732424541347974,
260
+ 0.29681420054606944, 0.428813482196275,
261
+ 0.13613684153323594, 0.11685593019097174,
262
+ 0.6137734743119663, 0.6325213429104964,
263
+ 0.6877559813398925, 0.18385234579055312,
264
+ 0.7501311470607039, 0.31922253900599407,
265
+ 0.43053698395186735, 0.9770196254788744,
266
+ 0.105776653432334, 0.17992045162625886,
267
+ 0.7068137351637119, 0.09374992924495854,
268
+ 0.4741257221497737, 0.2717329622804037,
269
+ 0.6427948478921109, 0.048162101812947195,
270
+ 0.649627174383166, 0.27438020721066836,
271
+ 0.9478733559036244, 0.6199505789910625,
272
+ 0.8043054302444751, 0.9363898295339244,
273
+ 0.6613804354420972, 0.5876014495519649]
274
+
275
+ prng.reseed("%s*08^_Tg{NnirtZ-94)q9z2l+~bB5")
276
+ result = Array.new(32) { prng.double }
277
+ #assert_equal(expected, result)
278
+
279
+ (0...32).each do |i|
280
+ assert_in_delta(expected[i], result[i], 1.0e-16)
281
+ end
282
+
283
+ end
284
+
285
+ end
@@ -3,14 +3,10 @@
3
3
  require_relative '../lib/fibonacci_rng'
4
4
  gem 'minitest'
5
5
  require 'minitest/autorun'
6
- require 'minitest_visible'
7
6
 
8
7
  #Test the monkey patches applied to the Object class.
9
8
  class FibonacciHasherTester < Minitest::Test
10
9
 
11
- #Track mini-test progress.
12
- include MinitestVisible
13
-
14
10
  def test_that_it_can_be_read
15
11
  fib = FibonacciRng.new('salt')
16
12
 
@@ -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,101 +1,86 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fibonacci_rng
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.4
4
+ version: 2.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter Camilleri
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-09-23 00:00:00.000000000 Z
11
+ date: 2021-05-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: minitest_visible
14
+ name: rake
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 0.1.1
19
+ version: 12.3.3
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: 0.1.1
26
+ version: 12.3.3
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: bundler
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '1.3'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
39
- - !ruby/object:Gem::Version
40
- version: '1.3'
41
- - !ruby/object:Gem::Dependency
42
- name: rake
43
29
  requirement: !ruby/object:Gem::Requirement
44
30
  requirements:
45
31
  - - ">="
46
32
  - !ruby/object:Gem::Version
47
- version: '0'
33
+ version: 2.1.0
48
34
  type: :development
49
35
  prerelease: false
50
36
  version_requirements: !ruby/object:Gem::Requirement
51
37
  requirements:
52
38
  - - ">="
53
39
  - !ruby/object:Gem::Version
54
- version: '0'
40
+ version: 2.1.0
55
41
  - !ruby/object:Gem::Dependency
56
- name: reek
42
+ name: minitest
57
43
  requirement: !ruby/object:Gem::Requirement
58
44
  requirements:
59
45
  - - "~>"
60
46
  - !ruby/object:Gem::Version
61
- version: 1.3.8
47
+ version: '5.7'
62
48
  type: :development
63
49
  prerelease: false
64
50
  version_requirements: !ruby/object:Gem::Requirement
65
51
  requirements:
66
52
  - - "~>"
67
53
  - !ruby/object:Gem::Version
68
- version: 1.3.8
54
+ version: '5.7'
69
55
  - !ruby/object:Gem::Dependency
70
- name: minitest
56
+ name: rdoc
71
57
  requirement: !ruby/object:Gem::Requirement
72
58
  requirements:
73
59
  - - "~>"
74
60
  - !ruby/object:Gem::Version
75
- version: 4.7.5
61
+ version: '5.0'
76
62
  type: :development
77
63
  prerelease: false
78
64
  version_requirements: !ruby/object:Gem::Requirement
79
65
  requirements:
80
66
  - - "~>"
81
67
  - !ruby/object:Gem::Version
82
- version: 4.7.5
68
+ version: '5.0'
83
69
  - !ruby/object:Gem::Dependency
84
- name: rdoc
70
+ name: reek
85
71
  requirement: !ruby/object:Gem::Requirement
86
72
  requirements:
87
73
  - - "~>"
88
74
  - !ruby/object:Gem::Version
89
- version: 4.0.1
75
+ version: '4.5'
90
76
  type: :development
91
77
  prerelease: false
92
78
  version_requirements: !ruby/object:Gem::Requirement
93
79
  requirements:
94
80
  - - "~>"
95
81
  - !ruby/object:Gem::Version
96
- version: 4.0.1
97
- description: A Fibonacci inspired pseudo random number generator. [Updated] The algorithm
98
- is changed to use bit rotate instead of bit shift.
82
+ version: '4.5'
83
+ description: A Fibonacci inspired pseudo random number generator with error detection.
99
84
  email:
100
85
  - peter.c.camilleri@gmail.com
101
86
  executables: []
@@ -103,6 +88,7 @@ extensions: []
103
88
  extra_rdoc_files: []
104
89
  files:
105
90
  - ".gitignore"
91
+ - CODE_OF_CONDUCT.md
106
92
  - Gemfile
107
93
  - LICENSE.txt
108
94
  - README.md
@@ -114,6 +100,7 @@ files:
114
100
  - lib/fibonacci_rng/hasher.rb
115
101
  - lib/fibonacci_rng/seeder.rb
116
102
  - lib/fibonacci_rng/spinner.rb
103
+ - lib/fibonacci_rng/validate.rb
117
104
  - lib/fibonacci_rng/version.rb
118
105
  - prng.rb
119
106
  - rakefile.rb
@@ -124,7 +111,8 @@ files:
124
111
  - tools/chi_squared.rb
125
112
  - tools/internal_rng.rb
126
113
  - tools/scatter_plot.rb
127
- homepage: http://teuthida-technologies.com/
114
+ - tools/torture_test.rb
115
+ homepage: https://github.com/PeterCamilleri/fibonacci_rng
128
116
  licenses:
129
117
  - MIT
130
118
  metadata: {}
@@ -143,10 +131,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
143
131
  - !ruby/object:Gem::Version
144
132
  version: '0'
145
133
  requirements: []
146
- rubyforge_project:
147
- rubygems_version: 2.2.2
134
+ rubygems_version: 3.2.17
148
135
  signing_key:
149
136
  specification_version: 4
150
- summary: "[Updated] A Fibonacci inspired pseudo random number generator."
137
+ summary: A Fibonacci inspired pseudo random number generator.
151
138
  test_files: []
152
- has_rdoc: