pixiedust 0.0.5 → 0.0.6
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/History.txt +3 -0
- data/lib/pixiedust.rb +74 -15
- data/test/random_dust.rb +56 -28
- metadata +2 -2
data/History.txt
CHANGED
data/lib/pixiedust.rb
CHANGED
@@ -5,7 +5,7 @@ rescue LoadError
|
|
5
5
|
end
|
6
6
|
|
7
7
|
class PixieDust
|
8
|
-
VERSION = '0.0.
|
8
|
+
VERSION = '0.0.6'
|
9
9
|
end
|
10
10
|
|
11
11
|
class Object
|
@@ -22,33 +22,92 @@ class RandomDust
|
|
22
22
|
RandomDust.between(min, max)
|
23
23
|
end
|
24
24
|
|
25
|
+
def RandomDust.bits_needed(val)
|
26
|
+
return val.to_s(2).length
|
27
|
+
end
|
28
|
+
|
29
|
+
def RandomDust.ubytes_needed(val)
|
30
|
+
bits = bits_needed(val)
|
31
|
+
bytes = bits/8
|
32
|
+
if bits%8 > 0
|
33
|
+
bytes += 1
|
34
|
+
end
|
35
|
+
return bytes
|
36
|
+
end
|
37
|
+
|
38
|
+
=begin
|
39
|
+
uint32s = bytes_allocated / 4
|
40
|
+
delta = 2**(8*val.size) - val # diff between num of uint32s and bytes needed
|
41
|
+
|
42
|
+
if delta >= 2**56 && delta < 2**64 then bytes_needed -= 7; unp="C"
|
43
|
+
elsif delta >= 2**48 && delta < 2**56 then bytes_needed -= 6; unp="S"
|
44
|
+
elsif delta >= 2**40 && delta < 2**48 then bytes_needed -= 5; unp="SC"
|
45
|
+
elsif delta >= 2**32 && delta < 2**40 then bytes_needed -= 4; unp="L"
|
46
|
+
#else unp=""
|
47
|
+
#end
|
48
|
+
#if delta >= 2**24 && delta < 2**32 then bytes_needed -= 3; unp="C"
|
49
|
+
elsif delta >= 2**24 && delta < 2**32 then bytes_needed -= 3; unp="C"
|
50
|
+
elsif delta >= 2**16 && delta < 2**24 then bytes_needed -= 2; unp="S"
|
51
|
+
elsif delta >= 2**8 && range < 2**16 then bytes_needed -= 1; unp="SC"
|
52
|
+
else unp=""
|
53
|
+
end
|
54
|
+
puts "delta is #{delta}, unp is #{unp}"
|
55
|
+
=end
|
56
|
+
|
25
57
|
def RandomDust.between(min, max)
|
58
|
+
if min == max then raise "min == max in RandomDust.between"; end
|
26
59
|
if min > max then raise "min > max in RandomDust.between"; end
|
27
60
|
|
28
61
|
value = 0
|
62
|
+
attempts = 0
|
29
63
|
range = max - min
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
delta = 2**(8*range.size) - range
|
64
|
+
byte_count = RandomDust.ubytes_needed(range)
|
65
|
+
uint32s = byte_count / 4
|
66
|
+
bytes = byte_count % 4
|
34
67
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
68
|
+
case bytes
|
69
|
+
when 3
|
70
|
+
unp = 'SC'
|
71
|
+
when 2
|
72
|
+
unp = 'S'
|
73
|
+
when 1
|
74
|
+
unp = 'C'
|
75
|
+
else
|
76
|
+
unp = ''
|
39
77
|
end
|
40
78
|
|
41
79
|
while true
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
80
|
+
attempts += 1
|
81
|
+
rand = OpenSSL::Random.random_bytes(byte_count) # XXX: grab extra to save time
|
82
|
+
|
83
|
+
# handle single byte values specially
|
84
|
+
# 255 & 0b0111_1111 # mask the highest bit
|
85
|
+
if byte_count == 1
|
86
|
+
value = rand.unpack('C').first
|
87
|
+
|
88
|
+
bits = bits_needed(range)
|
89
|
+
value = value & (2**bits - 1)
|
90
|
+
elsif byte_count == 2
|
91
|
+
value = rand.unpack('S').first
|
92
|
+
|
93
|
+
bits = bits_needed(range)
|
94
|
+
value = value & (2**bits - 1)
|
95
|
+
else
|
96
|
+
parts = rand.unpack(unp + "L"*(uint32s))
|
97
|
+
value = parts.shift
|
98
|
+
if bytes == 3
|
99
|
+
p = parts.shift
|
100
|
+
value += p << 16
|
101
|
+
end
|
102
|
+
parts.length.upto(uint32s - 1) { |x|
|
103
|
+
value += parts[x] << 32 * x
|
104
|
+
}
|
105
|
+
end
|
48
106
|
|
49
107
|
value += min
|
50
108
|
|
51
109
|
unless value < min || value > max
|
110
|
+
open('pixiedust-attempts.txt', "a+") { |f| f << "#{attempts} needed (#{min}-#{max} range\n" }
|
52
111
|
return value
|
53
112
|
end
|
54
113
|
end
|
data/test/random_dust.rb
CHANGED
@@ -3,40 +3,70 @@ require 'spec'
|
|
3
3
|
require 'statarray'
|
4
4
|
begin
|
5
5
|
require 'ruby-prof'
|
6
|
-
profile =
|
6
|
+
profile = true
|
7
7
|
rescue LoadError
|
8
8
|
end
|
9
9
|
|
10
10
|
require "#{File.dirname(__FILE__)}/../lib/pixiedust"
|
11
11
|
|
12
12
|
describe RandomDust do
|
13
|
-
it "Shouldn't generate numbers outside of range" do
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
13
|
+
#it "Shouldn't generate numbers outside of range" do
|
14
|
+
# min = -5
|
15
|
+
# max = 15
|
16
|
+
# if profile then RubyProf.start; end
|
17
|
+
# 1000.times {
|
18
|
+
# val = RandomDust.between(min,max)
|
19
|
+
# val.should <= max
|
20
|
+
# val.should >= min
|
21
|
+
# }
|
22
|
+
# if profile
|
23
|
+
# profile_data = RubyProf.stop
|
24
|
+
# printer = RubyProf::FlatPrinter.new(profile_data)
|
25
|
+
# printer.print(open("profile-#{DateDust.now_str}.txt", "w+"), 0)
|
26
|
+
# end
|
27
|
+
#end
|
28
|
+
|
29
|
+
it "Should know how many bytes are really needed by a number" do
|
30
|
+
RandomDust.ubytes_needed(1).should == 1
|
31
|
+
RandomDust.ubytes_needed(255).should == 1
|
32
|
+
RandomDust.ubytes_needed(256).should == 2
|
33
|
+
RandomDust.ubytes_needed(65535).should == 2
|
34
|
+
RandomDust.ubytes_needed(65536).should == 3
|
35
|
+
RandomDust.ubytes_needed(16777215).should == 3
|
36
|
+
RandomDust.ubytes_needed(16777216).should == 4
|
37
|
+
RandomDust.ubytes_needed(18446744073709551616).should == 9
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
it "Should generate numbers at ends of range" do
|
42
|
+
min = 0
|
43
|
+
max = [1, 4, 555]
|
44
|
+
|
45
|
+
max.each { |x|
|
46
|
+
vlist = []
|
47
|
+
2000.times {
|
48
|
+
vlist << RandomDust.between(min, x)
|
49
|
+
}
|
50
|
+
vstat = vlist.to_statarray
|
51
|
+
#puts "min: #{min}, min seen: #{vstat.min}"
|
52
|
+
#puts "max: #{x}, max seen: #{vstat.max}"
|
53
|
+
vstat.min.should == min
|
54
|
+
vstat.max.should == x
|
21
55
|
}
|
22
|
-
if profile
|
23
|
-
profile_data = RubyProf.stop
|
24
|
-
printer = RubyProf::FlatPrinter.new(profile_data)
|
25
|
-
printer.print(open("profile-#{DateDust.now_str}.txt", "w+"), 0)
|
26
|
-
end
|
27
56
|
end
|
28
57
|
|
29
58
|
it "Should generate numbers at ends of range" do
|
30
59
|
min = -5
|
31
60
|
max = 5
|
32
|
-
|
33
|
-
hit_max = false
|
61
|
+
vlist = []
|
34
62
|
100.times {
|
35
|
-
|
36
|
-
if RandomDust.between(min, max) == max; then hit_max = true; end
|
63
|
+
vlist << RandomDust.between(min, max)
|
37
64
|
}
|
38
|
-
|
39
|
-
|
65
|
+
vstat = vlist.to_statarray
|
66
|
+
#puts "min: #{vstat.min}"
|
67
|
+
#puts "max: #{vstat.max}"
|
68
|
+
vstat.min.should == min
|
69
|
+
vstat.max.should == max
|
40
70
|
end
|
41
71
|
|
42
72
|
it "Should have roughly equal counts of numbers in range" do
|
@@ -52,16 +82,14 @@ describe RandomDust do
|
|
52
82
|
}
|
53
83
|
|
54
84
|
counts = []
|
55
|
-
values.keys.each { |k|
|
85
|
+
values.keys.sort.each { |k|
|
56
86
|
counts << values[k]
|
87
|
+
#puts "#{k}: #{values[k]}"
|
57
88
|
}
|
58
89
|
|
59
|
-
|
60
|
-
#puts "
|
61
|
-
#puts "
|
62
|
-
|
63
|
-
#puts "stddev: #{ca.stddev}"
|
64
|
-
ca.stddev.should < 100
|
65
|
-
|
90
|
+
cstat = counts.to_statarray
|
91
|
+
#puts "median: #{cstat.median}"
|
92
|
+
#puts "stddev: #{cstat.stddev}"
|
93
|
+
cstat.stddev.should < 50
|
66
94
|
end
|
67
95
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pixiedust
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jonathan Wilkins
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-05-
|
12
|
+
date: 2008-05-16 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|