2
* This program is free software; you can redistribute it and/or modify
3
* it under the terms of the GNU General Public License as published by
4
* the Free Software Foundation; either version 2 of the License, or
5
* (at your option) any later version.
7
* This program is distributed in the hope that it will be useful,
8
* but WITHOUT ANY WARRANTY; without even the implied warranty of
9
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
* GNU General Public License for more details.
12
* You should have received a copy of the GNU General Public License
13
* along with this program; if not, write to the Free Software
14
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
* Copyright (C) 2002 University of Waikato, Hamilton, New Zealand
25
import java.util.Random;
28
* Class implementing some simple random variates generator.
30
* @author Xin Xu (xx5@cs.waikato.ac.nz)
31
* @version $Revision: 1.4 $
33
public final class RandomVariates
36
/** for serialization */
37
private static final long serialVersionUID = -4763742718209460354L;
40
* Simply the constructor of super class
42
public RandomVariates(){ super(); }
45
* Simply the constructor of super class
47
* @param seed the seed in this random object
49
public RandomVariates(long seed){ super(seed); }
52
* Simply use the method of the super class
54
* @param bits - random bits
55
* @return the next pseudorandom value from this random number
56
* generator's sequence.
58
protected int next(int bits) {return super.next(bits);}
61
* Generate a value of a variate following standard exponential
62
* distribution using simple inverse method.<p>
64
* Variates related to standard Exponential can be generated using simple
66
* @return a value of the variate
68
public double nextExponential(){
69
return -Math.log(1.0-super.nextDouble());
73
* Generate a value of a variate following standard Erlang distribution.
74
* It can be used when the shape parameter is an integer and not too large,
75
* say, <100. When the parameter is not an integer (which is often named
76
* Gamma distribution) or is large, use <code>nextGamma(double a)</code>
79
* @param a the shape parameter, must be no less than 1
80
* @return a value of the variate
81
* @exception Exception if parameter less than 1
83
public double nextErlang(int a) throws Exception{
85
throw new Exception("Shape parameter of Erlang distribution must be greater than 1!");
88
for(int i=1; i<=a; i++)
89
product *= super.nextDouble();
91
return -Math.log(product);
95
* Generate a value of a variate following standard Gamma distribution
96
* with shape parameter a.<p>
97
* If a>1, it uses a rejection method developed by Minh(1988)"Generating
98
* Gamma Variates", ACM Trans. on Math. Software, Vol.14, No.3, pp261-266.
100
* If a<1, it uses the algorithm "GS" developed by Ahrens and Dieter(1974)
101
* "COMPUTER METHODS FOR SAMPLING FROM GAMMA, BETA, POISSON AND BINOMIAL
102
* DISTRIBUTIONS", COMPUTING, 12 (1974), pp223-246, and further implemented
103
* in Fortran by Ahrens, Kohrt and Dieter(1983) "Algorithm 599: sampling
104
* from Gamma and Poisson distributions", ACM Trans. on Math. Software,
105
* Vol.9 No.2, pp255-257.<p>
107
* Variates related to standard Gamma can be generated using simple
110
* @param a the shape parameter, must be greater than 1
111
* @return a value of the variate
112
* @exception Exception if parameter not greater than 1
114
public double nextGamma(double a) throws Exception{
116
throw new Exception("Shape parameter of Gamma distribution"+
117
"must be greater than 0!");
119
return nextExponential();
121
double b=1.0+Math.exp(-1.0)*a, p,x, condition;
123
p=b*super.nextDouble();
125
x = Math.exp(Math.log(p)/a);
129
x = -Math.log((b-p)/a);
130
condition = (1.0-a)*Math.log(x);
133
while(nextExponential() < condition);
137
double b=a-1.0, D=Math.sqrt(b), D1,x1,x2,xl,f1,f2,x4,x5,xr,f4,f5,
153
f1 = Math.exp(b*Math.log(x1/b)+2.0*D1);
156
f2=Math.exp(b*Math.log(x2/b)+D1);
160
f4 = Math.exp(b*Math.log(x4/b)-D);
161
f5 = Math.exp(b*Math.log(x5/b)-2.0*D);
168
double u, w=Double.MAX_VALUE, x=b, v, xp;
169
while(Math.log(w) > (b*Math.log(x/b)+b-x)){
170
u=super.nextDouble()*p4;
171
if(u<=p1){ // step 5-6
173
if(w<=0.0) return (b+u/f4);
174
if(w<=f5) return (x4+(w*D)/f5);
176
v = super.nextDouble();
180
if(w >= f4+(f4-1)*(x-x4)/(x4-b))
182
if(w <= f4+(b/x4-1)*f4*(x-x4))
184
if((w < 2.0*f4-1.0) ||
185
(w < 2.0*f4-Math.exp(b*Math.log(xp/b)+b-xp)))
189
else if(u<=p2){ // step 7-8
191
if(w<=0.0) return (b-(u-p1)/f2);
192
if(w<=f1) return (x1+w*D1/f1);
194
v = super.nextDouble();
198
if(w >= f2+(f2-1)*(x-x2)/(x2-b))
200
if(w <= f2*(x-x1)/D1)
202
if((w < 2.0*f2-1.0) ||
203
(w < 2.0*f2-Math.exp(b*Math.log(xp/b)+b-xp)))
207
else if(u<p3){ // step 9
208
w = super.nextDouble();
210
x = x5-Math.log(u)/xr;
211
if(w <= (xr*(x5-x)+1.0)/u) return x;
215
w = super.nextDouble();
217
x = x1-Math.log(u)/xl;
219
if(w <= (xl*(x1-x)+1.0)/u) return x;
230
* Main method for testing this class.
232
* @param ops # of variates/seed, default is 10/45
234
public static void main(String[] ops) {
236
int n = Integer.parseInt(ops[0]);
239
long seed = Long.parseLong(ops[1]);
242
RandomVariates var = new RandomVariates(seed);
243
double varb[] = new double[n];
246
System.out.println("Generate "+n+" values with std. exp dist:");
247
for(int i=0; i<n; i++){
248
varb[i] = var.nextExponential();
249
System.out.print("["+i+"] "+varb[i]+", ");
252
System.out.println("\nMean is "+Utils.mean(varb)+
253
", Variance is "+Utils.variance(varb)+
254
"\n\nGenerate "+n+" values with"+
255
" std. Erlang-5 dist:");
257
for(int i=0; i<n; i++){
258
varb[i] = var.nextErlang(5);
259
System.out.print("["+i+"] "+varb[i]+", ");
262
System.out.println("\nMean is "+Utils.mean(varb)+
263
", Variance is "+Utils.variance(varb)+
264
"\n\nGenerate "+n+" values with"+
265
" std. Gamma(4.5) dist:");
267
for(int i=0; i<n; i++){
268
varb[i] = var.nextGamma(4.5);
269
System.out.print("["+i+"] "+varb[i]+", ");
272
System.out.println("\nMean is "+Utils.mean(varb)+
273
", Variance is "+Utils.variance(varb)+
274
"\n\nGenerate "+n+" values with"+
275
" std. Gamma(0.5) dist:");
277
for(int i=0; i<n; i++){
278
varb[i] = var.nextGamma(0.5);
279
System.out.print("["+i+"] "+varb[i]+", ");
282
System.out.println("\nMean is "+Utils.mean(varb)+
283
", Variance is "+Utils.variance(varb)+
284
"\n\nGenerate "+n+" values with"+
285
" std. Gaussian(5, 2) dist:");
287
for(int i=0; i<n; i++){
288
varb[i] = var.nextGaussian()*2.0+5.0;
289
System.out.print("["+i+"] "+varb[i]+", ");
291
System.out.println("\nMean is "+Utils.mean(varb)+
292
", Variance is "+Utils.variance(varb)+"\n");
294
} catch (Exception e) {