/* *
* Title:
* Description:
* Copyright: Copyright (c)
* Company:
* @author
* @version 1.0
*/
package umontreal.iro.lecuyer.rng;
import java.io.Serializable;
/**
* This class provides a convenient foundation on which RNGs can
* be built. It implements all the methods which do not depend directly on
* the generator itself, but only on its output, which is to be defined
* by implementing the abstract method nextValue. In the present
* class, all methods returning random numbers directly or indirectly
* (nextDouble, nextArrayOfDouble, nextInt and
* nextArrayOfInt) call nextValue. Thus, to define a subclass
* that implements a RNG, it suffices to implement nextValue, in addition
* to the reset... and toString methods.
* Of course, the other methods may also be overridden for improved efficiency.
*
*
* If the nextValue already generates numbers with a precision of
* 53-bits or higher, then {@link #nextDouble nextDouble} can be overridden to improve
* the performance. The mechanism for increasing the precision assumes that
* nextValue returns at least 29 bits of precision, in which case
* the higher precision numbers will have roughly 52 bits of precision.
* This mechanism was designed primarily for RNGs that return numbers with
* around 30 to 32 bits of precision.
*
*
* {@link RandomStreamBase} and its subclasses are implementing the {@link Serializable} interface.
* Each class has a serial number wich represent the class version.
* For instance 70510 means that the last change was the 10th May 2007.
*
*/
public abstract class RandomStreamBase implements CloneableRandomStream,
Serializable {
private static final long serialVersionUID = 70510L;
//La date de modification a l'envers, lire 10/05/2007
//constants
protected static double invtwo24 = 5.9604644775390625e-8; //2^(-24)
private static double EPSILON = 5.5511151231257827e-17; //2^(-54)
protected String name = null;
// prec53 keeps track if the precision has been increased or not.
protected boolean prec53 = false;
protected boolean anti = false; // Deprecated.
public abstract void resetStartStream();
public abstract void resetStartSubstream();
public abstract void resetNextSubstream();
public abstract String toString();
/**
* After calling this method with incp = true, each call to
* the RNG (direct or indirect) for this stream
* will return a uniform random number with more bits of precision than what
* is returned by nextValue,
* and will advance the state of the stream by 2 steps instead of 1
* (i.e., nextValue will be called twice for each random number).
*
*
* More precisely, if s is a stream of a subclass of
* RandomStreamBase, when the precision has been increased,
* the instruction ``u = s.nextDouble()'', is equivalent to
* ``u = (s.nextValue() + s.nextValue()*fact) % 1.0''
* where the constant fact is equal to 2-24.
* This also applies when calling nextDouble indirectly
* (e.g., via nextInt, etc.).
* By default, or if this method is called again with incp = false,
* each call to nextDouble for this stream advances the state by 1 step
* and returns the same number as nextValue.
*
* @param incp if the generator will be set to high precision mode
*
*
*/
public void increasedPrecision (boolean incp) {
prec53 = incp;
}
/**
* This method should return the next random number (between 0 and 1)
* from the current stream.
* If the stream is set to the high precision mode
* (increasedPrecision(true) was called), then each call to
* nextDouble will call nextValue twice, otherwise it will
* call it only once.
*
* @return a number in the interval (0,1)
*
*/
protected abstract double nextValue();
/**
* Returns a uniform random number between 0 and 1 from the stream.
* Its behavior depends on the last call to {@link #increasedPrecision increasedPrecision}.
* The generators programmed in SSJ never return the values 0 or 1.
*
* @return a number in the interval (0,1)
*
*/
public double nextDouble() {
double u = nextValue();
if (prec53)
u = (u + nextValue() * invtwo24) % 1.0 + EPSILON;
if(anti)
return 1.0 - u;
else
return u;
}
/**
* Calls nextDouble n times to fill the array u.
*
* @param u the array in which the numbers will be stored
*
* @param start the first index of u to be used
*
* @param n the number of random numbers to put in u
*
*
*/
public void nextArrayOfDouble (double[] u, int start, int n) {
if(u.length == 0)
throw new NullPointerException("The array must be initialized.");
if (u.length < n + start)
throw new IndexOutOfBoundsException("The array is too small.");
if(start < 0)
throw new IndexOutOfBoundsException("Must start at a " +
"non-negative index.");
if(n < 0)
throw new IllegalArgumentException("Must have a non-negative " +
"number of elements.");
for(int ii = start; ii < start + n; ii++)
u[ii] = nextDouble();
}
/**
* Calls nextDouble once to create one integer between
* i and j. This method always uses the highest order bits
* of the random number. It should be overridden if a faster implementation
* exists for the specific generator.
*
* @param i the smallest possible returned integer
*
* @param j the largest possible returned integer
*
* @return a random integer between i and j
*
*/
public int nextInt (int i, int j) {
if(i > j)
throw new IllegalArgumentException(i + " is larger than " +
j + ".");
// This works even for an interval [0, 2^31 - 1]. It would not with
// return i + (int)(nextDouble() * (j - i + 1));
return i + (int)(nextDouble() * (j - i + 1.0));
}
/**
* Calls nextInt n times to fill the array u.
* This method should be overridden if a faster implementation exists for
* the specific generator.
*
* @param i the smallest possible integer to put in u
*
* @param j the largest possible integer to put in u
*
* @param u the array in which the numbers will be stored
*
* @param start the first index of u to be used
*
* @param n the number of random numbers to put in u
*
*
*/
public void nextArrayOfInt (int i, int j, int[] u, int start, int n) {
if(u == null)
throw new NullPointerException("The array must be " +
"initialized.");
if (u.length < n + start)
throw new IndexOutOfBoundsException("The array is too small.");
if(start < 0)
throw new IndexOutOfBoundsException("Must start at a " +
"non-negative index.");
if(n < 0)
throw new IllegalArgumentException("Must have a non-negative " +
"number of elements.");
for(int ii = start; ii < start + n; ii++)
u[ii] = nextInt(i,j);
}
/**
* Use the toString method.
*
*
*/
@Deprecated
public String formatState() {
return toString();
}
@Deprecated
public String formatStateFull() {
throw new UnsupportedOperationException (
" call the toStringFull() method instead.");
}
/**
* Clones the current generator and return its copy.
*
* @return A deep copy of the current generator
*
*/
public RandomStreamBase clone() {
RandomStreamBase retour = null;
try {
retour = (RandomStreamBase)super.clone();
}
catch(CloneNotSupportedException cnse) {
cnse.printStackTrace(System.err);
}
return retour;
}
}
Ads help maintain this website.