Submitted by:	Phil Steitz


git-svn-id: https://svn.apache.org/repos/asf/jakarta/commons/proper/math/trunk@140885 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Mark R. Diggory 2003-06-04 02:45:49 +00:00
parent fe27566380
commit ba74c2510f
3 changed files with 288 additions and 214 deletions

View File

@ -58,196 +58,260 @@ import java.util.Collection;
/**
* Random data generation utilities
* @author Phil Steitz
* @version $Revision: 1.2 $ $Date: 2003/05/29 19:45:35 $
* @version $Revision: 1.3 $ $Date: 2003/06/04 02:45:49 $
*/
public interface RandomData {
/**
* Generates a random string of hex characters of length
* <code>len</code>.<br>
* <code>len</code>.
* <p>
* The generated string will be random, but not cryptographically
* secure. To generate cryptographically secure strings, use
* <code>nextSecureHexString</code>
* <p>
* <strong>Preconditions</strong>:<ul>
* <li><code>len > 0</code> (otherwise an IllegalArgumentException
* is thrown.)</li>
* </ul>
*
* @param len the length of the string to be generated
* @throws IllegalArgumentException if <code>len</code> is not positive.
* @return random string of hex characters of length <code>len</code>
*/
public String nextHexString(int len);
String nextHexString(int len);
/**
* Generates a uniformly distributed random integer between
* <code>lower</code> and <code>upper</code> (endpoints included).<br>
* <code>lower</code> and <code>upper</code> (endpoints included).
* <p>
* The generated integer will be random, but not cryptographically secure.
* To generate cryptographically secure integer sequences, use
* <code>nextSecureInt</code>.
* <p>
* <strong>Preconditions</strong>:<ul>
* <li><code>lower < upper</code> (otherwise an IllegalArgumentException
* is thrown.)</li>
* </ul>
*
* @param lower lower bound for generated integer
* @param upper upper bound for generated integer
* @exception IllegalArgumentException thrown if
* <code>lower</code> is not strictly less than <code>upper</code>.
* @return a random integer greater than or equal to <code>lower</code>
* and less than or equal to <code>upper</code>.
*/
public int nextInt(int lower, int upper);
int nextInt(int lower, int upper);
/**
* Generates a uniformly distributed random long integer between <
* code>lower</code> and <code>upper</code> (endpoints included).
* Generates a uniformly distributed random long integer between
* <code>lower</code> and <code>upper</code> (endpoints included).
* <p>
* The generated long integer values will be random, but not
* cryptographically secure.<br>
* cryptographically secure.
* To generate cryptographically secure sequences of longs, use
* <code>nextSecureLong</code>
* <p>
* <strong>Preconditions</strong>:<ul>
* <li><code>lower < upper</code> (otherwise an IllegalArgumentException
* is thrown.)</li>
* </ul>
*
* @param lower lower bound for generated integer
* @param upper upper bound for generated integer
* @exception IllegalArgumentException Thrown if lower > upper
* @return a random integer greater than or equal to <code>lower</code>
* and less than or equal to <code>upper</code>.
*/
public long nextLong(long lower, long upper);
long nextLong(long lower, long upper);
/**
* Generates a random string of hex characters from a secure random sequence.
* Generates a random string of hex characters from a secure random
* sequence.
* <p>
* If cryptographic security is not required,
* use <code>nextHexString()</code>.
* <p>
* <strong>Preconditions</strong>:<ul>
* <li><code>len > 0</code> (otherwise an IllegalArgumentException
* is thrown.)</li>
* </ul>
* @param len length of return string
* @exception IllegalArgumentException thrown if len <= 0
* @return the random hex string
*/
public String nextSecureHexString(int len);
String nextSecureHexString(int len);
/**
* Generates a uniformly distributed random integer between
* <code>lower</code> and <code>upper</code> (endpoints included)
* from a secure random sequence.<br>
* The generated sequence will be cryptographically secure.<br>
* If cryptographic security is not required, <code>nextInt</code>
* should be used.<br>
* <strong>Definition</strong>(secure random sequence):
* http://www.wikipedia.org/wiki/Cryptographically_secure_pseudo-random_number_generator<br>
* from a secure random sequence.
* <p>
* Sequences of integers generated using this method will be
* cryptographically secure. If cryptographic security is not required,
* <code>nextInt</code> should be used instead of this method.
* <p>
* <strong>Definition</strong>:
* <a href="http://www.wikipedia.org/wiki/
* Cryptographically_secure_pseudo-random_number_generator">
* Secure Random Sequence</a>
* <p>
* <strong>Preconditions</strong>:<ul>
* <li><code>lower < upper</code> (otherwise an IllegalArgumentException
* is thrown.)</li>
* </ul>
*
* @param lower lower bound for generated integer
* @param upper upper bound for generated integer
* @exception IllegalArgumentException thrown if
* <code>lower</code> is not strictly less than <code>upper</code>.
* @return a random integer greater than or equal to <code>lower</code>
* and less than or equal to <code>upper</code>.
*/
public int nextSecureInt(int lower, int upper);
int nextSecureInt(int lower, int upper);
/**
* Generates a random long integer between <code>lower</code>
* and <code>upper</code> (endpoints included).<br>
* The generated long sequence will be cryptographically secure.<br>
* If cryptographic security is not required,
* use <code>nextLong</code><br>
* and <code>upper</code> (endpoints included).<p>
* Sequences of long values generated using this method will be
* cryptographically secure. If cryptographic security is not required,
* <code>nextLong</code> should be used instead of this method.
* <p>
* <strong>Definition</strong>:
* <a href=http://www.wikipedia.org/wiki/Cryptographically_secure_pseudo-random_number_generator>
* <a href="http://www.wikipedia.org/wiki/
* Cryptographically_secure_pseudo-random_number_generator">
* Secure Random Sequence</a>
* <p>
* <strong>Preconditions</strong>:<ul>
* <li><code>lower < upper</code> (otherwise an IllegalArgumentException
* is thrown.)</li>
* </ul>
*
* @param lower lower bound for generated integer
* @param upper upper bound for generated integer
* @exception IllegalArgumentException thrown if
* <code>lower</code> is not strictly less than <code>upper</code>.
* @return a long integer greater than or equal to <code>lower</code>
* and less than or equal to <code>upper</code>.
*/
public long nextSecureLong(long lower, long upper);
long nextSecureLong(long lower, long upper);
/**
* Generates a random value from the Poisson distribution with
* the given mean.<br>
* the given mean.
* <p>
* <strong>Definition</strong>:
* <a href=http://www.itl.nist.gov/div898/handbook/eda/section3/eda366j.htm>
* Poisson Distribution</a><br>
* <a href="http://www.itl.nist.gov/div898/handbook/
* eda/section3/eda366j.htm">
* Poisson Distribution</a>
* <p>
* <strong>Preconditions</strong>: <ul>
* <li>The specified mean <i>must</i> be positive </li>
* <li>The specified mean <i>must</i> be positive (otherwise an
* IllegalArgumentException is thrown.)</li>
* </ul>
* @param mean Mean of the distribution
* @returns long
* @throws IllegalArgumentException if mean <= 0
* @return poisson deviate with the specified mean
*/
public long nextPoisson(double mean);
long nextPoisson(double mean);
/**
* Generates a random value from the
* Normal (a.k.a. Gaussian) distribution with the given mean
* and standard deviation.<br>
* Normal (or Gaussian) distribution with the given mean
* and standard deviation.
* <p>
* <strong>Definition</strong>:
* <a href=http://www.itl.nist.gov/div898/handbook/eda/section3/eda3661.htm>
* Normal Distribution</a><br>
* <a href="http://www.itl.nist.gov/div898/handbook/
* eda/section3/eda3661.htm">
* Normal Distribution</a>
* <p>
* <strong>Preconditions</strong>: <ul>
* <li>The specified standard deviation <i>must</i> be positive </li>
* <li><code>sigma > 0</code> (otherwise an IllegalArgumentException
* is thrown.)</li>
* </ul>
* @param mu Mean of the distribution
* @param sigma Standard deviation of the distribution
* @return random value from Gaussian distribution with mean = mu,
* standard deviation = sigma
* @throws IllegalArgumentExcption if sigma <= 0
*/
public double nextGaussian(double mu,double sigma);
double nextGaussian(double mu, double sigma);
/**
* Generates a random value from the exponential distribution
* with expected value = <code>mean</code><br>
* with expected value = <code>mean</code>.
* <p>
* <strong>Definition</strong>:
* <a href=http://www.itl.nist.gov/div898/handbook/eda/section3/eda3667.htm>
* Exponential Distribution</a><br>
* <a href="http://www.itl.nist.gov/div898/handbook/
* eda/section3/eda3667.htm">
* Exponential Distribution</a>
* <p>
* <strong>Preconditions</strong>: <ul>
* <li>The specified mean <i>must</i> be non-negative</li>
* <li><code>mu >= 0</code> (otherwise an IllegalArgumentException
* is thrown.)</li>
* </ul>
* @param mu Mean of the distribution
* @param mean Mean of the distribution
* @return random value from exponential distribution
*/
public double nextExponential(double mean);
double nextExponential(double mean);
/**
* Generates a uniformly distributed random value from the open interval
* (<code>lower</code>,<code>upper</code>) (i.e., endpoints excluded)
* (<code>lower</code>,<code>upper</code>) (i.e., endpoints excluded).
* <p>
* <strong>Definition</strong>:
* <a href=http://www.itl.nist.gov/div898/handbook/eda/section3/eda3662.htm>
* Uniform Distribution</a> <code>lower</code> and <code>upper - lower</code>
* are the
* <a href = http://www.itl.nist.gov/div898/handbook/eda/section3/eda364.htm>
* location and scale parameters</a>, respectively<br>
* <a href="http://www.itl.nist.gov/div898/handbook/
* eda/section3/eda3662.htm">
* Uniform Distribution</a> <code>lower</code> and
* <code>upper - lower</code> are the
* <a href = "http://www.itl.nist.gov/div898/handbook/eda/
* section3/eda364.htm">
* location and scale parameters</a>, respectively.
* <p>
* <strong>Preconditions</strong>:<ul>
* <li><code>lower < upper</code> (otherwise an IllegalArgumentException
* is thrown.)</li>
* </ul>
*
* @param lower lower endpoint of the interval of support
* @param upper upper endpoint of the interval of support
* @return uniformly distributed random value between lower
* and upper (exclusive)
* @exception IllegalArgumentException thrown if
* <code>lower</code> is not strictly less than <code>upper</code>.
*/
public double nextUniform(double lower, double upper);
double nextUniform(double lower, double upper);
/**
* Generates an integer array of length <code>k</code> whose entries
* are selected randomly, without repetition, from the integers
* {0, ... , n-1} -- i.e., generated arrays represent permutations
* of <code>n</code> taken <code>k</code> at a time. <p>
*
* are selected randomly, without repetition, from the integers <code>
* 0 through n-1</code> (inclusive).
* <p>
* Generated arrays represent permutations
* of <code>n</code> taken <code>k</code> at a time.
* <p>
* <strong>Preconditions:</strong><ul>
* <li> k must be less than or equal to n </li>
* <li> n must be positive (i.e. greater than 0) </li>
* <li> <code>k <= n</code></li>
* <li> <code>n > 0</code> </li>
* </ul>
* If the preconditions are not met, an IllegalArgumentException is
* thrown.
*
* @param n domain of the permutation
* @param k size of the permutation
* @return random k-permutation of n
*/
public int[] nextPermutation(int n, int k);
int[] nextPermutation(int n, int k);
/**
* Returns an array of <code>k</code> objects selected randomly
* from the Collection <code>c</code>. Sampling from <code>c</code>
* from the Collection <code>c</code>.
* <p>
* Sampling from <code>c</code>
* is without replacement; but if <code>c</code> contains identical
* objects, the sample may include repeats. If all elements of <code>
* c</code> are distinct, the resulting object array represents a
* <a href=http://rkb.home.cern.ch/rkb/AN16pp/node250.html#SECTION0002500000000000000000>
* <a href="http://rkb.home.cern.ch/rkb/AN16pp/
* node250.html#SECTION0002500000000000000000">
* Simple Random Sample</a> of size
* <code>k</code> from the elements of <code>c</code>.<p>
*
* <code>k</code> from the elements of <code>c</code>.
* <p>
* <strong>Preconditions:</strong><ul>
* <li> k must be less than or equal to the size of c </li>
* <li> c must not be empty </li>
* </ul>
* If the preconditions are not met, an IllegalArgumentException is
* thrown.
*
* @param c collection to be sampled
* @param k size of the sample
* @return random sample of k elements from c
*/
public Object[] nextSample(Collection c, int k);
Object[] nextSample(Collection c, int k);
}

