fibonacci_rng 0.4.3 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +78 -6
- data/fibonacci_rng.gemspec +4 -2
- data/lib/fibonacci_rng/spinner.rb +2 -1
- data/lib/fibonacci_rng/version.rb +1 -1
- data/lib/fibonacci_rng.rb +1 -0
- data/tests/fibinacci_rng_tests.rb +3 -3
- data/tests/hasher_tests.rb +4 -4
- data/tools/scatter_plot.rb +2 -2
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 92d9ec37d3384e39e3e122ed13281ba8001c8f2a
|
4
|
+
data.tar.gz: df41080f4dc1a92a75028a4f8cce4f94f5c969ed
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7885893e8155ca7b2c59ffd7688dd319a9935288b1796113d7185d263e4caad9c718aabbee84e1c7ca7e6c24bf8a79bbfd68634709c21467b02cb9ba22bb77de
|
7
|
+
data.tar.gz: 3e5cb32a061f12aa8a6218984318509788aea414a69ea4d2149733fd783bcd834bd0a86b7c7e522756cf08bda9fffea7177310c6cb870763c33ad9e437156331
|
data/README.md
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
# FibonacciRng
|
2
2
|
|
3
3
|
This gem implements a random number generator inspired by the famous Fibonacci
|
4
|
-
number sequence.
|
5
|
-
|
4
|
+
number sequence. To be specific, it is a normalized, cyclic Fibonacci pseudo
|
5
|
+
random number generator. So far, this generator has performed quite well when
|
6
|
+
compared to the built-in Ruby random number generator when tested with:
|
6
7
|
|
7
8
|
* A chi-squared test
|
8
9
|
* An auto-correlation test
|
@@ -170,9 +171,83 @@ generator = FibonacciRng.new
|
|
170
171
|
random_bytes = Array.new(len) { generator.byte }
|
171
172
|
```
|
172
173
|
|
174
|
+
## Theory of Operation
|
175
|
+
|
176
|
+
The random number generator used in this gem is based on a modified, cyclic
|
177
|
+
Fibonacci generator. This ring buffer design modifies the simple sequence so
|
178
|
+
that it feeds back onto itself, which in turn gives the appearance of chaos.
|
179
|
+
There is one further required modification however. Since the Fibonacci sequence
|
180
|
+
uses additions, a mechanism for preventing zeros from "swamping" the data, is
|
181
|
+
needed. This is accomplished by rotating one of the arguments to the right by
|
182
|
+
one bit. The basic outline of the generational cycle operation, with depth of
|
183
|
+
N is shown below:
|
184
|
+
![The Cycle Operation](docs/cycle.png)
|
185
|
+
<br>Notes:
|
186
|
+
* The last two elements are copies of the first two elements before
|
187
|
+
the array was transformed.
|
188
|
+
* Not shown above for brevity, the result of each addition is masked with the
|
189
|
+
value 0x1FFFFFFF before being stored. This masks off any data beyond the low
|
190
|
+
29 bits.
|
191
|
+
|
192
|
+
#### 29 bit Integers?
|
193
|
+
|
194
|
+
The random number generator masks the data in the ring buffer to 29 bit,
|
195
|
+
unsigned values. To understand this, it is first necessary to under why
|
196
|
+
masking is needed at all, and secondly, why this was done at 29 bits.
|
197
|
+
|
198
|
+
Masking at some level is required because it is needed to simulate the numeric
|
199
|
+
overflow of more primitive systems of arithmetic. In most systems, when the
|
200
|
+
limit of an integer is reached, overflow occurs with no error indication. Ruby
|
201
|
+
does not permit this to occur. To avoid overflow, Ruby transparently converts
|
202
|
+
from a simple integer (FIXNUM class) to a multiple-precision number
|
203
|
+
(BIGNUM class). The random number generator *requires* the computations to
|
204
|
+
overflow, so masking the results forces the computation to act as if they had.
|
205
|
+
|
206
|
+
So why 29 bits? Why not 32? or 64? The issue here is performance. Arithmetic
|
207
|
+
with BIGNUM values is much slower than with FIXNUM values. Further, the
|
208
|
+
conversion between FIXNUM and BIGNUM is also slow. The 29 bit size was
|
209
|
+
chosen to ensure that all computations remain with FIXNUM values without
|
210
|
+
ever reaching the threshold for the switch to BIGNUM values. In 32 bit Ruby
|
211
|
+
systems, 29 bits is the largest value that meets this requirement.
|
212
|
+
|
213
|
+
#### Code
|
214
|
+
|
215
|
+
Enough with all these words and pictures. The best way to gain insight into
|
216
|
+
ruby code is to study ruby code! What follows is the critical snippet of code
|
217
|
+
that makes this random number generator spin:
|
218
|
+
|
219
|
+
```ruby
|
220
|
+
private
|
221
|
+
|
222
|
+
#Cycle through the PRNG once.
|
223
|
+
def do_spin
|
224
|
+
@buffer[-2] = @buffer[0]
|
225
|
+
@buffer[-1] = @buffer[1]
|
226
|
+
|
227
|
+
(0...@depth).each do |idx|
|
228
|
+
tmp = @buffer[idx+2]
|
229
|
+
@buffer[idx] = (@buffer[idx+1] + ((tmp >> 1)|(tmp.odd? ? TOP : 0))) & CHOP
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
```
|
234
|
+
The above is found in the spinner.rb file. For completeness of understanding,
|
235
|
+
the following constants are defined in the fibonacci_rng.rb file:
|
236
|
+
|
237
|
+
```ruby
|
238
|
+
CHOP = 0x1FFFFFFF
|
239
|
+
TOP = 0x10000000
|
240
|
+
|
241
|
+
```
|
173
242
|
|
174
243
|
## Contributing
|
175
244
|
|
245
|
+
Creating a good pseudo random number generator is quite an undertaking. For
|
246
|
+
this reason, any input is most welcomed. There are two basic plans by which
|
247
|
+
this can be accomplished.
|
248
|
+
|
249
|
+
#### Plan A
|
250
|
+
|
176
251
|
1. Fork it
|
177
252
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
178
253
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
@@ -182,7 +257,4 @@ random_bytes = Array.new(len) { generator.byte }
|
|
182
257
|
#### Plan B
|
183
258
|
|
184
259
|
Go to the GitHub repository and raise an issue calling attention to some
|
185
|
-
aspect that could use some TLC or a suggestion or an idea.
|
186
|
-
to the issue that match the point you are trying to make. Then follow
|
187
|
-
your issue and keep up-to-date as it is worked on. All input are greatly
|
188
|
-
appreciated.
|
260
|
+
aspect that could use some TLC or a suggestion or an idea.
|
data/fibonacci_rng.gemspec
CHANGED
@@ -9,8 +9,10 @@ Gem::Specification.new do |spec|
|
|
9
9
|
spec.authors = ["Peter Camilleri"]
|
10
10
|
spec.email = ["peter.c.camilleri@gmail.com"]
|
11
11
|
spec.homepage = "http://teuthida-technologies.com/"
|
12
|
-
spec.description = "A Fibonacci inspired pseudo random number generator.
|
13
|
-
|
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."
|
14
16
|
spec.license = "MIT"
|
15
17
|
|
16
18
|
raw_list = `git ls-files`.split($/)
|
@@ -18,7 +18,8 @@ class FibonacciRng
|
|
18
18
|
@buffer[-1] = @buffer[1]
|
19
19
|
|
20
20
|
(0...@depth).each do |idx|
|
21
|
-
|
21
|
+
tmp = @buffer[idx+2]
|
22
|
+
@buffer[idx] = (@buffer[idx+1] + ((tmp >> 1)|(tmp.odd? ? TOP : 0))) & CHOP
|
22
23
|
end
|
23
24
|
end
|
24
25
|
|
data/lib/fibonacci_rng.rb
CHANGED
@@ -152,9 +152,9 @@ class FibonacciRngTester < Minitest::Test
|
|
152
152
|
def test_building_strings
|
153
153
|
rng = FibonacciRng.new(0)
|
154
154
|
|
155
|
-
assert_equal(
|
156
|
-
assert_equal('
|
157
|
-
assert_equal('
|
155
|
+
assert_equal("c}l'(q@g\\z", rng.string(10))
|
156
|
+
assert_equal('2727573312', rng.string(10, '0123456789'))
|
157
|
+
assert_equal('khto lk si', rng.string(10, 'Always look on the bright side of life.'))
|
158
158
|
end
|
159
159
|
|
160
160
|
end
|
data/tests/hasher_tests.rb
CHANGED
@@ -14,10 +14,10 @@ class FibonacciHasherTester < Minitest::Test
|
|
14
14
|
def test_that_it_can_be_read
|
15
15
|
fib = FibonacciRng.new('salt')
|
16
16
|
|
17
|
-
val =
|
17
|
+
val = 6283409396933018229308310224792996722092866776518016470611172637516158
|
18
18
|
assert_equal(val, fib.hash_value)
|
19
19
|
|
20
|
-
str = '
|
20
|
+
str = 'kxoj5k4rx6mqx1bmskx2133lrr21h8l2fs0zd1ver0ozi'
|
21
21
|
assert_equal(str, fib.hash_string)
|
22
22
|
end
|
23
23
|
|
@@ -26,13 +26,13 @@ class FibonacciHasherTester < Minitest::Test
|
|
26
26
|
|
27
27
|
fib << "The quick brown fox jumps over the lazy dog."
|
28
28
|
|
29
|
-
str = '
|
29
|
+
str = 'hoeh45h3fqlrgnynud0rg3v8q62cadr9gmxx9lomzo3hi'
|
30
30
|
assert_equal(str, fib.hash_string)
|
31
31
|
|
32
32
|
fib << nil
|
33
33
|
|
34
34
|
refute_equal(str, fib.hash_string)
|
35
|
-
str = '
|
35
|
+
str = '9anamtuoyhhb7v6s7y70m31mfsl2r2rbp4vki0vb9rnag'
|
36
36
|
assert_equal(str, fib.hash_string)
|
37
37
|
end
|
38
38
|
|
data/tools/scatter_plot.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
|
3
|
-
#A
|
3
|
+
#A Scatter Plot tester
|
4
4
|
class ScatterPlot
|
5
5
|
|
6
|
-
#Run a
|
6
|
+
#Run a scatter plot test on the random number generator.
|
7
7
|
def run(gen, max, count)
|
8
8
|
puts "Starting test"
|
9
9
|
bins = Array.new(max * 2, 0)
|
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: 0.
|
4
|
+
version: 1.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: 2016-03
|
11
|
+
date: 2016-04-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: minitest_visible
|
@@ -94,8 +94,8 @@ dependencies:
|
|
94
94
|
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: 4.0.1
|
97
|
-
description: A Fibonacci inspired pseudo random number generator.
|
98
|
-
|
97
|
+
description: A Fibonacci inspired pseudo random number generator. [Updated] The algorithm
|
98
|
+
is changed to use bit rotate instead of bit shift.
|
99
99
|
email:
|
100
100
|
- peter.c.camilleri@gmail.com
|
101
101
|
executables: []
|
@@ -146,6 +146,6 @@ rubyforge_project:
|
|
146
146
|
rubygems_version: 2.2.2
|
147
147
|
signing_key:
|
148
148
|
specification_version: 4
|
149
|
-
summary: A Fibonacci inspired pseudo random number generator.
|
149
|
+
summary: "[Updated] A Fibonacci inspired pseudo random number generator."
|
150
150
|
test_files: []
|
151
151
|
has_rdoc:
|