/* * @(#) src/net/sf/ivmaidns/util/PseudoRandom.java -- * Class for pseudo-random generator. ** * Copyright (c) 2000 Ivan Maidanski <ivmai@mail.ru> * All rights reserved. */ /* * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. ** * This software is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License (GPL) for more details. ** * Linking this library statically or dynamically with other modules is * making a combined work based on this library. Thus, the terms and * conditions of the GNU General Public License cover the whole * combination. ** * As a special exception, the copyright holders of this library give you * permission to link this library with independent modules to produce an * executable, regardless of the license terms of these independent * modules, and to copy and distribute the resulting executable under * terms of your choice, provided that you also meet, for each linked * independent module, the terms and conditions of the license of that * module. An independent module is a module which is not derived from * or based on this library. If you modify this library, you may extend * this exception to your version of the library, but you are not * obligated to do so. If you do not wish to do so, delete this * exception statement from your version. */ package net.sf.ivmaidns.util; import java.io.Serializable; /** * Class for pseudo-random generator. ** * An instance of this class is used to generate a stream of * pseudo-random numbers. The class uses a 64-bit mutable seed, * which contains 61-bit and 3-bit shift registers (which stand for * <CODE>((x pow 61) + (x pow 3) + 1)</CODE> and * <CODE>((y pow 3) + y + 1)</CODE> factory polynomes). Each single * generated pseudo-random bit is <CODE>((x ^ y) & 1)</CODE>, where * new <VAR>x</VAR> is set to * <CODE>(x * 2 | ((x >> 60) ^ (x >> 2)) & 1)</CODE> and new * <VAR>y</VAR> is set to <CODE>(y * 2 | ((y >> 2) ^ y) & 1)</CODE>, * which are the current non-zero values of the 61-bit and 3-bit * shift registers, respectively. Such construction of these two * shift registers guarantees good (but not cryptographically * strong) uniformly distributed pseudo-random bits sequence with * the aperiodity length of * <CODE>(((2 pow 61) - 1) * ((2 pow 3) - 1))</CODE>. Of course, the * actual algorithm is supplied with the fixes for zero values of * these shift registers (if <VAR>x</VAR> is zero then a non-zero * constant is added to <CODE>this</CODE> <VAR>seed</VAR>, if * <VAR>y</VAR> is zero then it is filled with the first non-zero * bits of <VAR>x</VAR>). The algorithm of this generator is * entirely implemented in <CODE>nextInt(int)</CODE> core method, * the others use it indirectly. The class also contains a method * for generation of normally distributed ('Gaussian') pseudo-random * numbers. ** * @see UnsignedInt * @see UnsignedLong * @see JavaConsts ** * @version 2.0 * @author Ivan Maidanski */ public class PseudoRandom implements ReallyCloneable, Serializable { /** * The class version unique identifier for serialization * interoperability. ** * @since 1.1 */ private static final long serialVersionUID = -1655238629402664209L; /** * Size of the first 'shift' register in <VAR>seed</VAR> * (<CODE>61</CODE>). ** * @see #GEN_B_SIZE * @see #seed * @see #nextInt(int) ** * @since 1.1 */ protected static final int GEN_A_SIZE = 61; /** * Size of the second 'shift' register in the lowest part of * <VAR>seed</VAR> (<CODE>3</CODE>). ** * @see #GEN_A_SIZE * @see #seed * @see #nextInt(int) ** * @since 1.1 */ protected static final int GEN_B_SIZE = 3; /** * The internal state associated with <CODE>this</CODE> * pseudo-random number generator. ** * <VAR>seed</VAR> (which consists of two shift registers) is * initially set by the constructor and modified each time * <CODE>this</CODE> generator produces a new value. <VAR>seed</VAR> * may be of any value, which may be modified asynchronously (since * the algorithm includes the checks for zero values of any or both * shift registers). ** * @serial ** * @see PseudoRandom#PseudoRandom(long) * @see #clone() * @see #nextInt(int) * @see #toString() */ protected long seed; /** * Creates a new pseudo-random generator with the predefined initial * state. ** * Initial state (<VAR>seed</VAR>) of generator is fully (but not * trivially) determined by <VAR>initializer</VAR>. Later, this * state is altered only by every (direct or indirect) call of * <CODE>nextInt(int)</CODE>. Important notes: if two instances of * this class are created with the same value of * <VAR>initializer</VAR>, and the same sequence of method calls is * made for each, they will generate and return identical sequences * of numbers (and these instances will be equal); on the other * hand, if output reproducibility of a pseudo-random generator is * not required then it may be initialized on the current time. ** * @param initializer * the long value which fully determines the output pseudo-random * bits sequence of the created generator. ** * @see #nextInt(int) * @see #clone() * @see #equals(java.lang.Object) * @see #toString() */ public PseudoRandom(long initializer) { initializer = (initializer ^ 0x5DEECE66DL) * JavaConsts.LONG_GOLD_MEDIAN; initializer = (initializer >>> (GEN_A_SIZE - 1)) ^ (initializer << (GEN_B_SIZE + 1)); if (GEN_A_SIZE + GEN_B_SIZE < JavaConsts.LONG_SIZE) initializer &= ~(-1L << (GEN_A_SIZE + GEN_B_SIZE)); this.seed = initializer; } /** * Generates and returns the next uniformly distributed unsigned * <CODE>int</CODE> pseudo-random number according to the specified * maximum. ** * Returned value is drawn from the bits sequence of * <CODE>this</CODE> random number generator. The unsigned result is * uniformly distributed in the range from <CODE>0</CODE> to * <VAR>unsignedMax</VAR>, inclusive. All <VAR>unsignedMax</VAR> * plus one possible <CODE>int</CODE> values are produced with * (approximately) equal probability. The hedge 'approximately' is * used in the foregoing description only because the method is only * approximately an unbiased source of independently chosen bits. * This is a core method of the generator. This method alters state * of <CODE>this</CODE> generator. Important notes: synchronization * is not needed even outside (unless two or more threads use the * same pseudo-random generator constructed with some specified * initializer), since <VAR>seed</VAR> may be modified in an * asynchronous (even non-atomary) way by multiple threads; this * method may be overridden in the subclasses. ** * @param unsignedMax * the unsigned maximum on the random number to be returned. * @return * a pseudo-random, uniformly distributed unsigned <CODE>int</CODE> * value between <CODE>0</CODE> and <VAR>unsignedMax</VAR> * (inclusive). ** * @see #nextBits(int) * @see #nextLong(long) * @see #nextBytes(byte[], int, int) * @see #nextName(int) * @see #nextFloat() */ public int nextInt(int unsignedMax) { if (unsignedMax != 0) { int value; long seed; if (((seed = this.seed) & (GEN_A_SIZE + GEN_B_SIZE < JavaConsts.LONG_SIZE ? ~(-1L << GEN_A_SIZE) << GEN_B_SIZE : -1 << GEN_B_SIZE)) == 0L) seed += JavaConsts.LONG_GOLD_MEDIAN; if (((int)seed & ~(-1 << GEN_B_SIZE)) == 0) { long high = seed; do { high >>>= GEN_B_SIZE; } while ((value = (int)high & ~(-1 << GEN_B_SIZE)) == 0); seed |= value; } int max = unsignedMax; do { int result = 0; unsignedMax = max; do { value = (int)seed & ~(1 << GEN_B_SIZE); value ^= (value >> (GEN_B_SIZE - 1)) ^ (value << 1); if (GEN_A_SIZE + GEN_B_SIZE < JavaConsts.LONG_SIZE ? (seed & (1L << (GEN_A_SIZE + GEN_B_SIZE - 1))) != 0L : seed < 0L) value ^= 1 << GEN_B_SIZE; seed = (value & ((1 << GEN_B_SIZE) | 1)) ^ (seed << 1); result = ((value >> GEN_B_SIZE) ^ value) & 1 | (result << 1); } while ((unsignedMax >>>= 1) != 0); unsignedMax = result; } while (((~max | unsignedMax) & (max - unsignedMax)) < 0); if (GEN_A_SIZE + GEN_B_SIZE < JavaConsts.LONG_SIZE) seed &= ~(-1L << (GEN_A_SIZE + GEN_B_SIZE)); this.seed = seed; } return unsignedMax; } /** * Generates and returns the next uniformly distributed unsigned * <CODE>long</CODE> pseudo-random number according to the specified * maximum. ** * This method uses only <CODE>nextInt(int)</CODE> core method. The * unsigned result is uniformly distributed in the range from * <CODE>0</CODE> to <VAR>unsignedMax</VAR>, inclusive. All * <VAR>unsignedMax</VAR> plus one possible <CODE>long</CODE> values * are produced with (approximately) equal probability. In fact, * this is a secondary 'core' method. ** * @param unsignedMax * the unsigned maximum on the random number to be returned. * @return * a pseudo-random, uniformly distributed unsigned <CODE>long</CODE> * value between <CODE>0</CODE> and <VAR>unsignedMax</VAR> * (inclusive). ** * @see #nextInt(int) * @see #nextDouble() * @see #nextGaussian() */ public long nextLong(long unsignedMax) { int count, size = 0; long value = unsignedMax; while ((value & ~JavaConsts.INT_LMASK) != 0L) { value >>>= JavaConsts.INT_SIZE; size += JavaConsts.INT_SIZE; } if ((count = (int)value) != 0) for (size += JavaConsts.INT_SIZE; count > 0; count <<= 1, size--); do { value = 0L; count = size; while ((count -= JavaConsts.INT_SIZE) >= 0) value = nextInt(-1) & JavaConsts.INT_LMASK | (value << JavaConsts.INT_SIZE); if ((count += JavaConsts.INT_SIZE) > 0) value = nextInt(~(-1 << count)) | (value << count); } while (((~unsignedMax | value) & (unsignedMax - value)) < 0L); return value; } /** * Generates and returns the next pseudo-random bits sequence packed * into <CODE>int</CODE> value. ** * The resulting sequence is in lowest <VAR>count</VAR> bits of the * returned value (top bits are set to zero). Each bit of the * sequence may be <CODE>0</CODE> or <CODE>1</CODE> with the equal * probability. Negative <VAR>count</VAR> is treated as zero. If the * sequence is too long (to fit <CODE>int</CODE> value) then it is * truncated. This method uses only <CODE>nextInt(int)</CODE> * method. ** * @param count * the count of bits to be generated. * @return * a packed sequence of pseudo-random bits. ** * @see #nextInt(int) * @see #nextLongBits(int) * @see #nextBytes(byte[], int, int) ** * @since 1.1 */ public final int nextBits(int count) { int bits = 0; if (count > 0) { bits = -1; if (count < JavaConsts.INT_SIZE) bits = ~(-1 << count); bits = nextInt(bits); } return bits; } /** * Generates and returns the next pseudo-random bits sequence packed * into <CODE>long</CODE> value. ** * The resulting sequence is in lowest <VAR>count</VAR> bits of the * returned value (top bits are set to zero). Each bit of the * sequence may be <CODE>0</CODE> or <CODE>1</CODE> with the equal * probability. Negative <VAR>count</VAR> is treated as zero. If the * sequence is too long (to fit <CODE>long</CODE> value) then it is * truncated. This method uses only <CODE>nextLong(long)</CODE> * method. ** * @param count * the count of bits to be generated. * @return * a packed sequence of pseudo-random bits. ** * @see #nextLong(long) * @see #nextBits(int) * @see #nextBytes(byte[], int, int) ** * @since 1.1 */ public final long nextLongBits(int count) { long bits = 0L; if (count > 0) { bits = -1L; if (count < JavaConsts.LONG_SIZE) bits = ~(-1L << count); bits = nextLong(bits); } return bits; } /** * Generates pseudo-random bytes and places them into the supplied * <CODE>byte</CODE> array at the specified offset. ** * Each byte is uniformly distributed in all its range. Negative * <VAR>len</VAR> is treated as zero. If an exception is thrown then * generator state and <VAR>bytes</VAR> content remain unchanged. * This method uses only <CODE>nextInt(int)</CODE> core method. ** * @param bytes * the byte array (must be non-<CODE>null</CODE> and of enough * length) in which to put the generated pseudo-random bytes. * @param offset * the offset (in the supplied byte array) at which to put the * generated pseudo-random bytes. * @param len * the amount of pseudo-random bytes to generate. * @exception NullPointerException * if <VAR>bytes</VAR> is <CODE>null</CODE>. * @exception ArrayIndexOutOfBoundsException * if <VAR>len</VAR> is positive and (<VAR>offset</VAR> is negative * or is greater than <CODE>length</CODE> of <VAR>bytes</VAR> minus * <VAR>len</VAR>). ** * @see #nextInt(int) * @see #nextBits(int) * @see #nextLongBits(int) * @see #nextName(int) */ public void nextBytes(byte[] bytes, int offset, int len) throws NullPointerException, ArrayIndexOutOfBoundsException { int value = bytes.length; if (len > 0) { value = bytes[offset] | bytes[offset + len - 1]; do { bytes[offset++] = (byte)nextInt(JavaConsts.BYTE_MASK); } while (--len > 0); } } /** * Generates and returns the next pseudo-random (file) name. ** * This method is useful for generation of random names for * temporary files. The resulting string contains only uniformly * distributed characters from the set of '0' through '9' and 'a' * through 'z'. Negative <VAR>len</VAR> is treated as zero. If an * exception is thrown then generator state remains unchanged. This * method uses only <CODE>nextInt(int)</CODE> core method. ** * @param len * the amount of characters to generate. * @return * a string (not <CODE>null</CODE>, with <CODE>length()</CODE> of * <CODE>max(len, 0)</CODE>), which is just created and contains * only the pseudo-random characters from the set denoted above. * @exception OutOfMemoryError * if there is not enough memory. ** * @see #nextInt(int) * @see #nextBytes(byte[], int, int) ** * @since 2.0 */ public String nextName(int len) { if (len <= 0) len = 0; char[] chars = new char[len]; for (int value; len > 0; chars[--len] = (char)value) if ((value = nextInt(('9' - '0' + 1) + ('z' - 'a')) + '0') > '9') value += 'a' - '9' - 1; return new String(chars); } /** * Generates and returns the next uniformly distributed * <CODE>float</CODE> pseudo-random number in the range from * <CODE>0</CODE> (inclusive) to <CODE>1</CODE> (exclusive). ** * All possible floating-point values from the denoted range are * produced with (approximately) equal probability. This method uses * only <CODE>nextInt(int)</CODE> core method (to fill up the * mantissa of the floating-point value). ** * @return * a pseudo-random, uniformly distributed <CODE>float</CODE> value * between <CODE>0</CODE> (inclusive) and <CODE>1</CODE> * (exclusive). ** * @see #nextInt(int) * @see #nextDouble() * @see #nextGaussian() */ public final float nextFloat() { return (float)nextInt(JavaConsts.FLOAT_M_MASK) / (JavaConsts.FLOAT_M_MASK + 1); } /** * Generates and returns the next uniformly distributed * <CODE>double</CODE> pseudo-random number in the range from * <CODE>0</CODE> (inclusive) to <CODE>1</CODE> (exclusive). ** * All possible floating-point values from the denoted range are * produced with (approximately) equal probability. This method uses * only <CODE>nextLong(long)</CODE> method (to fill up the mantissa * of the floating-point value). ** * @return * a pseudo-random, uniformly distributed <CODE>double</CODE> value * between <CODE>0</CODE> (inclusive) and <CODE>1</CODE> * (exclusive). ** * @see #nextLong(long) * @see #nextFloat() * @see #nextGaussian() */ public final double nextDouble() { return (double)nextLong(JavaConsts.DOUBLE_M_MASK) / (JavaConsts.DOUBLE_M_MASK + 1L); } /** * Generates and returns the next normally distributed * <CODE>double</CODE> pseudo-random number. ** * Here, so called 'Polar Algorithm' is used to produce normally * distributed ('Gaussian') pseudo-random numbers with the standard * mean and deviation (mean <CODE>0</CODE> and deviation * <CODE>1</CODE>). The method uses only <CODE>nextLong(long)</CODE> * method (to fill up the mantissa of the floating-point values), * and <CODE>log(double)</CODE>, <CODE>sqrt(double)</CODE> functions * of <CODE>Math</CODE> class (to compute 'Gaussian' numbers). * Important notes: most of all the produced Gaussian numbers are in * the range from <CODE>-6</CODE> to <CODE>6</CODE>. ** * @return * a pseudo-random, normally distributed <CODE>double</CODE> value * with mean <CODE>0</CODE> and deviation <CODE>1</CODE>. ** * @see #nextDouble() * @see #nextLong(long) */ public double nextGaussian() { double s, v, w; do { v = (double)nextLong(JavaConsts.DOUBLE_M_MASK) / ((JavaConsts.DOUBLE_M_MASK >>> 1) + 1L) - 1.0D; w = (double)nextLong(JavaConsts.DOUBLE_M_MASK) / ((JavaConsts.DOUBLE_M_MASK >>> 1) + 1L) - 1.0D; } while ((s = v * v + w * w) <= 0.0D || s >= 1.0D); s = Math.sqrt(-2.0D * Math.log(s) / s); return v * s; // (w * s) may be used as another independent result } /** * Creates and returns a copy of <CODE>this</CODE> object. ** * This method creates a new instance of the class of this object * and initializes its <VAR>seed</VAR> value with the same as * <VAR>seed</VAR> value of <CODE>this</CODE> object. ** * @return * a copy (not <CODE>null</CODE> and != <CODE>this</CODE>) of * <CODE>this</CODE> instance. * @exception OutOfMemoryError * if there is not enough memory. ** * @see PseudoRandom#PseudoRandom(long) * @see #equals(java.lang.Object) */ public Object clone() { Object obj; try { if ((obj = super.clone()) instanceof PseudoRandom && obj != this) return obj; } catch (CloneNotSupportedException e) {} throw new InternalError("CloneNotSupportedException"); } /** * Returns a hash code value for the object. ** * This method returns <VAR>seed</VAR> value 'squeezed' (hashed) to * value of <CODE>int</CODE> type. ** * @return * a hash code value for <CODE>this</CODE> object. ** * @see #equals(java.lang.Object) */ public int hashCode() { long seed = this.seed; return (int)((seed >> (JavaConsts.INT_SIZE - 1)) >> 1) ^ (int)seed; } /** * Indicates whether <CODE>this</CODE> object is equal to the * specified one. ** * This method returns <CODE>true</CODE> if and only if * <VAR>obj</VAR> is instance of this class and its <VAR>seed</VAR> * value is the same as <VAR>seed</VAR> value of <CODE>this</CODE> * object. ** * @param obj * the object (may be <CODE>null</CODE>) with which to compare. * @return * <CODE>true</CODE> if and only if <CODE>this</CODE> value is the * same as <VAR>obj</VAR> value. ** * @see PseudoRandom#PseudoRandom(long) * @see #clone() * @see #hashCode() */ public boolean equals(Object obj) { return obj == this || obj instanceof PseudoRandom && ((PseudoRandom)obj).seed == this.seed; } /** * Returns the string representation of the object. ** * This method returns the hexadecimal (with '0x' prefix) * zero-padded representation of <VAR>seed</VAR>. ** * @return * the string representation (not <CODE>null</CODE>, with non-zero * <CODE>length()</CODE>) of <CODE>this</CODE> object. * @exception OutOfMemoryError * if there is not enough memory. */ public String toString() { int digit, offset; long seed = this.seed; if (GEN_A_SIZE + GEN_B_SIZE < JavaConsts.LONG_SIZE) seed &= ~(-1L << (GEN_A_SIZE + GEN_B_SIZE)); char[] chars = new char[offset = ((GEN_A_SIZE + GEN_B_SIZE - 1) >> 2) + 3]; do { if ((digit = (int)seed & ((1 << 4) - 1)) > '9' - '0') digit += 'A' - '9' - 1; chars[--offset] = (char)(digit + '0'); seed >>>= 4; } while (offset > 2); chars[1] = 'x'; chars[0] = '0'; return new String(chars); } }