simple-random 1.0.2 → 1.0.3
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 +4 -4
- data/Gemfile +1 -0
- data/Gemfile.lock +5 -0
- data/VERSION +1 -1
- data/lib/simple-random.rb +2 -2
- data/lib/simple-random/simple_random.rb +126 -97
- data/test/test_simple_random.rb +1 -1
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e4aaf55a487de9bfbbaf5352472cd4d9b3888ab5
|
4
|
+
data.tar.gz: 21ba3e7c6b8337a21f8c3ad6d5e7a50f2527d792
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 55d1f2eee8febbd9b295065fbd8956bdc0bbdbd92d60ff46aa5cd2aeff8f7e0ad12dd991a84518308395feb4b194da9ebcd9851f539f51461bd3b99ccf9f8619
|
7
|
+
data.tar.gz: 3321d47d01c0b6a6692b7958c4bd4d90d3baa0b82621f318910fb14285aa3aa16df7478582a2072ca7b42636aef2e24cca08a90898484ec75c7bc7767fa786dd
|
data/Gemfile
CHANGED
@@ -6,6 +6,7 @@ source "http://rubygems.org"
|
|
6
6
|
# Add dependencies to develop your gem here.
|
7
7
|
# Include everything needed to run rake, tests, features, etc.
|
8
8
|
group :development do
|
9
|
+
gem "awesome_print", ">= 1.6"
|
9
10
|
gem "minitest", ">= 0"
|
10
11
|
gem "shoulda", ">= 0"
|
11
12
|
gem "rdoc", "~> 3.12"
|
data/Gemfile.lock
CHANGED
@@ -8,6 +8,7 @@ GEM
|
|
8
8
|
thread_safe (~> 0.1)
|
9
9
|
tzinfo (~> 1.1)
|
10
10
|
addressable (2.3.6)
|
11
|
+
awesome_print (1.6.1)
|
11
12
|
builder (3.2.2)
|
12
13
|
descendants_tracker (0.0.4)
|
13
14
|
thread_safe (~> 0.3, >= 0.3.1)
|
@@ -73,9 +74,13 @@ PLATFORMS
|
|
73
74
|
ruby
|
74
75
|
|
75
76
|
DEPENDENCIES
|
77
|
+
awesome_print (>= 1.6)
|
76
78
|
bundler (~> 1.0)
|
77
79
|
jeweler (~> 2.0.1)
|
78
80
|
minitest
|
79
81
|
rdoc (~> 3.12)
|
80
82
|
shoulda
|
81
83
|
simplecov
|
84
|
+
|
85
|
+
BUNDLED WITH
|
86
|
+
1.10.6
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.0.
|
1
|
+
1.0.3
|
data/lib/simple-random.rb
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
require 'simple-random
|
2
|
-
require 'simple-random
|
1
|
+
require File.join(File.dirname(__FILE__), 'simple-random', 'simple_random')
|
2
|
+
require File.join(File.dirname(__FILE__), 'simple-random', 'multi_threaded_simple_random')
|
@@ -1,54 +1,58 @@
|
|
1
1
|
class SimpleRandom
|
2
|
+
class InvalidSeedArgument < StandardError; end
|
3
|
+
|
4
|
+
C_32_BIT = 4294967296
|
5
|
+
F_32_BIT = 4294967296.0
|
6
|
+
|
2
7
|
def initialize
|
3
8
|
@m_w = 521288629
|
4
9
|
@m_z = 362436069
|
5
10
|
end
|
6
11
|
|
7
12
|
def set_seed(*args)
|
8
|
-
|
9
|
-
|
10
|
-
|
13
|
+
validate_seeds!(*args)
|
14
|
+
|
15
|
+
@m_w, @m_z = if args.size > 1
|
16
|
+
args[0..1].map(&:to_i)
|
11
17
|
elsif args.first.is_a?(Numeric)
|
12
|
-
@
|
13
|
-
elsif args.first.is_a?(Time)
|
14
|
-
x = (args.first.to_f * 1000000).to_i
|
15
|
-
@m_w = x >> 16
|
16
|
-
@m_z = x % 4294967296 # 2 ** 32
|
18
|
+
[@m_w, args.first.to_i]
|
17
19
|
else
|
18
|
-
|
19
|
-
@m_w = x >> 16
|
20
|
-
@m_z = x % 4294967296 # 2 ** 32
|
20
|
+
generate_temporal_seed(args.first || Time.now)
|
21
21
|
end
|
22
22
|
|
23
|
-
@m_w %=
|
24
|
-
@m_z %=
|
23
|
+
@m_w %= C_32_BIT
|
24
|
+
@m_z %= C_32_BIT
|
25
25
|
end
|
26
26
|
|
27
27
|
# Produce a uniform random sample from the open interval (lower, upper).
|
28
|
-
# The method will not return either end point.
|
29
28
|
def uniform(lower = 0, upper = 1)
|
30
|
-
|
31
|
-
|
29
|
+
fail ArgumentError, 'Upper bound must be greater than lower bound.' unless lower < upper
|
30
|
+
|
31
|
+
((get_unsigned_int + 1) * (upper - lower) / F_32_BIT) + lower
|
32
32
|
end
|
33
33
|
|
34
34
|
# Sample normal distribution with given mean and standard deviation
|
35
35
|
def normal(mean = 0.0, standard_deviation = 1.0)
|
36
|
-
|
36
|
+
fail ArgumentError, 'Standard deviation must be strictly positive' unless standard_deviation > 0
|
37
|
+
|
37
38
|
mean + standard_deviation * ((-2.0 * Math.log(uniform)) ** 0.5) * Math.sin(2.0 * Math::PI * uniform)
|
38
39
|
end
|
39
40
|
|
40
41
|
# Get exponential random sample with specified mean
|
41
42
|
def exponential(mean = 1)
|
42
|
-
|
43
|
+
fail ArgumentError, "Mean must be strictly positive" unless mean > 0
|
44
|
+
|
43
45
|
-1.0 * mean * Math.log(uniform)
|
44
46
|
end
|
45
47
|
|
46
48
|
# Get triangular random sample with specified lower limit, mode, upper limit
|
47
49
|
def triangular(lower, mode, upper)
|
48
|
-
|
49
|
-
|
50
|
+
fail ArgumentError, 'Upper bound must be greater than lower bound.' unless lower < upper
|
51
|
+
fail ArgumentError, 'Mode must lie between the upper and lower limits' if mode > upper || mode < lower
|
52
|
+
|
50
53
|
f_c = (mode - lower) / (upper - lower)
|
51
54
|
uniform_rand_num = uniform
|
55
|
+
|
52
56
|
if uniform_rand_num < f_c
|
53
57
|
lower + Math.sqrt(uniform_rand_num * (upper - lower) * (mode - lower))
|
54
58
|
else
|
@@ -60,28 +64,31 @@ class SimpleRandom
|
|
60
64
|
# by George Marsaglia and Wai Wan Tsang. ACM Transactions on Mathematical Software
|
61
65
|
# Vol 26, No 3, September 2000, pages 363-372.
|
62
66
|
def gamma(shape, scale)
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
v = 0.0
|
68
|
-
while v <= 0.0
|
69
|
-
x = normal
|
70
|
-
v = 1.0 + c * x
|
71
|
-
end
|
72
|
-
v = v ** 3
|
73
|
-
u = uniform
|
74
|
-
if u < (1.0 - 0.0331 * (x ** 4)) || Math.log(u) < (0.5 * (x ** 2) + d * (1.0 - v + Math.log(v)))
|
75
|
-
return scale * d * v
|
76
|
-
end
|
77
|
-
end
|
78
|
-
elsif shape <= 0.0
|
79
|
-
raise 'Shape must be positive'
|
67
|
+
fail ArgumentError, 'Shape must be strictly positive' unless shape > 0
|
68
|
+
|
69
|
+
base = if shape < 1
|
70
|
+
gamma(shape + 1.0, 1.0) * uniform ** -shape
|
80
71
|
else
|
81
|
-
|
82
|
-
|
83
|
-
|
72
|
+
d = shape - 1 / 3.0
|
73
|
+
c = (9 * d) ** -0.5
|
74
|
+
|
75
|
+
begin
|
76
|
+
z = normal
|
77
|
+
|
78
|
+
condition1 = z > (-1.0 / c)
|
79
|
+
condition2 = false
|
80
|
+
|
81
|
+
if condition1
|
82
|
+
u = uniform
|
83
|
+
v = (1 + c * z) ** 3
|
84
|
+
condition2 = Math.log(u) < (0.5 * (z ** 2) + d * (1.0 - v + Math.log(v)))
|
85
|
+
end
|
86
|
+
end while !condition2
|
87
|
+
|
88
|
+
d * v
|
84
89
|
end
|
90
|
+
|
91
|
+
scale * base
|
85
92
|
end
|
86
93
|
|
87
94
|
def chi_square(degrees_of_freedom)
|
@@ -93,34 +100,36 @@ class SimpleRandom
|
|
93
100
|
end
|
94
101
|
|
95
102
|
def beta(a, b)
|
96
|
-
|
103
|
+
fail ArgumentError, "Parameters must be strictly positive" unless a > 0 && b > 0
|
97
104
|
u = gamma(a, 1)
|
98
105
|
v = gamma(b, 1)
|
99
106
|
u / (u + v)
|
100
107
|
end
|
101
108
|
|
102
109
|
def weibull(shape, scale)
|
103
|
-
|
110
|
+
fail ArgumentError, 'Shape and scale must be positive' unless shape > 0 && scale > 0
|
104
111
|
|
105
112
|
scale * ((-Math.log(uniform)) ** (1.0 / shape))
|
106
113
|
end
|
107
114
|
|
108
115
|
def cauchy(median, scale)
|
109
|
-
|
116
|
+
fail ArgumentError, 'Scale must be positive' unless scale > 0
|
110
117
|
|
111
118
|
median + scale * Math.tan(Math::PI * (uniform - 0.5))
|
112
119
|
end
|
113
120
|
|
114
121
|
def student_t(degrees_of_freedom)
|
115
|
-
|
122
|
+
fail ArgumentError, 'Degrees of freedom must be strictly positive' unless degrees_of_freedom > 0
|
116
123
|
|
117
124
|
normal / ((chi_square(degrees_of_freedom) / degrees_of_freedom) ** 0.5)
|
118
125
|
end
|
119
126
|
|
120
127
|
def laplace(mean, scale)
|
121
|
-
u_1 = uniform
|
128
|
+
u_1 = uniform(-0.5, 0.5)
|
122
129
|
u_2 = uniform
|
123
|
-
|
130
|
+
|
131
|
+
sign = u_1 / u_1.abs
|
132
|
+
mean + sign * scale * Math.log(1 - u_2)
|
124
133
|
end
|
125
134
|
|
126
135
|
def log_normal(mu, sigma)
|
@@ -144,65 +153,85 @@ class SimpleRandom
|
|
144
153
|
((@m_z << 16) + (@m_w & 65535)) % 4294967296
|
145
154
|
end
|
146
155
|
|
147
|
-
def
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
-0.2056338417e-6,
|
164
|
-
0.6116095e-8,
|
165
|
-
0.50020075e-8,
|
166
|
-
-0.11812746e-8,
|
167
|
-
0.1043427e-9,
|
168
|
-
0.77823e-11,
|
169
|
-
-0.36968e-11,
|
170
|
-
0.51e-12,
|
171
|
-
-0.206e-13,
|
172
|
-
-0.54e-14,
|
173
|
-
0.14e-14
|
174
|
-
]
|
175
|
-
|
176
|
-
r = 1.0
|
156
|
+
def validate_seeds!(*args)
|
157
|
+
return true if args.compact.empty?
|
158
|
+
|
159
|
+
unless args[0].to_f.abs > 0
|
160
|
+
fail InvalidSeedArgument, 'Seeds must be strictly positive'
|
161
|
+
end
|
162
|
+
|
163
|
+
unless args[1].nil? || args[1].to_f.abs > 0
|
164
|
+
fail InvalidSeedArgument, 'Seeds must be strictly positive'
|
165
|
+
end
|
166
|
+
|
167
|
+
true
|
168
|
+
end
|
169
|
+
|
170
|
+
def generate_temporal_seed(timestamp = Time.now)
|
171
|
+
x = (timestamp.to_f * 1000000).to_i
|
177
172
|
|
173
|
+
[x >> 16, x % 4294967296]
|
174
|
+
end
|
175
|
+
|
176
|
+
def gamma_function(x)
|
178
177
|
return 1e308 if x > 171.0
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
178
|
+
|
179
|
+
if x.to_f == x.to_i
|
180
|
+
return unless x > 0
|
181
|
+
return 1 if x.to_i == 1
|
182
|
+
|
183
|
+
(1...x).inject(&:*)
|
185
184
|
else
|
186
|
-
if x.abs > 1.0
|
187
|
-
|
188
|
-
z = x.abs - x.abs.to_i
|
185
|
+
z = if x.abs > 1.0
|
186
|
+
x.abs - x.abs.to_i
|
189
187
|
else
|
190
|
-
|
188
|
+
x
|
191
189
|
end
|
192
190
|
|
193
|
-
gr = g
|
194
|
-
|
195
|
-
gr = gr * z + g[i]
|
191
|
+
gr = GAMMA_VALUES.inject(GAMMA_NAUGHT) do |sum, g|
|
192
|
+
sum * z + g
|
196
193
|
end
|
197
|
-
|
198
|
-
if x.abs > 1
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
end
|
194
|
+
|
195
|
+
r = if x.abs > 1
|
196
|
+
(1..(x.abs.to_i)).inject(1.0) { |prod, i| prod * (x.abs - i) }
|
197
|
+
else
|
198
|
+
1.0
|
203
199
|
end
|
204
|
-
end
|
205
200
|
|
206
|
-
|
201
|
+
if x < 0 && x.abs > 1
|
202
|
+
-Math::PI * gr * z / (x * r * Math.sin(Math::PI * x))
|
203
|
+
else
|
204
|
+
r / (gr * z)
|
205
|
+
end
|
206
|
+
end
|
207
207
|
end
|
208
|
+
|
209
|
+
GAMMA_NAUGHT = 0.14e-14
|
210
|
+
|
211
|
+
GAMMA_VALUES = [
|
212
|
+
-5.4e-15,
|
213
|
+
-2.06e-14,
|
214
|
+
5.1e-13,
|
215
|
+
-3.6968e-12,
|
216
|
+
7.7823e-12,
|
217
|
+
1.043427e-10,
|
218
|
+
-1.1812746e-09,
|
219
|
+
5.0020075e-09,
|
220
|
+
6.116095e-09,
|
221
|
+
-2.056338417e-07,
|
222
|
+
1.133027232e-06,
|
223
|
+
-1.2504934821e-06,
|
224
|
+
-2.01348547807e-05,
|
225
|
+
0.0001280502823882,
|
226
|
+
-0.0002152416741149,
|
227
|
+
-0.0011651675918591,
|
228
|
+
0.007218943246663,
|
229
|
+
-0.009621971527877,
|
230
|
+
-0.0421977345555443,
|
231
|
+
0.1665386113822915,
|
232
|
+
-0.0420026350340952,
|
233
|
+
-0.6558780715202538,
|
234
|
+
0.5772156649015329,
|
235
|
+
1.0
|
236
|
+
]
|
208
237
|
end
|
data/test/test_simple_random.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: simple-random
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- John D. Cook
|
@@ -9,8 +9,22 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2015-11-
|
12
|
+
date: 2015-11-25 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: awesome_print
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - ">="
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '1.6'
|
21
|
+
type: :development
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: '1.6'
|
14
28
|
- !ruby/object:Gem::Dependency
|
15
29
|
name: minitest
|
16
30
|
requirement: !ruby/object:Gem::Requirement
|