fibonacci_rng 1.2.4 → 2.0.3
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 +5 -5
- data/CODE_OF_CONDUCT.md +49 -0
- data/README.md +33 -0
- data/fibonacci.reek +5 -0
- data/fibonacci_rng.gemspec +11 -12
- data/lib/fibonacci_rng.rb +1 -0
- data/lib/fibonacci_rng/generator.rb +15 -3
- data/lib/fibonacci_rng/hasher.rb +2 -0
- data/lib/fibonacci_rng/spinner.rb +2 -0
- data/lib/fibonacci_rng/validate.rb +18 -0
- data/lib/fibonacci_rng/version.rb +1 -1
- data/prng.rb +4 -1
- data/tests/fibinacci_rng_tests.rb +285 -251
- data/tests/hasher_tests.rb +0 -4
- data/tools/torture_test.rb +27 -0
- metadata +23 -37
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 7c333d0cc63992b91586c7fb9abef10006b0aeaa066ec31b8825d082a7403f13
|
4
|
+
data.tar.gz: 88ad1c6b6c06f60472dbaa4ad36c711227ecb02d8b31c6e1a938904e0e15c7ba
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c6b1293e091193497ba2444ce770fcc641c9416c8227cdd835000e505e2f529d71307fcc2d44813d2b641e28e4dfe2a8e887a2e57168be10ee2e3da2559cd5b3
|
7
|
+
data.tar.gz: da35671c49f688fd5aa38f1729792afb5aa762a8951e528cfc80e230b21dde904af801246489396ef4369aae9ab5379bcf3075ef5b55b966919fef710f5fbfaf
|
data/CODE_OF_CONDUCT.md
ADDED
@@ -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: []
|
data/fibonacci_rng.gemspec
CHANGED
@@ -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 = "
|
12
|
-
spec.description = "A Fibonacci inspired pseudo random number generator
|
13
|
-
"
|
14
|
-
|
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
|
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
|
29
|
-
spec.add_development_dependency "bundler", "
|
30
|
-
spec.add_development_dependency "
|
31
|
-
spec.add_development_dependency '
|
32
|
-
spec.add_development_dependency '
|
33
|
-
|
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
|
-
|
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 =
|
63
|
+
part_one = raw_float * BASE
|
60
64
|
do_spin
|
61
|
-
|
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
|
data/lib/fibonacci_rng/hasher.rb
CHANGED
@@ -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
|
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
|
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
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
gen
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
gen
|
21
|
-
assert_equal(
|
22
|
-
assert_equal(
|
23
|
-
|
24
|
-
|
25
|
-
gen = FibonacciRng.new('seed', 12)
|
26
|
-
|
27
|
-
assert_equal(
|
28
|
-
assert_equal(
|
29
|
-
|
30
|
-
gen
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
gen
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
gen
|
43
|
-
assert_equal(
|
44
|
-
assert_equal(
|
45
|
-
assert_equal(
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
assert_equal(
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
assert_equal('seed', gen.seed)
|
59
|
-
assert_equal(
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
100.times do
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
0.
|
235
|
-
0.
|
236
|
-
0.
|
237
|
-
0.
|
238
|
-
0.
|
239
|
-
0.
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
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
|
data/tests/hasher_tests.rb
CHANGED
@@ -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:
|
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:
|
11
|
+
date: 2021-05-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: rake
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
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:
|
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:
|
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:
|
40
|
+
version: 2.1.0
|
55
41
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
42
|
+
name: minitest
|
57
43
|
requirement: !ruby/object:Gem::Requirement
|
58
44
|
requirements:
|
59
45
|
- - "~>"
|
60
46
|
- !ruby/object:Gem::Version
|
61
|
-
version:
|
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:
|
54
|
+
version: '5.7'
|
69
55
|
- !ruby/object:Gem::Dependency
|
70
|
-
name:
|
56
|
+
name: rdoc
|
71
57
|
requirement: !ruby/object:Gem::Requirement
|
72
58
|
requirements:
|
73
59
|
- - "~>"
|
74
60
|
- !ruby/object:Gem::Version
|
75
|
-
version:
|
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:
|
68
|
+
version: '5.0'
|
83
69
|
- !ruby/object:Gem::Dependency
|
84
|
-
name:
|
70
|
+
name: reek
|
85
71
|
requirement: !ruby/object:Gem::Requirement
|
86
72
|
requirements:
|
87
73
|
- - "~>"
|
88
74
|
- !ruby/object:Gem::Version
|
89
|
-
version: 4.
|
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.
|
97
|
-
description: A Fibonacci inspired pseudo random number generator
|
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
|
-
|
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
|
-
|
147
|
-
rubygems_version: 2.2.2
|
134
|
+
rubygems_version: 3.2.17
|
148
135
|
signing_key:
|
149
136
|
specification_version: 4
|
150
|
-
summary:
|
137
|
+
summary: A Fibonacci inspired pseudo random number generator.
|
151
138
|
test_files: []
|
152
|
-
has_rdoc:
|