View File

@ -64,42 +64,50 @@ import java.util.Collection;
/**
* Implements the <code>RandomData</code> interface using
* <code>java.util.Random</code> and
* <code>java.util.Random.SecureRandom</code> instances to generate data.
* <code>java.util.Random.SecureRandom</code> instances to generate data.
* <p>
* Supports reseeding the underlying
* <a href=http://www.wikipedia.org/wiki/Pseudo-random_number_generator>PRNG</a>.
* The <code>SecurityProvider</code> and <code>Algorithm</code>
* used by the <code>SecureRandom</code> instance can also be reset.<p>
* <a href="http://www.wikipedia.org/wiki/Pseudo-random_number_generator">
* PRNG</a>. The <code>SecurityProvider</code> and <code>Algorithm</code>
* used by the <code>SecureRandom</code> instance can also be reset.
* <p>
* For details on the PRNGs, see the JDK documentation for
* <code>java.util.Random</code> and
* <code>java.util.Random.SecureRandom</code></p><p>
* <code>java.util.Random.SecureRandom</code>
* <p>
* <strong>Usage Notes</strong>: <ul>
* <li>Instance variables are used to maintain <code>Random</code> and
* <li>
* Instance variables are used to maintain <code>Random</code> and
* <code>SecureRandom</code> instances used in data generation. Therefore,
* to generate a random sequence of values or strings, you should use just
* <strong>one</strong> <code>RandomDataImpl</code> instance repeatedly.</li>
* <li>The "secure" methods are *much* slower. These should be used only when
* a <a href=http://www.wikipedia.org/wiki/Cryptographically_secure_pseudo-random_number_generator>
* Secure Random Sequence</a> is required.</li>
*<li>When a new <code>RandomDataImpl</code> is created, the underlying random
* <li>
* The "secure" methods are *much* slower. These should be used only when
* a <a href="http://www.wikipedia.org/wiki/
* Cryptographically_secure_pseudo-random_number_generator"> Secure Random
* Sequence</a> is required.</li>
* <li>
* When a new <code>RandomDataImpl</code> is created, the underlying random
* number generators are <strong>not</strong> intialized. The first call to a
* data generation method, or to a <code>reSeed()</code> method instantiates
* the appropriate generator. If you do not explicitly seed the generator, it
* is by default seeded with the current time in milliseconds</li>
* <li>The <code>reSeed</code> and <code>reSeedSecure</code> methods delegate to
* the corresponding methods on the underlying <code>Random</code> and <code>
* SecureRandom</code> instances. Therefore, the contracts of these methods
* are as defined in the JDK documentation. In particular, <code>reSeed(long)
* </code> fully resets the initial state of the non-secure random number
* generator (so that reseeding with a specific value always results in the
* same subsequent random sequence); whereas reSeedSecure(long) does <strong> not
* </strong> reinitialize the secure random number generator (so secure sequences
* started with calls to reseedSecure(long) won't be identical).</li></ul>
*</p>
* <li>
* The <code>reSeed</code> and <code>reSeedSecure</code> methods delegate
* to the corresponding methods on the underlying <code>Random</code> and
* <code>SecureRandom</code> instances. Therefore, the contracts of these
* methods are as defined in the JDK documentation. In particular,
* <code>reSeed(long)</code> fully resets the initial state of the non-secure
* random number generator (so that reseeding with a specific value always
* results in the same subsequent random sequence); whereas reSeedSecure(long)
* does <strong>not</strong> reinitialize the secure random number generator
* (so secure sequences started with calls to reseedSecure(long) won't be
* identical).</li></ul>
*
* @author Phil Steitz
* @version $Revision: 1.2 $ $Date: 2003/05/29 19:45:35 $
* @version $Revision: 1.3 $ $Date: 2003/06/04 02:45:49 $
*/
public class RandomDataImpl implements RandomData{
public class RandomDataImpl implements RandomData {
/** underlying random number generator */
private Random rand = null;
@ -107,20 +115,19 @@ public class RandomDataImpl implements RandomData{
/** underlying secure random number generator */
private SecureRandom secRand = null;
public RandomDataImpl(){
/**
* Construct a RandomDataImpl.
*/
public RandomDataImpl() {
}
/**
* Generates a random string of hex characters
* If cryptographic security is required, use
* <code>nextSecureHexString()</code>.<br>
* <strong>Algorithm Description:</strong> hex strings are generated
* using a 2-step process. <ol>
* <li>len/2+1 binary bytes are generated using the underlying Random</li>
* <li>Each binary byte is translated into 2 hex digits</li></ol>
* @param len length of return string
* @exception IllegalArgumentException thrown if len <= 0
* @return the random hex string
* <li>
* len/2+1 binary bytes are generated using the underlying Random</li>
* <li>
* Each binary byte is translated into 2 hex digits</li></ol>
*/
public String nextHexString(int len) {
if (len <= 0) {
@ -146,23 +153,24 @@ public class RandomDataImpl implements RandomData{
* This guarantees <= 2 hex digits from toHexString()
* toHexString would otherwise add 2^32 to negative arguments.
*/
String hex = Integer.toHexString(c.intValue()+128);
String hex = Integer.toHexString(c.intValue() + 128);
// Make sure we add 2 hex digits for each byte
if (hex.length() == 1) hex = "0" + hex;
if (hex.length() == 1) {
hex = "0" + hex;
}
outBuffer.append(hex);
}
return outBuffer.toString().substring(0, len);
}
public int nextInt(int lower, int upper) {
if (lower >= upper) {
throw new IllegalArgumentException
("upper bound must be > lower bound");
}
Random rand = getRan();
return lower + (int)(Math.random() * (upper-lower+1));
return lower + (int) (Math.random() * (upper - lower + 1));
}
public long nextLong(long lower, long upper) {
@ -171,23 +179,22 @@ public class RandomDataImpl implements RandomData{
("upper bound must be > lower bound");
}
Random rand = getRan();
return lower + (long)(rand.nextDouble() * (upper-lower+1));
return lower + (long) (rand.nextDouble() * (upper - lower + 1));
}
/**
* Generates a random string of hex characters from a secure random sequence.
* If cryptographic security is not required,
* use <code>nextHexString()</code>.<br>
* <strong>Algorithm Description:</strong> hex strings are generated in 40-byte
* segments using a 3-step process. <ol>
* <li>20 random bytes are generated using the underlying SecureRandom</li>
* <li>SHA-1 hash is applied to yield a 20-byte binary digest</li>
* <li>Each byte of the binary digest is converted to 2 hex digits</li></ol><p>
* TODO: find external reference or provide justification for the claim that this
* yields a cryptographically secure sequence of hex strings.</p>
* @param len length of return string
* @exception IllegalArgumentException thrown if len <= 0
* @return the random hex string
* <strong>Algorithm Description:</strong> hex strings are generated in
* 40-byte segments using a 3-step process. <ol>
* <li>
* 20 random bytes are generated using the underlying
* <code>SecureRandom</code>.</li>
* <li>
* SHA-1 hash is applied to yield a 20-byte binary digest.</li>
* <li>
* Each byte of the binary digest is converted to 2 hex digits</li></ol>
* <p>
* TODO: find external reference or provide justification for the claim
* that this yields a cryptographically secure sequence of hex strings.
*/
public String nextSecureHexString(int len) {
if (len <= 0) {
@ -200,7 +207,7 @@ public class RandomDataImpl implements RandomData{
try {
alg = MessageDigest.getInstance("SHA-1");
} catch (NoSuchAlgorithmException ex) {
return null; // gulp FIXME? -- this *should* never fail. OK to swallow????
return null; // gulp FIXME? -- this *should* never fail.
}
alg.reset();
@ -225,48 +232,43 @@ public class RandomDataImpl implements RandomData{
* toHexString would otherwise add 2^32 to negative
* arguments
*/
String hex = Integer.toHexString(c.intValue()+128);
String hex = Integer.toHexString(c.intValue() + 128);
//Keep strings uniform length -- guarantees 40 bytes
if (hex.length() == 1) hex = "0" + hex;
if (hex.length() == 1) {
hex = "0" + hex;
}
outBuffer.append(hex);
}
}
return outBuffer.toString().substring(0, len);
}
public int nextSecureInt(int lower, int upper) {
if (lower >= upper) {
throw new IllegalArgumentException
("lower bound must be < upper bound");
}
SecureRandom sec = getSecRan();
return lower + (int)(sec.nextDouble() * (upper-lower+1));
return lower + (int) (sec.nextDouble() * (upper - lower + 1));
}
public long nextSecureLong(long lower, long upper) {
if (lower >= upper) {
throw new IllegalArgumentException
("lower bound must be < upper bound");
}
SecureRandom sec = getSecRan();
return lower + (long)(sec.nextDouble() * (upper-lower+1));
return lower + (long) (sec.nextDouble() * (upper - lower + 1));
}
/**
* Generates a random value from the Poisson distribution with
* the given mean.<br>
* <strong>Definition</strong>:
* <a href=http://www.itl.nist.gov/div898/handbook/eda/section3/eda366j.htm>
* Poisson Distribution</a><br>
* <strong>Algorithm Description</strong>:
* Uses simulation of a Poisson process using Uniform deviates, as described
* <a href = http://dmawww.epfl.ch/benarous/Pmmi/interactive/rng7.htm>
* Uses simulation of a Poisson process using Uniform deviates, as
* described
* <a href ="http://dmawww.epfl.ch/benarous/Pmmi/interactive/rng7.htm">
* here</a>
* @param mean Mean of the distribution
* @returns long
* @throws IllegalArgumentException if mean <= 0
*
*/
public long nextPoisson(double mean) {
double p = Math.exp(-mean);
@ -287,59 +289,38 @@ public class RandomDataImpl implements RandomData{
}
}
public double nextGaussian(double mu,double sigma) {
public double nextGaussian(double mu, double sigma) {
if (sigma <= 0) {
throw new IllegalArgumentException("Gaussian std dev must be > 0");
}
Random rand = getRan();
return sigma*rand.nextGaussian() + mu;
return sigma * rand.nextGaussian() + mu;
}
/**
* Generates a random value from the exponential distribution
* with expected value = <code>mean</code><br>
* <strong>Definition</strong>:
* <a href=http://www.itl.nist.gov/div898/handbook/eda/section3/eda3667.htm>
* Exponential Distribution</a><br>
* <strong>Preconditions</strong>: <ul>
* <li>The specified mean <i>must</i> be non-negative</li>
* </ul>
* <strong>Algorithm Description</strong>: Uses the
* <a href=http://www.jesus.ox.ac.uk/~clifford/a5/chap1/node5.html>
* <a href="http://www.jesus.ox.ac.uk/~clifford/a5/chap1/node5.html">
* Inversion Method</a> to generate exponential from uniform deviates.
* @param mu Mean of the distribution
* @return random value from exponential distribution
*/
public double nextExponential(double mean) {
if (mean < 0.0) throw new IllegalArgumentException
("Exponential mean must be >= 0");
if (mean < 0.0) {
throw new IllegalArgumentException
("Exponential mean must be >= 0");
}
Random rand = getRan();
double unif = rand.nextDouble();
while (unif == 0.0d) {
unif = rand.nextDouble();
}
return -mean*Math.log(unif);
return -mean * Math.log(unif);
}
/**
* Generates a uniformly distributed random value from the open interval
* (<code>lower</code>,<code>upper</code>) (i.e., endpoints excluded)
* <strong>Definition</strong>:
* <a href=http://www.itl.nist.gov/div898/handbook/eda/section3/eda3662.htm>
* Uniform Distribution</a> <code>lower</code> and <code>upper - lower</code>
* are the
* <a href = http://www.itl.nist.gov/div898/handbook/eda/section3/eda364.htm>
* location and scale parameters</a>, respectively<br>
* <strong>Algorithm Description</strong>: scales the output of
* Random.nextDouble(), but rejects 0 values (i.e., will generate another
* random double if Random.nextDouble() returns 0). This is necessary to
* provide a symmetric output interval (both endpoints excluded).
* @param lower lower endpoint of the interval of support
* @param upper upper endpoint of the interval of support
* @return uniformly distributed random value between lower
* and upper (exclusive)
* @exception IllegalArgumentException thrown if
* <code>lower</code> is not strictly less than <code>upper</code>.
* random double if Random.nextDouble() returns 0).
* This is necessary to provide a symmetric output interval
* (both endpoints excluded).
*/
public double nextUniform(double lower, double upper) {
if (lower >= upper) {
@ -347,16 +328,18 @@ public class RandomDataImpl implements RandomData{
("lower bound must be <= upper bound");
}
Random rand = getRan();
double result = lower + rand.nextDouble()*(upper-lower);
double result = lower + rand.nextDouble() * (upper - lower);
while (result == lower) {
result = lower + rand.nextDouble()*(upper-lower);
result = lower + rand.nextDouble() * (upper - lower);
}
return result;
}
/**
* Returns the static Random used to generate random data.<br>
* Creates and initializes if null
* Returns the static Random used to generate random data.
* <p>
* Creates and initializes if null.
*
* @return the static Random used to generate random data
*/
private Random getRan() {
@ -368,8 +351,10 @@ public class RandomDataImpl implements RandomData{
}
/**
* Returns the static SecureRandom used to generate secure random data.<br>
* Returns the static SecureRandom used to generate secure random data.
* <p>
* Creates and initializes if null.
*
* @return the static SecureRandom used to generate secure random data
*/
private SecureRandom getSecRan() {
@ -381,8 +366,10 @@ public class RandomDataImpl implements RandomData{
}
/**
* Reseeds the random number generator with the supplied seed. Will
* create and initialize if null.
* Reseeds the random number generator with the supplied seed.
* <p>
* Will create and initialize if null.
*
* @param seed the seed value to use
*/
public void reSeed(long seed) {
@ -394,18 +381,22 @@ public class RandomDataImpl implements RandomData{
/**
* Reseeds the secure random number generator with the current time
* in milliseconds. Will create and initialize if null.
* in milliseconds.
* <p>
* Will create and initialize if null.
*/
public void reSeedSecure() {
if (rand == null) {
rand = new Random();
if (secRand == null) {
secRand = new SecureRandom();
}
rand.setSeed(System.currentTimeMillis());
secRand.setSeed(System.currentTimeMillis());
}
/**
* Reseeds the secure random number generator with the supplied seed.
* <p>
* Will create and initialize if null.
*
* @param seed the seed value to use
*/
public void reSeedSecure(long seed) {
@ -417,7 +408,7 @@ public class RandomDataImpl implements RandomData{
/**
* Reseeds the random number generator with the current time
* in milliseconds
* in milliseconds.
*/
public void reSeed() {
if (rand == null) {
@ -429,18 +420,23 @@ public class RandomDataImpl implements RandomData{
/**
* Sets the PRNG algorithm for the underlying SecureRandom instance
* using the Security Provider API, as defined in
* <a href=http://java.sun.com/j2se/1.3/docs/guide/security/CryptoSpec.html#AppA>
* Java Cryptography Architecture API Specification & Reference</a><p>
* <strong>USAGE NOTE:</strong> This method carries <i>significant</i> overhead
* and may take several seconds to execute.</p>
* <a href="http://java.sun.com/j2se/1.3/docs/guide/security/
* CryptoSpec.html#AppA">
* Java Cryptography Architecture API Specification & Reference.</a>
* <p>
* <strong>USAGE NOTE:</strong> This method carries <i>significant</i>
* overhead and may take several seconds to execute.
*
* @param algorithm the name of the PRNG algorithm
* @param provider the name of the provider
* @throws NoSuchAlgorithmException if the specified algorithm is not available
* @throws NoSuchProviderException if the specified provider is not installed
* @throws NoSuchAlgorithmException if the specified algorithm
* is not available
* @throws NoSuchProviderException if the specified provider
* is not installed
*/
public void setSecureAlgorithm(String algorithm, String provider)
throws NoSuchAlgorithmException,NoSuchProviderException {
secRand = SecureRandom.getInstance(algorithm,provider);
throws NoSuchAlgorithmException, NoSuchProviderException {
secRand = SecureRandom.getInstance(algorithm, provider);
}
/**
@ -460,22 +456,22 @@ public class RandomDataImpl implements RandomData{
}
int[] index = getNatural(n);
shuffle(index,n-k);
shuffle(index, n - k);
int[] result = new int[k];
for (int i = 0; i < k; i++) {
result[i] = index[n-i-1];
result[i] = index[n - i - 1];
}
return result;
}
/**
* Uses a 2-cycle permutation shuffle to generate a random
* permutation of <code>c.size()</code> and then returns the
* elements whose indexes correspond to the elements of the
* generated permutation. This technique is described, and
* proven to generate random samples,
* <a href=http://www.maths.abdn.ac.uk/~igc/tch/mx4002/notes/node83.html>
* <strong>Algorithm Description</strong>: Uses a 2-cycle permutation
* shuffle to generate a random permutation of <code>c.size()</code> and
* then returns the elements whose indexes correspond to the elements of
* the generated permutation.
* This technique is described, and proven to generate random samples,
* <a href="http://www.maths.abdn.ac.uk/~igc/tch/mx4002/notes/node83.html">
* here</a>
*/
public Object[] nextSample(Collection c, int k) {
@ -490,9 +486,9 @@ public class RandomDataImpl implements RandomData{
}
Object[] objects = c.toArray();
int[] index = nextPermutation(len,k);
int[] index = nextPermutation(len, k);
Object[] result = new Object[k];
for (int i = 0; i < k; i ++) {
for (int i = 0; i < k; i++) {
result[i] = objects[index[i]];
}
return result;
@ -501,19 +497,19 @@ public class RandomDataImpl implements RandomData{
//------------------------Private methods----------------------------------
/**
* Uses a 2-cycle permutation shuffle to randomly re-order the last
* end elements of list
* <strong>Algorithm Description</strong>: Uses a 2-cycle permutation
* shuffle to randomly re-order the last <code>end</code> elements of list.
*
* @param list list to be shuffled
* @end element past which shuffling begins
*/
private void shuffle(int[] list, int end) {
int target = 0;
for (int i = list.length-1 ; i >= end; i--) {
for (int i = list.length - 1 ; i >= end; i--) {
if (i == 0) {
target = 0;
} else {
target = nextInt(0,i);
target = nextInt(0, i);
}
int temp = list[target];
list[target] = list[i];
@ -522,7 +518,7 @@ public class RandomDataImpl implements RandomData{
}
/**
* Returns an array representing n
* Returns an array representing n.
*
* @param n the natural number to represent
* @return array with entries = elements of n

View File

@ -69,7 +69,7 @@ import org.apache.commons.math.stat.UnivariateImpl;
* Test cases for the RandomData class.
*
* @author Phil Steitz
* @version $Revision: 1.4 $ $Date: 2003/05/29 20:35:45 $
* @version $Revision: 1.5 $ $Date: 2003/06/04 02:45:49 $
*/
public final class RandomDataTest extends TestCase {
@ -462,9 +462,9 @@ public final class RandomDataTest extends TestCase {
assertTrue("same seeds",
!hex.equals(randomData.nextSecureHexString(40)));
/* TODO: probably should remove this test as the package grows,
* since it takes about 4 seconds
*/
/* remove this test back soon,
* since it takes about 4 seconds */
randomData.setSecureAlgorithm("SHA1PRNG","SUN");
assertTrue("different seeds",
!hex.equals(randomData.nextSecureHexString(40)));
@ -480,7 +480,21 @@ public final class RandomDataTest extends TestCase {
fail("expecting NoSuchProviderException");
} catch (NoSuchProviderException ex) {
;
}
}
// test reseeding without first using the generators
RandomDataImpl rd = new RandomDataImpl();
rd.reSeed(100);
double ret = rd.nextLong(1,2);
RandomDataImpl rd2 = new RandomDataImpl();
rd2.reSeedSecure(2000);
ret = rd2.nextSecureLong(1,2);
rd = new RandomDataImpl();
rd.reSeed();
ret = rd.nextLong(1,2);
rd2 = new RandomDataImpl();
rd2.reSeedSecure();
ret = rd2.nextSecureLong(1,2);
}
/** tests for nextSample() sampling from Collection */