210 lines
5.9 KiB
Java
210 lines
5.9 KiB
Java
package net.berack.upo.valpre.rand;
|
|
|
|
/* --------------------------------------------------------------------------
|
|
* This is a Java library for generating random variates from six discrete
|
|
* distributions
|
|
*
|
|
* Generator Range (x) Mean Variance
|
|
*
|
|
* bernoulli(p) x = 0,1 p p*(1-p)
|
|
* binomial(n, p) x = 0,...,n n*p n*p*(1-p)
|
|
* equilikely(a, b) x = a,...,b (a+b)/2 ((b-a+1)*(b-a+1)-1)/12
|
|
* Geometric(p) x = 0,... p/(1-p) p/((1-p)*(1-p))
|
|
* pascal(n, p) x = 0,... n*p/(1-p) n*p/((1-p)*(1-p))
|
|
* poisson(m) x = 0,... m m
|
|
*
|
|
* and seven continuous distributions
|
|
*
|
|
* uniform(a, b) a < x < b (a + b)/2 (b - a)*(b - a)/12
|
|
* exponential(m) x > 0 m m*m
|
|
* erlang(n, b) x > 0 n*b n*b*b
|
|
* normal(m, s) all x m s*s
|
|
* logNormal(a, b) x > 0 see below
|
|
* chiSquare(n) x > 0 n 2*n
|
|
* student(n) all x 0 (n > 1) n/(n - 2) (n > 2)
|
|
*
|
|
* For the a Lognormal(a, b) random variable, the mean and variance are
|
|
*
|
|
* mean = exp(a + 0.5*b*b)
|
|
* variance = (exp(b*b) - 1) * exp(2*a + b*b)
|
|
*
|
|
* Name : Rvgs.java (Random Variate GeneratorS)
|
|
* Authors : Steve Park & Dave Geyer
|
|
* Translated by : Richard Dutton & Jun Wang
|
|
* Language : Java
|
|
* Latest Revision : 7-1-04
|
|
* --------------------------------------------------------------------------
|
|
*/
|
|
public class Rvgs {
|
|
|
|
private final Rng rng;
|
|
|
|
// public Rvgs() {
|
|
// this.rngs = new Rngs(Rng.DEFAULT);
|
|
// }
|
|
|
|
public Rvgs(Rng rng) {
|
|
if (rng == null)
|
|
throw new NullPointerException();
|
|
this.rng = rng;
|
|
}
|
|
|
|
/**
|
|
* Returns 1 with probability p or 0 with probability 1 - p.
|
|
* NOTE: use 0.0 < p < 1.0
|
|
*/
|
|
public long bernoulli(double p) {
|
|
return ((this.rng.random() < (1.0 - p)) ? 0 : 1);
|
|
}
|
|
|
|
/**
|
|
* Returns a binomial distributed integer between 0 and n inclusive.
|
|
* NOTE: use n > 0 and 0.0 < p < 1.0
|
|
*/
|
|
public long binomial(long n, double p) {
|
|
long i, x = 0;
|
|
|
|
for (i = 0; i < n; i++)
|
|
x += bernoulli(p);
|
|
return (x);
|
|
}
|
|
|
|
/**
|
|
* Returns an equilikely distributed integer between a and b inclusive.
|
|
* NOTE: use a < b
|
|
*/
|
|
public long equilikely(long a, long b) {
|
|
return (a + (long) ((b - a + 1) * this.rng.random()));
|
|
}
|
|
|
|
/**
|
|
* Returns a geometric distributed non-negative integer.
|
|
* NOTE: use 0.0 < p < 1.0
|
|
*/
|
|
public long geometric(double p) {
|
|
return ((long) (Math.log(1.0 - this.rng.random()) / Math.log(p)));
|
|
}
|
|
|
|
/**
|
|
* Returns a Pascal distributed non-negative integer.
|
|
* NOTE: use n > 0 and 0.0 < p < 1.0
|
|
*/
|
|
public long pascal(long n, double p) {
|
|
long i, x = 0;
|
|
|
|
for (i = 0; i < n; i++)
|
|
x += geometric(p);
|
|
return (x);
|
|
}
|
|
|
|
/**
|
|
* Returns a Poisson distributed non-negative integer.
|
|
* NOTE: use m > 0
|
|
*/
|
|
public long poisson(double m) {
|
|
double t = 0.0;
|
|
long x = 0;
|
|
|
|
while (t < m) {
|
|
t += exponential(1.0);
|
|
x++;
|
|
}
|
|
return (x - 1);
|
|
}
|
|
|
|
/**
|
|
* Returns a uniformly distributed real number between a and b.
|
|
* NOTE: use a < b
|
|
*/
|
|
public double uniform(double a, double b) {
|
|
return (a + (b - a) * this.rng.random());
|
|
}
|
|
|
|
/**
|
|
* Returns an exponentially distributed positive real number.
|
|
* NOTE: use m > 0.0
|
|
*/
|
|
public double exponential(double m) {
|
|
return (-m * Math.log(1.0 - this.rng.random()));
|
|
}
|
|
|
|
/**
|
|
* Returns an Erlang distributed positive real number.
|
|
* NOTE: use n > 0 and b > 0.0
|
|
*/
|
|
public double erlang(long n, double b) {
|
|
long i;
|
|
double x = 0.0;
|
|
|
|
for (i = 0; i < n; i++)
|
|
x += exponential(b);
|
|
return (x);
|
|
}
|
|
|
|
/**
|
|
* Returns a normal (Gaussian) distributed real number.
|
|
* NOTE: use s > 0.0
|
|
*
|
|
* Uses a very accurate approximation of the normal idf due to Odeh & Evans,
|
|
* J. Applied Statistics, 1974, vol 23, pp 96-97.
|
|
*/
|
|
public double normal(double m, double s) {
|
|
final double p0 = 0.322232431088;
|
|
final double q0 = 0.099348462606;
|
|
final double p1 = 1.0;
|
|
final double q1 = 0.588581570495;
|
|
final double p2 = 0.342242088547;
|
|
final double q2 = 0.531103462366;
|
|
final double p3 = 0.204231210245e-1;
|
|
final double q3 = 0.103537752850;
|
|
final double p4 = 0.453642210148e-4;
|
|
final double q4 = 0.385607006340e-2;
|
|
double u, t, p, q, z;
|
|
|
|
u = this.rng.random();
|
|
if (u < 0.5)
|
|
t = Math.sqrt(-2.0 * Math.log(u));
|
|
else
|
|
t = Math.sqrt(-2.0 * Math.log(1.0 - u));
|
|
p = p0 + t * (p1 + t * (p2 + t * (p3 + t * p4)));
|
|
q = q0 + t * (q1 + t * (q2 + t * (q3 + t * q4)));
|
|
if (u < 0.5)
|
|
z = (p / q) - t;
|
|
else
|
|
z = t - (p / q);
|
|
return (m + s * z);
|
|
}
|
|
|
|
/**
|
|
* Returns a lognormal distributed positive real number.
|
|
* NOTE: use b > 0.0
|
|
*/
|
|
public double logNormal(double a, double b) {
|
|
return (Math.exp(a + b * normal(0.0, 1.0)));
|
|
}
|
|
|
|
/**
|
|
* Returns a chi-square distributed positive real number.
|
|
* NOTE: use n > 0
|
|
*/
|
|
public double chiSquare(long n) {
|
|
long i;
|
|
double z, x = 0.0;
|
|
|
|
for (i = 0; i < n; i++) {
|
|
z = normal(0.0, 1.0);
|
|
x += z * z;
|
|
}
|
|
return (x);
|
|
}
|
|
|
|
/**
|
|
* Returns a student-t distributed real number.
|
|
* NOTE: use n > 0
|
|
*/
|
|
public double student(long n) {
|
|
return (normal(0.0, 1.0) / Math.sqrt(chiSquare(n) / n));
|
|
}
|
|
|
|
}
|