diff --git a/src/java/org/apache/commons/math/RandomData.java b/src/java/org/apache/commons/math/RandomData.java
index 7b93df866..938e64a23 100644
--- a/src/java/org/apache/commons/math/RandomData.java
+++ b/src/java/org/apache/commons/math/RandomData.java
@@ -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
- * len
.
+ * len
.
+ *
* The generated string will be random, but not cryptographically
* secure. To generate cryptographically secure strings, use
* nextSecureHexString
+ *
+ * Preconditions:
len > 0
(otherwise an IllegalArgumentException
+ * is thrown.)len
is not positive.
+ * @return random string of hex characters of length len
*/
- public String nextHexString(int len);
+ String nextHexString(int len);
/**
* Generates a uniformly distributed random integer between
- * lower
and upper
(endpoints included).lower
and upper
(endpoints included).
+ *
* The generated integer will be random, but not cryptographically secure.
* To generate cryptographically secure integer sequences, use
* nextSecureInt
.
+ *
+ * Preconditions:
lower < upper
(otherwise an IllegalArgumentException
+ * is thrown.)lower
is not strictly less than upper
.
* @return a random integer greater than or equal to lower
* and less than or equal to upper
.
*/
- public int nextInt(int lower, int upper);
+ int nextInt(int lower, int upper);
/**
- * Generates a uniformly distributed random long integer between <
- * code>lower and upper
(endpoints included).
+ * Generates a uniformly distributed random long integer between
+ * lower
and upper
(endpoints included).
+ *
* The generated long integer values will be random, but not
- * cryptographically secure.
+ * cryptographically secure.
* To generate cryptographically secure sequences of longs, use
* nextSecureLong
+ *
+ * Preconditions:
lower < upper
(otherwise an IllegalArgumentException
+ * is thrown.)lower
* and less than or equal to upper
.
*/
- 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.
+ *
* If cryptographic security is not required,
* use nextHexString()
.
+ *
+ * Preconditions:
len > 0
(otherwise an IllegalArgumentException
+ * is thrown.)lower
and upper
(endpoints included)
- * from a secure random sequence.nextInt
- * should be used.
+ * Sequences of integers generated using this method will be
+ * cryptographically secure. If cryptographic security is not required,
+ * nextInt
should be used instead of this method.
+ *
+ * Definition: + * + * Secure Random Sequence + *
+ * Preconditions:
lower < upper
(otherwise an IllegalArgumentException
+ * is thrown.)lower
is not strictly less than upper
.
* @return a random integer greater than or equal to lower
* and less than or equal to upper
.
*/
- public int nextSecureInt(int lower, int upper);
+ int nextSecureInt(int lower, int upper);
/**
* Generates a random long integer between lower
- * and upper
(endpoints included).nextLong
upper
(endpoints included).
+ * Sequences of long values generated using this method will be
+ * cryptographically secure. If cryptographic security is not required,
+ * nextLong
should be used instead of this method.
+ *
* Definition: - * + * * Secure Random Sequence + *
+ * Preconditions:
lower < upper
(otherwise an IllegalArgumentException
+ * is thrown.)lower
is not strictly less than upper
.
* @return a long integer greater than or equal to lower
* and less than or equal to upper
.
*/
- 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.
* Definition:
- *
- * Poisson Distribution
+ *
+ * Poisson Distribution
+ *
* Preconditions:
* Definition:
- *
- * Normal Distribution
+ *
+ * Normal Distribution
+ *
* Preconditions:
sigma > 0
(otherwise an IllegalArgumentException
+ * is thrown.)mean
mean
.
+ *
* Definition:
- *
- * Exponential Distribution
+ *
+ * Exponential Distribution
+ *
* Preconditions:
mu >= 0
(otherwise an IllegalArgumentException
+ * is thrown.)lower
,upper
) (i.e., endpoints excluded)
+ * (lower
,upper
) (i.e., endpoints excluded).
+ *
* Definition:
- *
- * Uniform Distribution lower
and upper - lower
- * are the
- *
- * location and scale parameters, respectively
+ *
+ * Uniform Distribution lower
and
+ * upper - lower
are the
+ *
+ * location and scale parameters, respectively.
+ *
+ * Preconditions:
lower < upper
(otherwise an IllegalArgumentException
+ * is thrown.)lower
is not strictly less than upper
.
*/
- public double nextUniform(double lower, double upper);
+ double nextUniform(double lower, double upper);
/**
* Generates an integer array of length k
whose entries
- * are selected randomly, without repetition, from the integers
- * {0, ... , n-1} -- i.e., generated arrays represent permutations
- * of n
taken k
at a time.
- *
+ * are selected randomly, without repetition, from the integers
+ * 0 through n-1
(inclusive).
+ *
+ * Generated arrays represent permutations
+ * of n
taken k
at a time.
+ *
* Preconditions:
k <= n
n > 0
k
objects selected randomly
- * from the Collection c
. Sampling from c
+ * from the Collection c
.
+ *
+ * Sampling from c
* is without replacement; but if c
contains identical
* objects, the sample may include repeats. If all elements of
* c
are distinct, the resulting object array represents a
- *
+ *
* Simple Random Sample of size
- * k
from the elements of c
.
- *
+ * k
from the elements of c
.
+ *
* Preconditions:
RandomData
interface using
* java.util.Random
and
- * java.util.Random.SecureRandom
instances to generate data.
+ * java.util.Random.SecureRandom
instances to generate data.
+ *
* Supports reseeding the underlying
- * PRNG.
- * The SecurityProvider
and Algorithm
- * used by the SecureRandom
instance can also be reset.
+ *
+ * PRNG. The SecurityProvider
and Algorithm
+ * used by the SecureRandom
instance can also be reset.
+ *
* For details on the PRNGs, see the JDK documentation for
* java.util.Random
and
- * java.util.Random.SecureRandom
+ * java.util.Random.SecureRandom
+ *
* Usage Notes:
Random
and
+ * Random
and
* SecureRandom
instances used in data generation. Therefore,
* to generate a random sequence of values or strings, you should use just
* one RandomDataImpl
instance repeatedly.RandomDataImpl
is created, the underlying random
+ * RandomDataImpl
is created, the underlying random
* number generators are not intialized. The first call to a
* data generation method, or to a reSeed()
method instantiates
* the appropriate generator. If you do not explicitly seed the generator, it
* is by default seeded with the current time in millisecondsreSeed
and reSeedSecure
methods delegate to
- * the corresponding methods on the underlying Random
and
- * SecureRandom
instances. Therefore, the contracts of these methods
- * are as defined in the JDK documentation. In particular, reSeed(long)
- *
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 not
- * reinitialize the secure random number generator (so secure sequences
- * started with calls to reseedSecure(long) won't be identical).reSeed
and reSeedSecure
methods delegate
+ * to the corresponding methods on the underlying Random
and
+ * SecureRandom
instances. Therefore, the contracts of these
+ * methods are as defined in the JDK documentation. In particular,
+ * reSeed(long)
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 not reinitialize the secure random number generator
+ * (so secure sequences started with calls to reseedSecure(long) won't be
+ * identical).nextSecureHexString()
.nextHexString()
.- * TODO: find external reference or provide justification for the claim that this - * yields a cryptographically secure sequence of hex strings.
- * @param len length of return string - * @exception IllegalArgumentException thrown if len <= 0 - * @return the random hex string + * Algorithm Description: hex strings are generated in + * 40-byte segments using a 3-step process.SecureRandom
.
+ * 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.
- * Definition:
- *
- * Poisson Distribution
* Algorithm Description:
- * Uses simulation of a Poisson process using Uniform deviates, as described
- *
+ * Uses simulation of a Poisson process using Uniform deviates, as
+ * described
+ *
* here
- * @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 = mean
- * Definition:
- *
- * Exponential Distribution
- * Preconditions:
lower
,upper
) (i.e., endpoints excluded)
- * Definition:
- *
- * Uniform Distribution lower
and upper - lower
- * are the
- *
- * location and scale parameters, respectivelylower
is not strictly less than upper
.
+ * 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.
+ * 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.
+ * Returns the static SecureRandom used to generate secure random data.
+ *
* 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. + *
+ * 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. + *
+ * 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. + *
* 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 - * - * Java Cryptography Architecture API Specification & Reference
- * USAGE NOTE: This method carries significant overhead - * and may take several seconds to execute.
+ * + * Java Cryptography Architecture API Specification & Reference. + *
+ * USAGE NOTE: This method carries significant
+ * 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 c.size()
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,
- *
+ * Algorithm Description: Uses a 2-cycle permutation
+ * shuffle to generate a random permutation of c.size()
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,
+ *
* here
*/
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
+ * Algorithm Description: Uses a 2-cycle permutation
+ * shuffle to randomly re-order the last end
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
diff --git a/src/test/org/apache/commons/math/RandomDataTest.java b/src/test/org/apache/commons/math/RandomDataTest.java
index 3caa2a45d..161352de8 100644
--- a/src/test/org/apache/commons/math/RandomDataTest.java
+++ b/src/test/org/apache/commons/math/RandomDataTest.java
@@ -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 */