fibonacci_rng 0.4.3 → 1.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: 24192194041fbb6a8a907907c3d80c793a25eb1a
4
- data.tar.gz: afc6ce49588ec4aaeb8de9b1ead78bbec947f3ed
3
+ metadata.gz: 92d9ec37d3384e39e3e122ed13281ba8001c8f2a
4
+ data.tar.gz: df41080f4dc1a92a75028a4f8cce4f94f5c969ed
5
5
  SHA512:
6
- metadata.gz: b8c839b0aad4e0defdc304bdb6bbdbf40a3db783711c2961345468e7e76d119bc78db0a147a763a283b42495c228e7b0017ee6b05a1d84e75d1cfa024472206a
7
- data.tar.gz: e331373058f17ef81d5b43808f48c62e29a752de076620a2bdb9b1ad3cfcd75bdf20acae5ee032250aee3c69de302ded79a406ca560adafbb148ba9a9278c1f0
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. So far, this generator has performed quite well when compared
5
- to the built-in Ruby random number generator when tested with:
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. Apply labels
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.
@@ -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. Suitable for light duties."
13
- spec.summary = "A Fibonacci inspired pseudo random number generator."
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
- @buffer[idx] = (@buffer[idx+1] + (@buffer[idx+2] >> 1)) & CHOP
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
 
@@ -2,5 +2,5 @@
2
2
 
3
3
  #The class of Fibonacci inspired random number generators.
4
4
  class FibonacciRng
5
- VERSION = "0.4.3"
5
+ VERSION = "1.0.0"
6
6
  end
data/lib/fibonacci_rng.rb CHANGED
@@ -10,6 +10,7 @@ require_relative "fibonacci_rng/version"
10
10
  class FibonacciRng
11
11
 
12
12
  CHOP = 0x1FFFFFFF
13
+ TOP = 0x10000000
13
14
  BYTE = 0xFF
14
15
  WORD = 0xFFFF
15
16
  BASE = (CHOP+1).to_f
@@ -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('8{4y5+-N+c', rng.string(10))
156
- assert_equal('1149049996', rng.string(10, '0123456789'))
157
- assert_equal('tfes oAy', rng.string(10, 'Always look on the bright side of life.'))
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
@@ -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 = 6419946790796257801349293118951652810485853780437507149800008378866623
17
+ val = 6283409396933018229308310224792996722092866776518016470611172637516158
18
18
  assert_equal(val, fib.hash_value)
19
19
 
20
- str = 'le247zggdghf5vpcjbw2hrjf9eu8ql01wvl1fhv14bykf'
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 = 'j5jqhk7ntrze02icv38gj28efa2qrctr6mi5ejbr2p4nj'
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 = '1g5sgt443g4jcn3bfpiee1fkqoklo0i1ctkjro2vevpp0'
35
+ str = '9anamtuoyhhb7v6s7y70m31mfsl2r2rbp4vki0vb9rnag'
36
36
  assert_equal(str, fib.hash_string)
37
37
  end
38
38
 
@@ -1,9 +1,9 @@
1
1
  # coding: utf-8
2
2
 
3
- #A Chi Squared tester
3
+ #A Scatter Plot tester
4
4
  class ScatterPlot
5
5
 
6
- #Run a chi squared test on the random number generator.
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.3
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-26 00:00:00.000000000 Z
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. Suitable for light
98
- duties.
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: