pixiedust 0.0.5 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- 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
|