blob: 4a7da0615418fd9cbf5cb9a266acb0b88b6f94af [file] [log] [blame]
/*
* Copyright 2009 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*
* INCLUDES MODIFICATIONS BY RICHARD ZSCHECH AS WELL AS GOOGLE.
*/
package java.util;
import static javaemul.internal.InternalPreconditions.checkCriticalArgument;
import static javaemul.internal.InternalPreconditions.checkNotNull;
import javaemul.internal.JsUtils;
/**
* This class provides methods that generates pseudo-random numbers of different
* types, such as {@code int}, {@code long}, {@code double}, and {@code float}.
* It follows the algorithms specified in the JRE javadoc.
*
* This emulated version of Random is not serializable.
*/
public class Random {
private static final double multiplierHi = 0x5de;
private static final double multiplierLo = 0xece66d;
private static final double twoToThe24 = 16777216.0;
private static final double twoToThe31 = 2147483648.0;
private static final double twoToThe32 = 4294967296.0;
private static final double twoToTheMinus24 =
5.9604644775390625e-8;
private static final double twoToTheMinus26 =
1.490116119384765625e-8;
private static final double twoToTheMinus31 =
4.656612873077392578125e-10;
private static final double twoToTheMinus53 =
1.1102230246251565404236316680908203125e-16;
private static final double[] twoToTheXMinus24 = new double[25];
private static final double[] twoToTheXMinus48 = new double[33];
/**
* A value used to avoid two random number generators produced at the same
* time having the same seed.
*/
private static int uniqueSeed = 0;
// Initialize power-of-two tables
static {
double twoToTheXMinus48Tmp = 1.52587890625e-5; // 1.0 / (1 << (48 - 32));
for (int i = 32; i >= 0; i--) {
twoToTheXMinus48[i] = twoToTheXMinus48Tmp;
twoToTheXMinus48Tmp *= 0.5;
}
double twoToTheXMinus24Tmp = 1.0;
for (int i = 24; i >= 0; i--) {
twoToTheXMinus24[i] = twoToTheXMinus24Tmp;
twoToTheXMinus24Tmp *= 0.5;
}
}
/**
* The boolean value indicating if the second Gaussian number is available.
*/
private boolean haveNextNextGaussian = false;
/**
* The second Gaussian generated number.
*/
private double nextNextGaussian;
/**
* The high 24 bits of the 48=bit seed value.
*/
private double seedhi;
/**
* The low 24 bits of the 48=bit seed value.
*/
private double seedlo;
/**
* Construct a random generator with the current time of day in milliseconds
* plus a unique counter value as the initial state.
*
* @see #setSeed
*/
public Random() {
// JsDate.now used instead of System.currentTimeMillis()
// as it returns a double in order to avoid the use os LongLib.
double seed = uniqueSeed++ + JsUtils.getTime();
int hi = (int) Math.floor(seed * twoToTheMinus24) & 0xffffff;
int lo = (int) (seed - (hi * twoToThe24));
setSeed(hi, lo);
}
/**
* Construct a random generator with the given {@code seed} as the initial
* state.
*
* @param seed the seed that will determine the initial state of this random
* number generator.
* @see #setSeed
*/
public Random(long seed) {
setSeed(seed);
}
/**
* Returns the next pseudo-random, uniformly distributed {@code boolean} value
* generated by this generator.
*
* @return a pseudo-random, uniformly distributed boolean value.
*/
public boolean nextBoolean() {
return nextInternal(1) != 0;
}
/**
* Modifies the {@code byte} array by a random sequence of {@code byte}s
* generated by this random number generator.
*
* @param buf non-null array to contain the new random {@code byte}s.
* @see #next
*/
public void nextBytes(byte[] buf) {
checkNotNull(buf);
int rand = 0, count = 0, loop = 0;
while (count < buf.length) {
if (loop == 0) {
rand = (int) nextInternal(32);
loop = 3;
} else {
loop--;
}
buf[count++] = (byte) rand;
rand >>= 8;
}
}
/**
* Generates a normally distributed random {@code double} number between 0.0
* inclusively and 1.0 exclusively.
*
* @return a random {@code double} in the range [0.0 - 1.0)
* @see #nextFloat
*/
public double nextDouble() {
return nextInternal(26) * twoToTheMinus26 +
nextInternal(27) * twoToTheMinus53;
}
/**
* Generates a normally distributed random {@code float} number between 0.0
* inclusively and 1.0 exclusively.
*
* @return float a random {@code float} number between [0.0 and 1.0)
* @see #nextDouble
*/
public float nextFloat() {
return (float) (nextInternal(24) * twoToTheMinus24);
}
/**
* Pseudo-randomly generates (approximately) a normally distributed {@code
* double} value with mean 0.0 and a standard deviation value of {@code 1.0}
* using the <i>polar method<i> of G. E. P. Box, M. E. Muller, and G.
* Marsaglia, as described by Donald E. Knuth in <i>The Art of Computer
* Programming, Volume 2: Seminumerical Algorithms</i>, section 3.4.1,
* subsection C, algorithm P.
*
* @return a random {@code double}
* @see #nextDouble
*/
public synchronized double nextGaussian() {
if (haveNextNextGaussian) {
// if X1 has been returned, return the second Gaussian
haveNextNextGaussian = false;
return nextNextGaussian;
}
double v1, v2, s;
do {
// Generates two independent random variables U1, U2
v1 = 2 * nextDouble() - 1;
v2 = 2 * nextDouble() - 1;
s = v1 * v1 + v2 * v2;
} while (s >= 1);
// See errata for TAOCP vol. 2, 3rd ed. for proper handling of s == 0 case
// (page 5 of http://www-cs-faculty.stanford.edu/~uno/err2.ps.gz)
double norm = (s == 0) ? 0.0 : Math.sqrt(-2.0 * Math.log(s) / s);
nextNextGaussian = v2 * norm;
haveNextNextGaussian = true;
return v1 * norm;
}
/**
* Generates a uniformly distributed 32-bit {@code int} value from the random
* number sequence.
*
* @return a uniformly distributed {@code int} value.
* @see java.lang.Integer#MAX_VALUE
* @see java.lang.Integer#MIN_VALUE
* @see #next
* @see #nextLong
*/
public int nextInt() {
return (int) nextInternal(32);
}
/**
* Returns a new pseudo-random {@code int} value which is uniformly
* distributed between 0 (inclusively) and the value of {@code n}
* (exclusively).
*
* @param n the exclusive upper border of the range [0 - n).
* @return a random {@code int}.
*/
public int nextInt(int n) {
checkCriticalArgument(n > 0);
if ((n & -n) == n) {
return (int) ((n * nextInternal(31)) * twoToTheMinus31);
}
double bits, val;
do {
bits = nextInternal(31);
val = bits % n;
} while (bits - val + (n - 1) < 0);
return (int) val;
}
/**
* Generates a uniformly distributed 64-bit integer value from the random
* number sequence.
*
* @return 64-bit random integer.
* @see java.lang.Integer#MAX_VALUE
* @see java.lang.Integer#MIN_VALUE
* @see #next
* @see #nextInt()
* @see #nextInt(int)
*/
public long nextLong() {
return ((long) nextInternal(32) << 32) + (long) nextInternal(32);
}
/**
* Modifies the seed a using linear congruential formula presented in <i>The
* Art of Computer Programming, Volume 2</i>, Section 3.2.1.
*
* @param seed the seed that alters the state of the random number generator.
* @see #next
* @see #Random()
* @see #Random(long)
*/
public synchronized void setSeed(long seed) {
setSeed((int) ((seed >> 24) & 0xffffff), (int) (seed & 0xffffff));
}
/**
* Returns a pseudo-random uniformly distributed {@code int} value of the
* number of bits specified by the argument {@code bits} as described by
* Donald E. Knuth in <i>The Art of Computer Programming, Volume 2:
* Seminumerical Algorithms</i>, section 3.2.1.
*
* @param bits number of bits of the returned value.
* @return a pseudo-random generated int number.
* @see #nextBytes
* @see #nextDouble
* @see #nextFloat
* @see #nextInt()
* @see #nextInt(int)
* @see #nextGaussian
* @see #nextLong
*/
protected synchronized int next(int bits) {
return (int) nextInternal(bits);
}
private synchronized double nextInternal(int bits) {
double hi = seedhi * multiplierLo + seedlo * multiplierHi;
double lo = seedlo * multiplierLo + 0xb;
double carry = Math.floor(lo * twoToTheMinus24);
hi += carry;
lo -= carry * twoToThe24;
hi %= twoToThe24;
seedhi = hi;
seedlo = lo;
if (bits <= 24) {
// High bits of seedhi, shifted right
return Math.floor(seedhi * twoToTheXMinus24[bits]);
} else {
// All bits of seedhi, shifted left
double h = seedhi * (1 << (bits - 24));
// High bits of seedlo, shifted right
double l = Math.floor(seedlo * twoToTheXMinus48[bits]);
// Sum of high and low bits
double dval = h + l;
// Force sign based on bit 31
if (dval >= twoToThe31) {
dval -= twoToThe32;
}
return dval;
}
}
// seedhi and seedlo should be integers from 0 to 2^24 - 1
private synchronized void setSeed(int seedhi, int seedlo) {
this.seedhi = seedhi ^ 0x5de;
this.seedlo = seedlo ^ 0xece66d;
haveNextNextGaussian = false;
}
}