cheap_random 0.9.2
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.
- data/.gitignore +4 -0
- data/LICENSE.md +20 -0
- data/README.md +85 -0
- data/cheap_random.gemspec +38 -0
- data/examples/cb.rb +18 -0
- data/examples/chi_squared.rb +48 -0
- data/examples/cr.rb +33 -0
- data/examples/make_seed.rb +23 -0
- data/lib/cheap_big_file.rb +70 -0
- data/lib/cheap_bits.rb +127 -0
- data/lib/cheap_byte_count.rb +30 -0
- data/lib/cheap_dependency.rb +40 -0
- data/lib/cheap_file.rb +47 -0
- data/lib/cheap_random.rb +175 -0
- data/lib/cheap_random/version.rb +4 -0
- data/lib/cheap_test.rb +52 -0
- data/spec/cheap_big_file_spec.rb +50 -0
- data/spec/cheap_bits_spec.rb +65 -0
- data/spec/cheap_random_spec.rb +10 -0
- data/spec/using_cheap_bits_cheap_random_spec.rb +35 -0
- metadata +89 -0
data/.gitignore
ADDED
data/LICENSE.md
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2006 - 2012 Bardi Einarsson
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
CheapRandom
|
2
|
+
============
|
3
|
+
|
4
|
+
Description
|
5
|
+
-----------
|
6
|
+
**CheapRandom** is a set of tools for pseudo random number generation from arbitrary data. The properties of the **CheapRandom seed** make convenient random number generation possible -- useful for easily repeatable software testing. The **CheapRandom algorithm** is information conserving and generally appears to produce lower chi-squared statistics than **Kernel::rand** i.e. it appears to be more random. The **CheapRandom algorithm**, an original work by Bardi Einarsson, has been in use for 6 years.
|
7
|
+
|
8
|
+
Why should one use CheapRandom?
|
9
|
+
-------------------------------
|
10
|
+
Simple and powerful: The **CheapRandom algorithm** is fast, fast enough to be practical to use in ruby as ruby. The properties of the **CheapRandom seed** (see below) make management of seeds and random data easy and verifiable.
|
11
|
+
|
12
|
+
Version
|
13
|
+
-------
|
14
|
+
v0.9.1 with comprehensive tests, developed using ruby 1.9.3 and rspec 2.10.0.
|
15
|
+
|
16
|
+
Installation
|
17
|
+
------------
|
18
|
+
Clone the repository. Create a directory called **random** in the repository root. Use **examples/make\_seed.rb** to make a **the.seed** file - (a 256 byte permutation file) from arbitrary data using the **CheapRandom default seed**.
|
19
|
+
|
20
|
+
Usage and documentation
|
21
|
+
-----------------------
|
22
|
+
Study the programs in the **examples** and **spec** directories and use the **.rb** files in the **lib** directory. See below for more information.
|
23
|
+
|
24
|
+
License
|
25
|
+
-------
|
26
|
+
Copyright (c) 2006 - 2012 Bardi Einarsson. Released under the MIT License. See the [LICENSE][license] file for further details.
|
27
|
+
|
28
|
+
[license]: https://github.com/bardibardi/cheap_random/blob/master/LICENSE.md
|
29
|
+
|
30
|
+
Create a large file of random bytes
|
31
|
+
-----------------------------------
|
32
|
+
Copy (or link) some large file (with a known hash) to the **random** directory. Use **examples/cr.rb** to randomize it into a **.random** file (the rspec tests expect **test.zip** and **test.zip.random**).
|
33
|
+
|
34
|
+
Use a large file of random bytes as a source of random numbers
|
35
|
+
--------------------------------------------------------------
|
36
|
+
Use **examples/cb.rb** to see how to use **lib/cheap\_bits.rb** to create a random number generator which uses that large file. **spec/using\_cheap\_bits\_cheap\_random\_spec.rb** uses **lib/cheap\_bits.rb** to generate random numbers. It should be compared with **spec/cheap\_random\_spec.rb** which uses **Kernel::rand**.
|
37
|
+
|
38
|
+
Manage a large file used as the source of random numbers
|
39
|
+
--------------------------------------------------------
|
40
|
+
The large file does not need to be kept if it is something like **jruby-bin-1.6.7.2.zip**. For example, one can keep a reference to its internet location, its sha1 hash and the **CheapRandom seed** file used when creating its **.random** file.
|
41
|
+
|
42
|
+
Manage the seed file used when generating .random files
|
43
|
+
-------------------------------------------------------
|
44
|
+
The **CheapRandom seed** file does not need to be kept if it is generated from the **CheapRandom default seed** and some arbitrary file, say a picture of a pet cat. One can simply keep the picture of the pet cat.
|
45
|
+
|
46
|
+
CheapBits#random(n) in lib/cheap\_bits.rb
|
47
|
+
-----------------------------------------
|
48
|
+
**random(n)**, where n is an integer greater than zero, behaves like **Kernel::rand(n)**. It is only dependent on the **.random** file, not on how the **.random** file was generated. Note that the **.random** file is treated like a ring buffer of random bits.
|
49
|
+
|
50
|
+
CheapRandom::cheap\_random3!(is\_randomizing, perm, s)
|
51
|
+
------------------------------------------------------
|
52
|
+
**cheap\_random3!** updates **s**, a byte string. **perm** is a **CheapRandom seed**, a byte string of 256 bytes all different. **is\_randomizing** is a boolean which determines whether or **s** is being randomized or un-randomized. **cheap\_random3!** returns another perm / **CheapRandom seed**. **spec/cheap\_random\_spec.rb** is used to test **cheap\_random3!**. **spec/using\_cheap\_bits\_cheap\_random\_spec.rb** is also used to test **cheap\_random3!** and to demonstrate the use of **lib/cheap\_bits.rb**.
|
53
|
+
|
54
|
+
Properties of the CheapRandom seed
|
55
|
+
----------------------------------
|
56
|
+
**CheapRandom seeds** are easy to identify. All the **CheapRandom seeds** are 256 bytes, all different.
|
57
|
+
|
58
|
+
**CheapRandom seeds** can be used to identify files. **CheapRandom seeds** are a type of hash function result. When **test.zip** is processed into **test.zip.random**, **test.zip.seed** is also produced. **test.zip.seed** is the result of **cheap\_random3!** on **test.zip**.
|
59
|
+
|
60
|
+
Given the same start seed -- **the.seed**, the result seed files **test.zip.seed** and **test.zip.random.seed** are always identical. (**test.zip.random.seed** is the result of **cheap\_random3!** on **test.zip.random**.)
|
61
|
+
|
62
|
+
make\_seed.rb
|
63
|
+
-------------
|
64
|
+
**ruby examples/make\_seed.rb pet\_cat.png** => **random/pet\_cat.png.seed** which should be copied to **random/the.seed**
|
65
|
+
|
66
|
+
cr.rb
|
67
|
+
-----
|
68
|
+
**ruby examples/cr.rb test.zip** => **random/test.zip.random** and **random/test.zip.seed**
|
69
|
+
|
70
|
+
cb.rb
|
71
|
+
-----
|
72
|
+
**ruby examples/cb.rb** => listing of byte frequencies for **random/test.zip.random**
|
73
|
+
|
74
|
+
chi\_squared.rb
|
75
|
+
---------------
|
76
|
+
**ruby examples/chi\_squared.rb test.zip** => a listing of a chi-squared statistic for **random/test.zip.random** followed by a listing of a chi-squared statistic for the same amount of data generated by **Kernel::rand 256**
|
77
|
+
|
78
|
+
Test
|
79
|
+
----
|
80
|
+
Make sure that the **random** directory exists and contains the files **pet\_cat.png**, **pet\_cat.png.seed**, **the.seed**, **test.zip** and **test.zip.random** as described above. Run **rspec**. The tests are quite comprehensive.
|
81
|
+
|
82
|
+
Other possible uses of CheapRandom
|
83
|
+
----------------------------------
|
84
|
+
There are a number of intriguing possible uses for the **CheapRandom algorithm** and the **CheapRandom seed** properties beyond random number generation.
|
85
|
+
|
@@ -0,0 +1,38 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'cheap_random'
|
3
|
+
s.version = '0.9.2'
|
4
|
+
s.date = '2012-06-12'
|
5
|
+
s.summary = 'pseudo random number generation from arbitrary data'
|
6
|
+
s.description = <<-EOT
|
7
|
+
**CheapRandom** is a set of tools for pseudo random number generation from arbitrary data. The properties of the **CheapRandom seed** make convenient random number generation possible -- useful for easily repeatable software testing. The **CheapRandom algorithm** is information conserving and generally appears to produce lower chi-squared statistics than **Kernel::rand** i.e. it appears to be more random. The **CheapRandom algorithm**, an original work by Bardi Einarsson, has been in use for 6 years.
|
8
|
+
EOT
|
9
|
+
|
10
|
+
s.authors = ['Bardi Einarsson']
|
11
|
+
s.email = ['bardi_e@hotmail.com']
|
12
|
+
s.homepage = 'https://github.com/bardibardi/cheap_random'
|
13
|
+
s.required_ruby_version = '>= 1.9.2'
|
14
|
+
s.add_development_dependency('rspec', '~> 2.2')
|
15
|
+
s.files = %w(
|
16
|
+
cheap_random.gemspec
|
17
|
+
.gitignore
|
18
|
+
LICENSE.md
|
19
|
+
README.md
|
20
|
+
examples/cb.rb
|
21
|
+
examples/chi_squared.rb
|
22
|
+
examples/cr.rb
|
23
|
+
examples/make_seed.rb
|
24
|
+
lib/cheap_big_file.rb
|
25
|
+
lib/cheap_bits.rb
|
26
|
+
lib/cheap_byte_count.rb
|
27
|
+
lib/cheap_dependency.rb
|
28
|
+
lib/cheap_file.rb
|
29
|
+
lib/cheap_random.rb
|
30
|
+
lib/cheap_random/version.rb
|
31
|
+
lib/cheap_test.rb
|
32
|
+
spec/cheap_big_file_spec.rb
|
33
|
+
spec/cheap_bits_spec.rb
|
34
|
+
spec/cheap_random_spec.rb
|
35
|
+
spec/using_cheap_bits_cheap_random_spec.rb
|
36
|
+
)
|
37
|
+
end
|
38
|
+
|
data/examples/cb.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
p File.absolute_path(__FILE__)
|
2
|
+
CHEAP_DEPENDENCY_ENV_NAME = 'CD'
|
3
|
+
load File.expand_path('../lib/cheap_dependency.rb', File.dirname(__FILE__))
|
4
|
+
CheapDependency.cd_get('cheap_bits')
|
5
|
+
|
6
|
+
BASE_DIR = File.expand_path('../random', File.dirname(__FILE__))
|
7
|
+
RANDOM_FILE_SOURCE = "test.zip"
|
8
|
+
XLAT_EXT = '.random'
|
9
|
+
CB = CheapBits.new(9, BASE_DIR, RANDOM_FILE_SOURCE, XLAT_EXT)
|
10
|
+
|
11
|
+
def l
|
12
|
+
load File.absolute_path(__FILE__)
|
13
|
+
end
|
14
|
+
|
15
|
+
if !CheapDependency.cd_test?
|
16
|
+
p CB.get_many_random 441241, 256
|
17
|
+
end
|
18
|
+
|
@@ -0,0 +1,48 @@
|
|
1
|
+
p File.absolute_path(__FILE__)
|
2
|
+
CHEAP_DEPENDENCY_ENV_NAME = 'CD'
|
3
|
+
load File.expand_path('../lib/cheap_dependency.rb', File.dirname(__FILE__))
|
4
|
+
CheapDependency.cd_get('cheap_byte_count')
|
5
|
+
|
6
|
+
BASE_DIR = File.expand_path('../random', File.dirname(__FILE__))
|
7
|
+
XLAT_EXT = '.random'
|
8
|
+
|
9
|
+
def byte_count_array(file_name)
|
10
|
+
afn = "#{BASE_DIR}/#{file_name}#{XLAT_EXT}"
|
11
|
+
CheapByteCount.byte_count_array_from_file afn
|
12
|
+
end
|
13
|
+
|
14
|
+
def chi(a)
|
15
|
+
d = a.length
|
16
|
+
n = a.reduce(:+)
|
17
|
+
p n
|
18
|
+
e = (n*1.0)/d
|
19
|
+
p e
|
20
|
+
c = a.reduce(0) {|acc, r| acc + (r - e)*(r - e)/e}
|
21
|
+
[d - 1, c]
|
22
|
+
end
|
23
|
+
|
24
|
+
def rand_array(a)
|
25
|
+
d = a.length
|
26
|
+
n = a.reduce(:+)
|
27
|
+
rand_a = []
|
28
|
+
d.times {rand_a << 0}
|
29
|
+
n.times {i = rand(d); rand_a[i] += 1}
|
30
|
+
rand_a
|
31
|
+
end
|
32
|
+
|
33
|
+
def chi_of_bytes(file_name)
|
34
|
+
bca = byte_count_array file_name
|
35
|
+
chi bca
|
36
|
+
end
|
37
|
+
|
38
|
+
def l
|
39
|
+
load File.absolute_path(__FILE__)
|
40
|
+
end
|
41
|
+
|
42
|
+
if !CheapDependency.cd_test?
|
43
|
+
file_name = ARGV[0]
|
44
|
+
bca = byte_count_array file_name
|
45
|
+
p chi(bca)
|
46
|
+
p chi(rand_array(bca))
|
47
|
+
end
|
48
|
+
|
data/examples/cr.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
p File.absolute_path(__FILE__)
|
2
|
+
CHEAP_DEPENDENCY_ENV_NAME = 'CD'
|
3
|
+
load File.expand_path('../lib/cheap_dependency.rb', File.dirname(__FILE__))
|
4
|
+
CheapDependency.cd_get(
|
5
|
+
'cheap_random',
|
6
|
+
'cheap_file',
|
7
|
+
'cheap_big_file'
|
8
|
+
)
|
9
|
+
if CheapDependency.cd_test?
|
10
|
+
CheapDependency.cd_get 'cheap_test'
|
11
|
+
end
|
12
|
+
|
13
|
+
BASE_DIR = File.expand_path('../random', File.dirname(__FILE__))
|
14
|
+
# SEED = CheapRandom.cheap_seed!('secret' * 100)
|
15
|
+
# CheapFile.to_file "#{BASE_DIR}/the.seed", SEED
|
16
|
+
SEED = CheapFile.from_file "#{BASE_DIR}/the.seed"
|
17
|
+
XLAT = lambda {|is_do, perm, s| CheapRandom.cheap_random3! is_do, perm, s}
|
18
|
+
XLAT_EXT = '.random'
|
19
|
+
# CheapFile.new(BASE_DIR, XLAT_EXT, SEED, XLAT).xlat_small_file file_name
|
20
|
+
CF = CheapBigFile.new(9, BASE_DIR, XLAT_EXT, SEED, XLAT)
|
21
|
+
|
22
|
+
def l
|
23
|
+
load File.absolute_path(__FILE__)
|
24
|
+
end
|
25
|
+
|
26
|
+
if !CheapDependency.cd_test?
|
27
|
+
file_name = ARGV[0]
|
28
|
+
generated_seed = CF.xlat_big_file file_name
|
29
|
+
seed_file_name = "#{BASE_DIR}/#{file_name}.seed"
|
30
|
+
CheapFile.to_file seed_file_name, generated_seed
|
31
|
+
p generated_seed.each_byte.inject([], :<<)
|
32
|
+
end
|
33
|
+
|
@@ -0,0 +1,23 @@
|
|
1
|
+
p File.absolute_path(__FILE__)
|
2
|
+
CHEAP_DEPENDENCY_ENV_NAME = 'CD'
|
3
|
+
load File.expand_path('../lib/cheap_dependency.rb', File.dirname(__FILE__))
|
4
|
+
CheapDependency.cd_get(
|
5
|
+
'cheap_random',
|
6
|
+
'cheap_file',
|
7
|
+
'cheap_big_file'
|
8
|
+
)
|
9
|
+
|
10
|
+
BASE_DIR = File.expand_path('../random', File.dirname(__FILE__))
|
11
|
+
SEED = CheapRandom.reverse_perm
|
12
|
+
XLAT = lambda {|is_do, perm, s| CheapRandom.cheap_random3! is_do, perm, s}
|
13
|
+
XLAT_EXT = '.random'
|
14
|
+
CF = CheapBigFile.new(9, BASE_DIR, XLAT_EXT, SEED, XLAT)
|
15
|
+
|
16
|
+
if !CheapDependency.cd_test?
|
17
|
+
file_name = ARGV[0]
|
18
|
+
generated_seed = CF.xlat_big_file file_name, false
|
19
|
+
seed_file_name = "#{BASE_DIR}/#{file_name}.seed"
|
20
|
+
CheapFile.to_file seed_file_name, generated_seed
|
21
|
+
p generated_seed.each_byte.inject([], :<<)
|
22
|
+
end
|
23
|
+
|
@@ -0,0 +1,70 @@
|
|
1
|
+
class CheapBigFile < CheapFile
|
2
|
+
|
3
|
+
def self.readblock(fd_in, half_block_size)
|
4
|
+
fd_in.readpartial half_block_size
|
5
|
+
rescue EOFError
|
6
|
+
nil
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.write(fd_out, s)
|
10
|
+
fd_out.write s if fd_out
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.wipe!(s)
|
14
|
+
(0...s.length).each {|i| s.setbyte i, 255}
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.eof_sout_from_blocks(half_block_size, s0, s1)
|
18
|
+
return [true, nil] unless s0
|
19
|
+
return [true, s0] unless s1
|
20
|
+
return [true, s0 + s1] if half_block_size > s1.length
|
21
|
+
[false, s0]
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.xlat(fd_in, fd_out, half_block_size, is_do, seed, xlat_lambda)
|
25
|
+
perm = seed
|
26
|
+
s0 = readblock fd_in, half_block_size
|
27
|
+
eof = false
|
28
|
+
while !eof do
|
29
|
+
s1 = readblock fd_in, half_block_size
|
30
|
+
eof, sout = eof_sout_from_blocks half_block_size, s0, s1
|
31
|
+
if sout
|
32
|
+
perm = xlat_lambda.call is_do, perm, sout
|
33
|
+
write fd_out, sout
|
34
|
+
end
|
35
|
+
if sout.length > half_block_size
|
36
|
+
wipe! s0
|
37
|
+
wipe! s1
|
38
|
+
end
|
39
|
+
s0 = s1
|
40
|
+
end
|
41
|
+
perm
|
42
|
+
end
|
43
|
+
|
44
|
+
def initialize(block_size_exponent, base_dir, xlat_ext, seed, xlat_lambda)
|
45
|
+
super base_dir, xlat_ext, seed, xlat_lambda
|
46
|
+
@block_size = 1 << block_size_exponent
|
47
|
+
@half_block_size = @block_size >> 1
|
48
|
+
end
|
49
|
+
|
50
|
+
def xlat_big(fd_in, fd_out, is_do)
|
51
|
+
self.class.xlat(fd_in, fd_out, @half_block_size, is_do, @seed, @xlat)
|
52
|
+
end
|
53
|
+
|
54
|
+
def xlat_big_file(fn, should_write = true)
|
55
|
+
is_do, afn, new_afn = self.class.is_do_afn_new_afn @base_dir, fn, @xlat_ext
|
56
|
+
perm = nil
|
57
|
+
File.open(afn, 'rb') do |fd_in|
|
58
|
+
if should_write
|
59
|
+
File.open(new_afn, 'wb') do |fd_out|
|
60
|
+
perm = xlat_big(fd_in, fd_out, is_do)
|
61
|
+
end
|
62
|
+
else
|
63
|
+
perm = xlat_big(fd_in, nil, is_do)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
perm
|
67
|
+
end
|
68
|
+
|
69
|
+
end #CheapBigFile
|
70
|
+
|
data/lib/cheap_bits.rb
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
class CheapBits
|
2
|
+
|
3
|
+
def self.readblock(fd_in, block_size)
|
4
|
+
fd_in.readpartial block_size
|
5
|
+
rescue EOFError
|
6
|
+
nil
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.getbit(random_block, bit_offset)
|
10
|
+
byte_offset = bit_offset >> 3
|
11
|
+
byte_bit_offset = bit_offset - (byte_offset << 3)
|
12
|
+
byte = random_block.getbyte(byte_offset)
|
13
|
+
1 & (byte >> (7 - byte_bit_offset))
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(block_size_exponent, base_dir, fn, xlat_ext)
|
17
|
+
@afn = "#{base_dir}/#{fn}#{xlat_ext}"
|
18
|
+
@block_size = 1 << block_size_exponent
|
19
|
+
@fd_in = nil
|
20
|
+
@current_block = ''
|
21
|
+
@bits_total = 0
|
22
|
+
@bit_offset = 0
|
23
|
+
end
|
24
|
+
|
25
|
+
def readblock
|
26
|
+
open unless @fd_in
|
27
|
+
s = self.class.readblock @fd_in, @block_size
|
28
|
+
if !s
|
29
|
+
rewind
|
30
|
+
s = self.class.readblock @fd_in, @block_size
|
31
|
+
end
|
32
|
+
@current_block = s
|
33
|
+
@bits_total = @current_block.length << 3
|
34
|
+
@bit_offset = 0
|
35
|
+
s
|
36
|
+
end
|
37
|
+
|
38
|
+
def close
|
39
|
+
@fd_in.close if @fd_in
|
40
|
+
end
|
41
|
+
|
42
|
+
def open
|
43
|
+
@fd_in = File.open(@afn)
|
44
|
+
end
|
45
|
+
|
46
|
+
def rewind
|
47
|
+
close
|
48
|
+
open
|
49
|
+
@current_block = ''
|
50
|
+
@bits_total = 0
|
51
|
+
@bit_offset = 0
|
52
|
+
end
|
53
|
+
|
54
|
+
def getbit
|
55
|
+
readblock if @bit_offset == @bits_total
|
56
|
+
bit = self.class.getbit(@current_block, @bit_offset)
|
57
|
+
@bit_offset += 1
|
58
|
+
bit
|
59
|
+
end
|
60
|
+
|
61
|
+
def getbits_as_number(how_many)
|
62
|
+
return nil unless how_many > 0
|
63
|
+
first_one_bit_found = false
|
64
|
+
bits = 0
|
65
|
+
how_many.times do
|
66
|
+
bit = getbit
|
67
|
+
if first_one_bit_found
|
68
|
+
bits = bits << 1
|
69
|
+
bits += bit
|
70
|
+
else
|
71
|
+
if 1 == bit
|
72
|
+
bits = 1
|
73
|
+
first_one_bit_found = true
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
bits
|
78
|
+
end
|
79
|
+
|
80
|
+
def random(n)
|
81
|
+
return nil unless n > 0
|
82
|
+
return 0 if 1 == n
|
83
|
+
bits_needed = 0
|
84
|
+
power_of_two = 1
|
85
|
+
while n > power_of_two
|
86
|
+
bits_needed += 1
|
87
|
+
power_of_two = power_of_two << 1
|
88
|
+
end
|
89
|
+
bits = power_of_two
|
90
|
+
while bits >= n
|
91
|
+
bits = getbits_as_number bits_needed
|
92
|
+
end
|
93
|
+
bits
|
94
|
+
end
|
95
|
+
|
96
|
+
def broken_random(n)
|
97
|
+
current = n
|
98
|
+
acc = 0
|
99
|
+
while current > 0
|
100
|
+
odd = 1 == 1 & current
|
101
|
+
current = current >> 1
|
102
|
+
if current > 0
|
103
|
+
acc += current if 1 == getbit
|
104
|
+
end
|
105
|
+
if odd
|
106
|
+
if (1 == getbit)
|
107
|
+
acc += 1
|
108
|
+
else
|
109
|
+
current += 1
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
acc - 1
|
114
|
+
end
|
115
|
+
|
116
|
+
def get_many_random(how_many, what)
|
117
|
+
a = []
|
118
|
+
what.times {a << 0}
|
119
|
+
how_many.times do
|
120
|
+
r = random(what)
|
121
|
+
a[r] += 1
|
122
|
+
end
|
123
|
+
a
|
124
|
+
end
|
125
|
+
|
126
|
+
end #CheapBits
|
127
|
+
|
@@ -0,0 +1,30 @@
|
|
1
|
+
class CheapByteCount
|
2
|
+
|
3
|
+
def self.readblock(fd_in)
|
4
|
+
fd_in.readpartial 4096
|
5
|
+
rescue EOFError
|
6
|
+
nil
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.byte_count_array_from_file(file_name)
|
10
|
+
bca = nil
|
11
|
+
File.open(file_name, 'rb') do |fd_in|
|
12
|
+
bca = new(fd_in).byte_count_array
|
13
|
+
end
|
14
|
+
bca
|
15
|
+
end
|
16
|
+
|
17
|
+
attr_reader :byte_count_array
|
18
|
+
|
19
|
+
def initialize(fd_in)
|
20
|
+
@byte_count_array = []
|
21
|
+
256.times {@byte_count_array << 0}
|
22
|
+
while s = self.class.readblock(fd_in) do
|
23
|
+
s.each_byte do |b|
|
24
|
+
@byte_count_array[b] += 1
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module CheapDependency
|
2
|
+
|
3
|
+
def self.cd_test?
|
4
|
+
'test' == ENV[CHEAP_DEPENDENCY_ENV_NAME]
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.cd_test(load)
|
8
|
+
ENV[CHEAP_DEPENDENCY_ENV_NAME] = 'test' if load
|
9
|
+
ENV[CHEAP_DEPENDENCY_ENV_NAME] = 'no_test' unless load
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.cd_exists_absolute_fn(relative_fn_base)
|
13
|
+
afn = File.expand_path("#{relative_fn_base}.rb", File.dirname(__FILE__))
|
14
|
+
[File.exists?(afn), afn]
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.cd_require_relative(relative_fn_base)
|
18
|
+
exists, afn = cd_exists_absolute_fn relative_fn_base
|
19
|
+
require_relative relative_fn_base if exists
|
20
|
+
require relative_fn_base unless exists
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.cd_load_relative(relative_fn_base)
|
24
|
+
exists, afn = cd_exists_absolute_fn relative_fn_base
|
25
|
+
load afn if exists
|
26
|
+
require relative_fn_base unless exists
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.cd_get(*relative_fn_base_array)
|
30
|
+
relative_fn_base_array.each do |relative_fn_base|
|
31
|
+
if cd_test?
|
32
|
+
cd_load_relative relative_fn_base
|
33
|
+
else
|
34
|
+
cd_require_relative relative_fn_base
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
data/lib/cheap_file.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
class CheapFile
|
2
|
+
|
3
|
+
def self.file?(afn)
|
4
|
+
File.file? afn
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.from_file(afn)
|
8
|
+
f = File.new afn, 'rb'
|
9
|
+
s = f.read
|
10
|
+
s.force_encoding 'ASCII-8BIT'
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.to_file(afn, s)
|
14
|
+
f = File.new afn, "wb"
|
15
|
+
f.write s
|
16
|
+
f.close
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.is_do_afn_new_afn(base_dir, fn, xlat_ext)
|
20
|
+
afn = "#{base_dir}/#{fn}"
|
21
|
+
xlat_match = afn =~ Regexp.new("\\#{xlat_ext}$")
|
22
|
+
new_afn = afn[0, xlat_match] if xlat_match
|
23
|
+
new_afn = afn + xlat_ext unless xlat_match
|
24
|
+
[!xlat_match, afn, new_afn]
|
25
|
+
end
|
26
|
+
|
27
|
+
def initialize(base_dir, xlat_ext, seed, xlat_lambda)
|
28
|
+
@base_dir = base_dir
|
29
|
+
@xlat_ext = xlat_ext
|
30
|
+
@seed = seed
|
31
|
+
@xlat = xlat_lambda
|
32
|
+
end
|
33
|
+
|
34
|
+
def xlat_small(is_do, s)
|
35
|
+
@xlat.call is_do, @seed, s
|
36
|
+
end
|
37
|
+
|
38
|
+
def xlat_small_file(fn, should_write = true)
|
39
|
+
is_do, afn, new_afn = self.class.is_do_afn_new_afn @base_dir, fn, @xlat_ext
|
40
|
+
s = self.class.from_file afn
|
41
|
+
perm = xlat_small is_do, s
|
42
|
+
self.class.to_file new_afn, s if should_write
|
43
|
+
perm
|
44
|
+
end
|
45
|
+
|
46
|
+
end #CheapFile
|
47
|
+
|
data/lib/cheap_random.rb
ADDED
@@ -0,0 +1,175 @@
|
|
1
|
+
module CheapRandom
|
2
|
+
|
3
|
+
def self.subperm(perm, length)
|
4
|
+
result = ' ' * length
|
5
|
+
idx = 0
|
6
|
+
(0..255).each do |x|
|
7
|
+
if perm.getbyte(x) < length
|
8
|
+
result.setbyte idx, perm.getbyte(x)
|
9
|
+
idx += 1
|
10
|
+
end
|
11
|
+
end
|
12
|
+
result
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.permute(perm, buffer, offset, length)
|
16
|
+
disp = 0
|
17
|
+
temp = 0
|
18
|
+
y = 0
|
19
|
+
(0...length).each do |x|
|
20
|
+
while perm.getbyte(y) >= length do
|
21
|
+
y += 1
|
22
|
+
end
|
23
|
+
disp = offset + perm.getbyte(y)
|
24
|
+
y += 1
|
25
|
+
temp = buffer.getbyte disp
|
26
|
+
buffer.setbyte disp, buffer.getbyte(offset + x)
|
27
|
+
buffer.setbyte(offset + x, temp)
|
28
|
+
end
|
29
|
+
nil
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.unpermute(perm, buffer, offset, length)
|
33
|
+
disp = 0
|
34
|
+
temp = 0
|
35
|
+
y = 255
|
36
|
+
(1..length).each do |x|
|
37
|
+
while perm.getbyte(y) >= length do
|
38
|
+
y -= 1
|
39
|
+
end
|
40
|
+
disp = offset + perm.getbyte(y)
|
41
|
+
y -= 1
|
42
|
+
temp = buffer.getbyte disp
|
43
|
+
buffer.setbyte disp, buffer.getbyte(offset + length - x)
|
44
|
+
buffer.setbyte(offset + length - x, temp)
|
45
|
+
end
|
46
|
+
nil
|
47
|
+
end
|
48
|
+
|
49
|
+
# is_randomizing is a boolean
|
50
|
+
# cheap_random with is_randomizing true, randomizes
|
51
|
+
# cheap_random with is_randomizing false, un-randomizes
|
52
|
+
# perm is a read only string of length 256 with each
|
53
|
+
# byte represented once
|
54
|
+
# perm is cheap_random's seed
|
55
|
+
# nextperm is a writeable string of length 256
|
56
|
+
# comes in as a copy of perm
|
57
|
+
# it is the next seed for use in chain seeding
|
58
|
+
# translation is a buffer needed for perm reversed as a substitution transformation
|
59
|
+
# buffer is read as unrandomized text
|
60
|
+
# and written as randomized text
|
61
|
+
# offset is a pointer into the buffer
|
62
|
+
# length is from 1 to 256
|
63
|
+
# it is the number of bytes to process
|
64
|
+
# starting at offset in buffer
|
65
|
+
def self.cheap_random7(is_randomizing, perm, nextperm, translation, buffer, offset, length)
|
66
|
+
if is_randomizing then
|
67
|
+
random_cheap_random(perm, nextperm, buffer, offset, length)
|
68
|
+
else
|
69
|
+
(0..255).each do |x|
|
70
|
+
translation.setbyte perm.getbyte(x), x
|
71
|
+
end
|
72
|
+
unrandom_cheap_random(perm, nextperm, translation, buffer, offset, length)
|
73
|
+
end
|
74
|
+
return nil
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.random_cheap_random(perm, nextperm, buffer, offset, length)
|
78
|
+
disp = 0
|
79
|
+
temp = 0
|
80
|
+
y = 0
|
81
|
+
(0...length).each do |x|
|
82
|
+
disp = offset + x
|
83
|
+
y = buffer.getbyte(disp) ^ perm.getbyte(x)
|
84
|
+
y = perm.getbyte((y + x + x + x) & 255)
|
85
|
+
buffer.setbyte disp, y
|
86
|
+
temp = nextperm.getbyte x
|
87
|
+
nextperm.setbyte x, nextperm.getbyte(y)
|
88
|
+
nextperm.setbyte y, temp
|
89
|
+
end
|
90
|
+
y = 0
|
91
|
+
(0...length).each do |x|
|
92
|
+
while perm.getbyte(y) >= length do
|
93
|
+
y += 1
|
94
|
+
end
|
95
|
+
disp = offset + perm.getbyte(y)
|
96
|
+
y += 1
|
97
|
+
temp = buffer.getbyte disp
|
98
|
+
buffer.setbyte disp, buffer.getbyte(offset + x)
|
99
|
+
buffer.setbyte(offset + x, temp)
|
100
|
+
end
|
101
|
+
nil
|
102
|
+
end
|
103
|
+
|
104
|
+
def self.unrandom_cheap_random(perm, nextperm, translation, buffer, offset, length)
|
105
|
+
disp = 0
|
106
|
+
temp = 0
|
107
|
+
y = 255
|
108
|
+
(1..length).each do |x|
|
109
|
+
while perm.getbyte(y) >= length do
|
110
|
+
y -= 1
|
111
|
+
end
|
112
|
+
disp = offset + perm.getbyte(y)
|
113
|
+
y -= 1
|
114
|
+
temp = buffer.getbyte disp
|
115
|
+
buffer.setbyte disp, buffer.getbyte(offset + length - x)
|
116
|
+
buffer.setbyte(offset + length - x, temp)
|
117
|
+
end
|
118
|
+
y = 0
|
119
|
+
(0...length).each do |x|
|
120
|
+
disp = offset + x
|
121
|
+
y = buffer.getbyte disp
|
122
|
+
buffer.setbyte(disp, ((translation.getbyte(y) + 768 - x - x - x) & 255) ^ perm.getbyte(x))
|
123
|
+
temp = nextperm.getbyte(x)
|
124
|
+
nextperm.setbyte x, nextperm.getbyte(y)
|
125
|
+
nextperm.setbyte y, temp
|
126
|
+
end
|
127
|
+
nil
|
128
|
+
end
|
129
|
+
|
130
|
+
def self.next_block_size(size)
|
131
|
+
return 256 if size > 511
|
132
|
+
return size if size <= 256
|
133
|
+
size - (size >> 1)
|
134
|
+
end
|
135
|
+
|
136
|
+
# length > 0
|
137
|
+
def self.cheap_random5!(is_randomizing, startperm, buffer, offset, length)
|
138
|
+
nextperm = startperm + 'NEXT'
|
139
|
+
perm = (' ' * 256) + 'PERM'
|
140
|
+
translation = (' ' * 256) + 'TRAN'
|
141
|
+
len = length
|
142
|
+
off = offset
|
143
|
+
while len > 0 do
|
144
|
+
bs = next_block_size len
|
145
|
+
(0..255).each do |x|
|
146
|
+
perm.setbyte x, nextperm.getbyte(x)
|
147
|
+
end
|
148
|
+
cheap_random7(is_randomizing, perm, nextperm, translation, buffer, off, bs)
|
149
|
+
off += bs
|
150
|
+
len -= bs
|
151
|
+
end
|
152
|
+
nextperm[0..255]
|
153
|
+
end
|
154
|
+
|
155
|
+
def self.reverse_perm
|
156
|
+
s = ' ' * 256
|
157
|
+
(0..255).each do |x|
|
158
|
+
s.setbyte(x, 255 - x)
|
159
|
+
end
|
160
|
+
s
|
161
|
+
end
|
162
|
+
|
163
|
+
def self.cheap_random3!(is_randomizing, perm, s)
|
164
|
+
cheap_random5!(is_randomizing, perm, s, 0, s.length)
|
165
|
+
end
|
166
|
+
|
167
|
+
def self.cheap_seed!(s)
|
168
|
+
ip = reverse_perm
|
169
|
+
result = cheap_random3!(true, ip, s)
|
170
|
+
cheap_random3!(false, ip, s)
|
171
|
+
result
|
172
|
+
end
|
173
|
+
|
174
|
+
end # CheapRandom
|
175
|
+
|
data/lib/cheap_test.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
module CheapTest
|
2
|
+
|
3
|
+
def self.random(n)
|
4
|
+
rand(n)
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.cheap_perm_check!(perm, s)
|
8
|
+
return nil if length > 256
|
9
|
+
CheapRandom::permute perm, s, 0, length
|
10
|
+
CheapRandom::unpermute perm, s, 0, length
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.random_string(len)
|
14
|
+
s = ' ' * len
|
15
|
+
(0...len).each do |x|
|
16
|
+
s.setbyte x, random(256)
|
17
|
+
end
|
18
|
+
s
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.identity_perm
|
22
|
+
s = ' ' * 256
|
23
|
+
(0..255).each do |x|
|
24
|
+
s.setbyte x, x
|
25
|
+
end
|
26
|
+
s
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.random_perm
|
30
|
+
s = identity_perm
|
31
|
+
i = 256
|
32
|
+
(0..255).each do |x|
|
33
|
+
temp = s.getbyte x
|
34
|
+
y = x + random(i)
|
35
|
+
s.setbyte x, s.getbyte(y)
|
36
|
+
s.setbyte y, temp
|
37
|
+
i -= 1
|
38
|
+
end
|
39
|
+
s
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.is_reversible?
|
43
|
+
s = random_string(random(10000))
|
44
|
+
x = s + 'X'
|
45
|
+
ip = random_perm
|
46
|
+
CheapRandom::cheap_random3!(true, ip, s)
|
47
|
+
CheapRandom::cheap_random3!(false, ip, s)
|
48
|
+
s == x[0...(s.length)]
|
49
|
+
end
|
50
|
+
|
51
|
+
end #CheapTest
|
52
|
+
|
@@ -0,0 +1,50 @@
|
|
1
|
+
load 'cheap_file.rb'
|
2
|
+
load 'cheap_big_file.rb'
|
3
|
+
require 'stringio'
|
4
|
+
|
5
|
+
module CheapTest
|
6
|
+
|
7
|
+
FAKE_XLAT = lambda do |is_do, perm, s|
|
8
|
+
return [s.length] unless perm
|
9
|
+
perm << s.length
|
10
|
+
end
|
11
|
+
|
12
|
+
CF = CheapBigFile.new(9, nil, nil, nil, FAKE_XLAT)
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "CheapBigFile's block handling for CheapRandom" do
|
17
|
+
it "should return blocks usable as 256 byte chunks" do
|
18
|
+
(257..3000).each do |i|
|
19
|
+
fd_in = StringIO.new('x' * i)
|
20
|
+
a = CheapTest::CF.xlat_big fd_in, nil, CheapTest::FAKE_XLAT
|
21
|
+
len = a.length
|
22
|
+
exist = len > 0
|
23
|
+
exist.should == true
|
24
|
+
total = a.reduce(:+)
|
25
|
+
total.should == i
|
26
|
+
last_block_big_enough = a[-1] > 255
|
27
|
+
last_block_big_enough.should == true
|
28
|
+
a[0..-2].each do |size|
|
29
|
+
big_enough = size > 255
|
30
|
+
big_enough.should == true
|
31
|
+
multiple_of_256 = 0 == (size % 256)
|
32
|
+
multiple_of_256.should == true
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "CheapBigFile's block handling for CheapRandom" do
|
39
|
+
it "should return small blocks less than size 257" do
|
40
|
+
(1..256).each do |i|
|
41
|
+
fd_in = StringIO.new('x' * i)
|
42
|
+
a = CheapTest::CF.xlat_big fd_in, nil, CheapTest::FAKE_XLAT
|
43
|
+
len = a.length
|
44
|
+
len.should == 1
|
45
|
+
same_size = a[-1] == i
|
46
|
+
same_size.should == true
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
@@ -0,0 +1,65 @@
|
|
1
|
+
load 'cheap_file.rb'
|
2
|
+
load 'cheap_big_file.rb'
|
3
|
+
load 'cheap_bits.rb'
|
4
|
+
load 'cheap_byte_count.rb'
|
5
|
+
|
6
|
+
module CheapTest
|
7
|
+
|
8
|
+
BASE_DIR ||= File.expand_path('../random', File.dirname(__FILE__))
|
9
|
+
RANDOM_FILE_SOURCE ||= "test.zip"
|
10
|
+
XLAT_EXT ||= '.random'
|
11
|
+
CB ||= CheapBits.new(9, BASE_DIR, RANDOM_FILE_SOURCE, XLAT_EXT)
|
12
|
+
FILE_NAME = "#{BASE_DIR}/#{RANDOM_FILE_SOURCE}#{XLAT_EXT}"
|
13
|
+
|
14
|
+
def self.random(n)
|
15
|
+
CB.random n
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "CheapBits random(1)" do
|
21
|
+
it "should return 0" do
|
22
|
+
is_zero = 0 == CheapTest.random(1)
|
23
|
+
is_zero.should == true
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "CheapBits random" do
|
28
|
+
it "should get an in bounds number" do
|
29
|
+
inbounds = 256 > CheapTest.random(256)
|
30
|
+
inbounds.should == true
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "CheapBits getbit" do
|
35
|
+
fake_random_block = ' ' * 8
|
36
|
+
(0..7).each {|i| fake_random_block.setbyte(7 - i, 1 << i) }
|
37
|
+
it "should get the correct bit" do
|
38
|
+
(0..7).each do |i|
|
39
|
+
bit = CheapBits.getbit fake_random_block, ((i << 3) + i)
|
40
|
+
bit.should == 1
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "CheapBits get_many_random" do
|
46
|
+
it "should be plausibly random" do
|
47
|
+
a = CheapTest::CB.get_many_random 30000, 3
|
48
|
+
a.each do |i|
|
49
|
+
plausible = i > 9750
|
50
|
+
plausible.should == true
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe "CheapBits get_many_random" do
|
56
|
+
it "should process all bytes in file" do
|
57
|
+
bca = CheapByteCount.byte_count_array_from_file CheapTest::FILE_NAME
|
58
|
+
how_many = File.new(CheapTest::FILE_NAME).size
|
59
|
+
CheapTest::CB.rewind
|
60
|
+
a = CheapTest::CB.get_many_random how_many, 256
|
61
|
+
same_byte_count_profile = bca == a
|
62
|
+
same_byte_count_profile.should == true
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
@@ -0,0 +1,35 @@
|
|
1
|
+
load 'cheap_random.rb'
|
2
|
+
load 'cheap_test.rb'
|
3
|
+
|
4
|
+
load 'cheap_file.rb'
|
5
|
+
load 'cheap_big_file.rb'
|
6
|
+
load 'cheap_bits.rb'
|
7
|
+
|
8
|
+
module CheapTest
|
9
|
+
|
10
|
+
BASE_DIR ||= File.expand_path('../random', File.dirname(__FILE__))
|
11
|
+
RANDOM_FILE_SOURCE ||= "test.zip"
|
12
|
+
XLAT_EXT ||= '.random'
|
13
|
+
CB ||= CheapBits.new(9, BASE_DIR, RANDOM_FILE_SOURCE, XLAT_EXT)
|
14
|
+
|
15
|
+
def self.random(n)
|
16
|
+
CB.random n
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "CheapTest random" do
|
22
|
+
it "should be using the CheapBits RANDOM_FILE_SOURCE" do
|
23
|
+
bit = CheapTest.random 2
|
24
|
+
is_a_bit = 2 > bit
|
25
|
+
is_a_bit.should == true
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "CheapRandom randomizer" do
|
30
|
+
it "should reversibly randomize arbitrary strings when using arbitrary seed permutations" do
|
31
|
+
reversed = CheapTest.is_reversible?
|
32
|
+
reversed.should == true
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
metadata
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cheap_random
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.9.2
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Bardi Einarsson
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-06-12 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '2.2'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '2.2'
|
30
|
+
description: ! ' **CheapRandom** is a set of tools for pseudo random number generation
|
31
|
+
from arbitrary data. The properties of the **CheapRandom seed** make convenient
|
32
|
+
random number generation possible -- useful for easily repeatable software testing.
|
33
|
+
The **CheapRandom algorithm** is information conserving and generally appears to
|
34
|
+
produce lower chi-squared statistics than **Kernel::rand** i.e. it appears to be
|
35
|
+
more random. The **CheapRandom algorithm**, an original work by Bardi Einarsson,
|
36
|
+
has been in use for 6 years.
|
37
|
+
|
38
|
+
'
|
39
|
+
email:
|
40
|
+
- bardi_e@hotmail.com
|
41
|
+
executables: []
|
42
|
+
extensions: []
|
43
|
+
extra_rdoc_files: []
|
44
|
+
files:
|
45
|
+
- cheap_random.gemspec
|
46
|
+
- .gitignore
|
47
|
+
- LICENSE.md
|
48
|
+
- README.md
|
49
|
+
- examples/cb.rb
|
50
|
+
- examples/chi_squared.rb
|
51
|
+
- examples/cr.rb
|
52
|
+
- examples/make_seed.rb
|
53
|
+
- lib/cheap_big_file.rb
|
54
|
+
- lib/cheap_bits.rb
|
55
|
+
- lib/cheap_byte_count.rb
|
56
|
+
- lib/cheap_dependency.rb
|
57
|
+
- lib/cheap_file.rb
|
58
|
+
- lib/cheap_random.rb
|
59
|
+
- lib/cheap_random/version.rb
|
60
|
+
- lib/cheap_test.rb
|
61
|
+
- spec/cheap_big_file_spec.rb
|
62
|
+
- spec/cheap_bits_spec.rb
|
63
|
+
- spec/cheap_random_spec.rb
|
64
|
+
- spec/using_cheap_bits_cheap_random_spec.rb
|
65
|
+
homepage: https://github.com/bardibardi/cheap_random
|
66
|
+
licenses: []
|
67
|
+
post_install_message:
|
68
|
+
rdoc_options: []
|
69
|
+
require_paths:
|
70
|
+
- lib
|
71
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ! '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: 1.9.2
|
77
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
78
|
+
none: false
|
79
|
+
requirements:
|
80
|
+
- - ! '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
requirements: []
|
84
|
+
rubyforge_project:
|
85
|
+
rubygems_version: 1.8.23
|
86
|
+
signing_key:
|
87
|
+
specification_version: 3
|
88
|
+
summary: pseudo random number generation from arbitrary data
|
89
|
+
test_files: []
|