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 * Random data generation utilities
* @author Phil Steitz * @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 { public interface RandomData {
/** /**
* Generates a random string of hex characters of length * 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 * The generated string will be random, but not cryptographically
* secure. To generate cryptographically secure strings, use * secure. To generate cryptographically secure strings, use
* <code>nextSecureHexString</code> * <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 * @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 * 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. * The generated integer will be random, but not cryptographically secure.
* To generate cryptographically secure integer sequences, use * To generate cryptographically secure integer sequences, use
* <code>nextSecureInt</code>. * <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 lower lower bound for generated integer
* @param upper upper 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> * @return a random integer greater than or equal to <code>lower</code>
* and less than or equal to <code>upper</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 < * Generates a uniformly distributed random long integer between
* code>lower</code> and <code>upper</code> (endpoints included). * <code>lower</code> and <code>upper</code> (endpoints included).
* <p>
* The generated long integer values will be random, but not * The generated long integer values will be random, but not
* cryptographically secure.<br> * cryptographically secure.
* To generate cryptographically secure sequences of longs, use * To generate cryptographically secure sequences of longs, use
* <code>nextSecureLong</code> * <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 lower lower bound for generated integer
* @param upper upper 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> * @return a random integer greater than or equal to <code>lower</code>
* and less than or equal to <code>upper</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, * If cryptographic security is not required,
* use <code>nextHexString()</code>. * 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 * @param len length of return string
* @exception IllegalArgumentException thrown if len <= 0
* @return the random hex string * @return the random hex string
*/ */
public String nextSecureHexString(int len); String nextSecureHexString(int len);
/** /**
* Generates a uniformly distributed random integer between * Generates a uniformly distributed random integer between
* <code>lower</code> and <code>upper</code> (endpoints included) * <code>lower</code> and <code>upper</code> (endpoints included)
* from a secure random sequence.<br> * from a secure random sequence.
* The generated sequence will be cryptographically secure.<br> * <p>
* If cryptographic security is not required, <code>nextInt</code> * Sequences of integers generated using this method will be
* should be used.<br> * cryptographically secure. If cryptographic security is not required,
* <strong>Definition</strong>(secure random sequence): * <code>nextInt</code> should be used instead of this method.
* http://www.wikipedia.org/wiki/Cryptographically_secure_pseudo-random_number_generator<br> * <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 lower lower bound for generated integer
* @param upper upper 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> * @return a random integer greater than or equal to <code>lower</code>
* and less than or equal to <code>upper</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> * Generates a random long integer between <code>lower</code>
* and <code>upper</code> (endpoints included).<br> * and <code>upper</code> (endpoints included).<p>
* The generated long sequence will be cryptographically secure.<br> * Sequences of long values generated using this method will be
* If cryptographic security is not required, * cryptographically secure. If cryptographic security is not required,
* use <code>nextLong</code><br> * <code>nextLong</code> should be used instead of this method.
* <p>
* <strong>Definition</strong>: * <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> * 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 lower lower bound for generated integer
* @param upper upper 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> * @return a long integer greater than or equal to <code>lower</code>
* and less than or equal to <code>upper</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 * Generates a random value from the Poisson distribution with
* the given mean.<br> * the given mean.
* <p>
* <strong>Definition</strong>: * <strong>Definition</strong>:
* <a href=http://www.itl.nist.gov/div898/handbook/eda/section3/eda366j.htm> * <a href="http://www.itl.nist.gov/div898/handbook/
* Poisson Distribution</a><br> * eda/section3/eda366j.htm">
* Poisson Distribution</a>
* <p>
* <strong>Preconditions</strong>: <ul> * <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> * </ul>
* @param mean Mean of the distribution * @param mean Mean of the distribution
* @returns long * @return poisson deviate with the specified mean
* @throws IllegalArgumentException if mean <= 0
*/ */
public long nextPoisson(double mean); long nextPoisson(double mean);
/** /**
* Generates a random value from the * Generates a random value from the
* Normal (a.k.a. Gaussian) distribution with the given mean * Normal (or Gaussian) distribution with the given mean
* and standard deviation.<br> * and standard deviation.
* <p>
* <strong>Definition</strong>: * <strong>Definition</strong>:
* <a href=http://www.itl.nist.gov/div898/handbook/eda/section3/eda3661.htm> * <a href="http://www.itl.nist.gov/div898/handbook/
* Normal Distribution</a><br> * eda/section3/eda3661.htm">
* Normal Distribution</a>
* <p>
* <strong>Preconditions</strong>: <ul> * <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> * </ul>
* @param mu Mean of the distribution * @param mu Mean of the distribution
* @param sigma Standard deviation of the distribution * @param sigma Standard deviation of the distribution
* @return random value from Gaussian distribution with mean = mu, * @return random value from Gaussian distribution with mean = mu,
* standard deviation = sigma * 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 * 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>: * <strong>Definition</strong>:
* <a href=http://www.itl.nist.gov/div898/handbook/eda/section3/eda3667.htm> * <a href="http://www.itl.nist.gov/div898/handbook/
* Exponential Distribution</a><br> * eda/section3/eda3667.htm">
* Exponential Distribution</a>
* <p>
* <strong>Preconditions</strong>: <ul> * <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> * </ul>
* @param mu Mean of the distribution * @param mean Mean of the distribution
* @return random value from exponential 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 * 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>: * <strong>Definition</strong>:
* <a href=http://www.itl.nist.gov/div898/handbook/eda/section3/eda3662.htm> * <a href="http://www.itl.nist.gov/div898/handbook/
* Uniform Distribution</a> <code>lower</code> and <code>upper - lower</code> * eda/section3/eda3662.htm">
* are the * Uniform Distribution</a> <code>lower</code> and
* <a href = http://www.itl.nist.gov/div898/handbook/eda/section3/eda364.htm> * <code>upper - lower</code> are the
* location and scale parameters</a>, respectively<br> * <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 lower lower endpoint of the interval of support
* @param upper upper endpoint of the interval of support * @param upper upper endpoint of the interval of support
* @return uniformly distributed random value between lower * @return uniformly distributed random value between lower
* and upper (exclusive) * 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 * Generates an integer array of length <code>k</code> whose entries
* are selected randomly, without repetition, from the integers * are selected randomly, without repetition, from the integers <code>
* {0, ... , n-1} -- i.e., generated arrays represent permutations * 0 through n-1</code> (inclusive).
* of <code>n</code> taken <code>k</code> at a time. <p> * <p>
* * Generated arrays represent permutations
* of <code>n</code> taken <code>k</code> at a time.
* <p>
* <strong>Preconditions:</strong><ul> * <strong>Preconditions:</strong><ul>
* <li> k must be less than or equal to n </li> * <li> <code>k <= n</code></li>
* <li> n must be positive (i.e. greater than 0) </li> * <li> <code>n > 0</code> </li>
* </ul> * </ul>
* If the preconditions are not met, an IllegalArgumentException is
* thrown.
* *
* @param n domain of the permutation * @param n domain of the permutation
* @param k size of the permutation * @param k size of the permutation
* @return random k-permutation of n * @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 * 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 * is without replacement; but if <code>c</code> contains identical
* objects, the sample may include repeats. If all elements of <code> * objects, the sample may include repeats. If all elements of <code>
* c</code> are distinct, the resulting object array represents a * 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 * 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> * <strong>Preconditions:</strong><ul>
* <li> k must be less than or equal to the size of c </li> * <li> k must be less than or equal to the size of c </li>
* <li> c must not be empty </li> * <li> c must not be empty </li>
* </ul> * </ul>
* If the preconditions are not met, an IllegalArgumentException is
* thrown.
* *
* @param c collection to be sampled * @param c collection to be sampled
* @param k size of the sample * @param k size of the sample
* @return random sample of k elements from c * @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 * Implements the <code>RandomData</code> interface using
* <code>java.util.Random</code> and * <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 * Supports reseeding the underlying
* <a href=http://www.wikipedia.org/wiki/Pseudo-random_number_generator>PRNG</a>. * <a href="http://www.wikipedia.org/wiki/Pseudo-random_number_generator">
* The <code>SecurityProvider</code> and <code>Algorithm</code> * PRNG</a>. The <code>SecurityProvider</code> and <code>Algorithm</code>
* used by the <code>SecureRandom</code> instance can also be reset.<p> * used by the <code>SecureRandom</code> instance can also be reset.
* <p>
* For details on the PRNGs, see the JDK documentation for * For details on the PRNGs, see the JDK documentation for
* <code>java.util.Random</code> and * <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> * <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, * <code>SecureRandom</code> instances used in data generation. Therefore,
* to generate a random sequence of values or strings, you should use just * to generate a random sequence of values or strings, you should use just
* <strong>one</strong> <code>RandomDataImpl</code> instance repeatedly.</li> * <strong>one</strong> <code>RandomDataImpl</code> instance repeatedly.</li>
* <li>The "secure" methods are *much* slower. These should be used only when * <li>
* a <a href=http://www.wikipedia.org/wiki/Cryptographically_secure_pseudo-random_number_generator> * The "secure" methods are *much* slower. These should be used only when
* Secure Random Sequence</a> is required.</li> * a <a href="http://www.wikipedia.org/wiki/
*<li>When a new <code>RandomDataImpl</code> is created, the underlying random * 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 * number generators are <strong>not</strong> intialized. The first call to a
* data generation method, or to a <code>reSeed()</code> method instantiates * data generation method, or to a <code>reSeed()</code> method instantiates
* the appropriate generator. If you do not explicitly seed the generator, it * the appropriate generator. If you do not explicitly seed the generator, it
* is by default seeded with the current time in milliseconds</li> * is by default seeded with the current time in milliseconds</li>
* <li>The <code>reSeed</code> and <code>reSeedSecure</code> methods delegate to * <li>
* the corresponding methods on the underlying <code>Random</code> and <code> * The <code>reSeed</code> and <code>reSeedSecure</code> methods delegate
* SecureRandom</code> instances. Therefore, the contracts of these methods * to the corresponding methods on the underlying <code>Random</code> and
* are as defined in the JDK documentation. In particular, <code>reSeed(long) * <code>SecureRandom</code> instances. Therefore, the contracts of these
* </code> fully resets the initial state of the non-secure random number * methods are as defined in the JDK documentation. In particular,
* generator (so that reseeding with a specific value always results in the * <code>reSeed(long)</code> fully resets the initial state of the non-secure
* same subsequent random sequence); whereas reSeedSecure(long) does <strong> not * random number generator (so that reseeding with a specific value always
* </strong> reinitialize the secure random number generator (so secure sequences * results in the same subsequent random sequence); whereas reSeedSecure(long)
* started with calls to reseedSecure(long) won't be identical).</li></ul> * does <strong>not</strong> reinitialize the secure random number generator
*</p> * (so secure sequences started with calls to reseedSecure(long) won't be
* identical).</li></ul>
* *
* @author Phil Steitz * @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 */ /** underlying random number generator */
private Random rand = null; private Random rand = null;
@ -107,20 +115,19 @@ public class RandomDataImpl implements RandomData{
/** underlying secure random number generator */ /** underlying secure random number generator */
private SecureRandom secRand = null; 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 * <strong>Algorithm Description:</strong> hex strings are generated
* using a 2-step process. <ol> * using a 2-step process. <ol>
* <li>len/2+1 binary bytes are generated using the underlying Random</li> * <li>
* <li>Each binary byte is translated into 2 hex digits</li></ol> * len/2+1 binary bytes are generated using the underlying Random</li>
* @param len length of return string * <li>
* @exception IllegalArgumentException thrown if len <= 0 * Each binary byte is translated into 2 hex digits</li></ol>
* @return the random hex string
*/ */
public String nextHexString(int len) { public String nextHexString(int len) {
if (len <= 0) { if (len <= 0) {
@ -146,23 +153,24 @@ public class RandomDataImpl implements RandomData{
* This guarantees <= 2 hex digits from toHexString() * This guarantees <= 2 hex digits from toHexString()
* toHexString would otherwise add 2^32 to negative arguments. * 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 // 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); outBuffer.append(hex);
} }
return outBuffer.toString().substring(0, len); return outBuffer.toString().substring(0, len);
} }
public int nextInt(int lower, int upper) { public int nextInt(int lower, int upper) {
if (lower >= upper) { if (lower >= upper) {
throw new IllegalArgumentException throw new IllegalArgumentException
("upper bound must be > lower bound"); ("upper bound must be > lower bound");
} }
Random rand = getRan(); 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) { public long nextLong(long lower, long upper) {
@ -171,23 +179,22 @@ public class RandomDataImpl implements RandomData{
("upper bound must be > lower bound"); ("upper bound must be > lower bound");
} }
Random rand = getRan(); 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. * <strong>Algorithm Description:</strong> hex strings are generated in
* If cryptographic security is not required, * 40-byte segments using a 3-step process. <ol>
* use <code>nextHexString()</code>.<br> * <li>
* <strong>Algorithm Description:</strong> hex strings are generated in 40-byte * 20 random bytes are generated using the underlying
* segments using a 3-step process. <ol> * <code>SecureRandom</code>.</li>
* <li>20 random bytes are generated using the underlying SecureRandom</li> * <li>
* <li>SHA-1 hash is applied to yield a 20-byte binary digest</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> * <li>
* TODO: find external reference or provide justification for the claim that this * Each byte of the binary digest is converted to 2 hex digits</li></ol>
* yields a cryptographically secure sequence of hex strings.</p> * <p>
* @param len length of return string * TODO: find external reference or provide justification for the claim
* @exception IllegalArgumentException thrown if len <= 0 * that this yields a cryptographically secure sequence of hex strings.
* @return the random hex string
*/ */
public String nextSecureHexString(int len) { public String nextSecureHexString(int len) {
if (len <= 0) { if (len <= 0) {
@ -200,7 +207,7 @@ public class RandomDataImpl implements RandomData{
try { try {
alg = MessageDigest.getInstance("SHA-1"); alg = MessageDigest.getInstance("SHA-1");
} catch (NoSuchAlgorithmException ex) { } catch (NoSuchAlgorithmException ex) {
return null; // gulp FIXME? -- this *should* never fail. OK to swallow???? return null; // gulp FIXME? -- this *should* never fail.
} }
alg.reset(); alg.reset();
@ -225,48 +232,43 @@ public class RandomDataImpl implements RandomData{
* toHexString would otherwise add 2^32 to negative * toHexString would otherwise add 2^32 to negative
* arguments * arguments
*/ */
String hex = Integer.toHexString(c.intValue()+128); String hex = Integer.toHexString(c.intValue() + 128);
//Keep strings uniform length -- guarantees 40 bytes //Keep strings uniform length -- guarantees 40 bytes
if (hex.length() == 1) hex = "0" + hex; if (hex.length() == 1) {
hex = "0" + hex;
}
outBuffer.append(hex); outBuffer.append(hex);
} }
} }
return outBuffer.toString().substring(0, len); return outBuffer.toString().substring(0, len);
} }
public int nextSecureInt(int lower, int upper) { public int nextSecureInt(int lower, int upper) {
if (lower >= upper) { if (lower >= upper) {
throw new IllegalArgumentException throw new IllegalArgumentException
("lower bound must be < upper bound"); ("lower bound must be < upper bound");
} }
SecureRandom sec = getSecRan(); 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) { public long nextSecureLong(long lower, long upper) {
if (lower >= upper) { if (lower >= upper) {
throw new IllegalArgumentException throw new IllegalArgumentException
("lower bound must be < upper bound"); ("lower bound must be < upper bound");
} }
SecureRandom sec = getSecRan(); 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>: * <strong>Algorithm Description</strong>:
* Uses simulation of a Poisson process using Uniform deviates, as described * Uses simulation of a Poisson process using Uniform deviates, as
* <a href = http://dmawww.epfl.ch/benarous/Pmmi/interactive/rng7.htm> * described
* <a href ="http://dmawww.epfl.ch/benarous/Pmmi/interactive/rng7.htm">
* here</a> * here</a>
* @param mean Mean of the distribution *
* @returns long
* @throws IllegalArgumentException if mean <= 0
*/ */
public long nextPoisson(double mean) { public long nextPoisson(double mean) {
double p = Math.exp(-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) { if (sigma <= 0) {
throw new IllegalArgumentException("Gaussian std dev must be > 0"); throw new IllegalArgumentException("Gaussian std dev must be > 0");
} }
Random rand = getRan(); 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 * <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. * 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) { public double nextExponential(double mean) {
if (mean < 0.0) throw new IllegalArgumentException if (mean < 0.0) {
("Exponential mean must be >= 0"); throw new IllegalArgumentException
("Exponential mean must be >= 0");
}
Random rand = getRan(); Random rand = getRan();
double unif = rand.nextDouble(); double unif = rand.nextDouble();
while (unif == 0.0d) { while (unif == 0.0d) {
unif = rand.nextDouble(); 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 * <strong>Algorithm Description</strong>: scales the output of
* Random.nextDouble(), but rejects 0 values (i.e., will generate another * Random.nextDouble(), but rejects 0 values (i.e., will generate another
* random double if Random.nextDouble() returns 0). This is necessary to * random double if Random.nextDouble() returns 0).
* provide a symmetric output interval (both endpoints excluded). * This is necessary to provide a symmetric output interval
* @param lower lower endpoint of the interval of support * (both endpoints excluded).
* @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) { public double nextUniform(double lower, double upper) {
if (lower >= upper) { if (lower >= upper) {
@ -347,16 +328,18 @@ public class RandomDataImpl implements RandomData{
("lower bound must be <= upper bound"); ("lower bound must be <= upper bound");
} }
Random rand = getRan(); Random rand = getRan();
double result = lower + rand.nextDouble()*(upper-lower); double result = lower + rand.nextDouble() * (upper - lower);
while (result == lower) { while (result == lower) {
result = lower + rand.nextDouble()*(upper-lower); result = lower + rand.nextDouble() * (upper - lower);
} }
return result; return result;
} }
/** /**
* Returns the static Random used to generate random data.<br> * Returns the static Random used to generate random data.
* Creates and initializes if null * <p>
* Creates and initializes if null.
*
* @return the static Random used to generate random data * @return the static Random used to generate random data
*/ */
private Random getRan() { 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. * Creates and initializes if null.
*
* @return the static SecureRandom used to generate secure random data * @return the static SecureRandom used to generate secure random data
*/ */
private SecureRandom getSecRan() { private SecureRandom getSecRan() {
@ -381,8 +366,10 @@ public class RandomDataImpl implements RandomData{
} }
/** /**
* Reseeds the random number generator with the supplied seed. Will * Reseeds the random number generator with the supplied seed.
* create and initialize if null. * <p>
* Will create and initialize if null.
*
* @param seed the seed value to use * @param seed the seed value to use
*/ */
public void reSeed(long seed) { public void reSeed(long seed) {
@ -394,18 +381,22 @@ public class RandomDataImpl implements RandomData{
/** /**
* Reseeds the secure random number generator with the current time * 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() { public void reSeedSecure() {
if (rand == null) { if (secRand == null) {
rand = new Random(); secRand = new SecureRandom();
} }
rand.setSeed(System.currentTimeMillis()); secRand.setSeed(System.currentTimeMillis());
} }
/** /**
* Reseeds the secure random number generator with the supplied seed. * Reseeds the secure random number generator with the supplied seed.
* <p>
* Will create and initialize if null. * Will create and initialize if null.
*
* @param seed the seed value to use * @param seed the seed value to use
*/ */
public void reSeedSecure(long seed) { public void reSeedSecure(long seed) {
@ -417,7 +408,7 @@ public class RandomDataImpl implements RandomData{
/** /**
* Reseeds the random number generator with the current time * Reseeds the random number generator with the current time
* in milliseconds * in milliseconds.
*/ */
public void reSeed() { public void reSeed() {
if (rand == null) { if (rand == null) {
@ -429,18 +420,23 @@ public class RandomDataImpl implements RandomData{
/** /**
* Sets the PRNG algorithm for the underlying SecureRandom instance * Sets the PRNG algorithm for the underlying SecureRandom instance
* using the Security Provider API, as defined in * using the Security Provider API, as defined in
* <a href=http://java.sun.com/j2se/1.3/docs/guide/security/CryptoSpec.html#AppA> * <a href="http://java.sun.com/j2se/1.3/docs/guide/security/
* Java Cryptography Architecture API Specification & Reference</a><p> * CryptoSpec.html#AppA">
* <strong>USAGE NOTE:</strong> This method carries <i>significant</i> overhead * Java Cryptography Architecture API Specification & Reference.</a>
* and may take several seconds to execute.</p> * <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 algorithm the name of the PRNG algorithm
* @param provider the name of the provider * @param provider the name of the provider
* @throws NoSuchAlgorithmException if the specified algorithm is not available * @throws NoSuchAlgorithmException if the specified algorithm
* @throws NoSuchProviderException if the specified provider is not installed * is not available
* @throws NoSuchProviderException if the specified provider
* is not installed
*/ */
public void setSecureAlgorithm(String algorithm, String provider) public void setSecureAlgorithm(String algorithm, String provider)
throws NoSuchAlgorithmException,NoSuchProviderException { throws NoSuchAlgorithmException, NoSuchProviderException {
secRand = SecureRandom.getInstance(algorithm,provider); secRand = SecureRandom.getInstance(algorithm, provider);
} }
/** /**
@ -460,22 +456,22 @@ public class RandomDataImpl implements RandomData{
} }
int[] index = getNatural(n); int[] index = getNatural(n);
shuffle(index,n-k); shuffle(index, n - k);
int[] result = new int[k]; int[] result = new int[k];
for (int i = 0; i < k; i++) { for (int i = 0; i < k; i++) {
result[i] = index[n-i-1]; result[i] = index[n - i - 1];
} }
return result; return result;
} }
/** /**
* Uses a 2-cycle permutation shuffle to generate a random * <strong>Algorithm Description</strong>: Uses a 2-cycle permutation
* permutation of <code>c.size()</code> and then returns the * shuffle to generate a random permutation of <code>c.size()</code> and
* elements whose indexes correspond to the elements of the * then returns the elements whose indexes correspond to the elements of
* generated permutation. This technique is described, and * the generated permutation.
* proven to generate random samples, * This technique is described, and proven to generate random samples,
* <a href=http://www.maths.abdn.ac.uk/~igc/tch/mx4002/notes/node83.html> * <a href="http://www.maths.abdn.ac.uk/~igc/tch/mx4002/notes/node83.html">
* here</a> * here</a>
*/ */
public Object[] nextSample(Collection c, int k) { public Object[] nextSample(Collection c, int k) {
@ -490,9 +486,9 @@ public class RandomDataImpl implements RandomData{
} }
Object[] objects = c.toArray(); Object[] objects = c.toArray();
int[] index = nextPermutation(len,k); int[] index = nextPermutation(len, k);
Object[] result = new Object[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]]; result[i] = objects[index[i]];
} }
return result; return result;
@ -501,19 +497,19 @@ public class RandomDataImpl implements RandomData{
//------------------------Private methods---------------------------------- //------------------------Private methods----------------------------------
/** /**
* Uses a 2-cycle permutation shuffle to randomly re-order the last * <strong>Algorithm Description</strong>: Uses a 2-cycle permutation
* end elements of list * shuffle to randomly re-order the last <code>end</code> elements of list.
* *
* @param list list to be shuffled * @param list list to be shuffled
* @end element past which shuffling begins * @end element past which shuffling begins
*/ */
private void shuffle(int[] list, int end) { private void shuffle(int[] list, int end) {
int target = 0; int target = 0;
for (int i = list.length-1 ; i >= end; i--) { for (int i = list.length - 1 ; i >= end; i--) {
if (i == 0) { if (i == 0) {
target = 0; target = 0;
} else { } else {
target = nextInt(0,i); target = nextInt(0, i);
} }
int temp = list[target]; int temp = list[target];
list[target] = list[i]; 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 * @param n the natural number to represent
* @return array with entries = elements of n * @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. * Test cases for the RandomData class.
* *
* @author Phil Steitz * @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 { public final class RandomDataTest extends TestCase {
@ -462,9 +462,9 @@ public final class RandomDataTest extends TestCase {
assertTrue("same seeds", assertTrue("same seeds",
!hex.equals(randomData.nextSecureHexString(40))); !hex.equals(randomData.nextSecureHexString(40)));
/* TODO: probably should remove this test as the package grows, /* remove this test back soon,
* since it takes about 4 seconds * since it takes about 4 seconds */
*/
randomData.setSecureAlgorithm("SHA1PRNG","SUN"); randomData.setSecureAlgorithm("SHA1PRNG","SUN");
assertTrue("different seeds", assertTrue("different seeds",
!hex.equals(randomData.nextSecureHexString(40))); !hex.equals(randomData.nextSecureHexString(40)));
@ -480,7 +480,21 @@ public final class RandomDataTest extends TestCase {
fail("expecting NoSuchProviderException"); fail("expecting NoSuchProviderException");
} catch (NoSuchProviderException ex) { } 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 */ /** tests for nextSample() sampling from Collection */