How many times can I use randomGenerator.nextDoubl

2019-04-07 06:33发布

问题:

I'm using the Random class in Java as a pseudo-random number generator. I'm using the function nextDouble a lot of times (~10^5). How many times before I have to reseed to prevent from getting the same numbers? Is reseeding needed?

    Random generator = new Random();
    double[] numbers = new double[n];
    for (int i = 0; i < n; i++) numbers[i] = generator.nextDouble();

This is for an experiment, the numbers will be used as coordinates for points on a space, so I want the distribution to be as uniform as possible.

Also how do I reseed? Where do I get the int seed from?

回答1:

The random number generator will produce a random double from two random int values. The internal seed has 48 bit, so the random sequence repeats after at most 2^48 int values, or 2^47 double values.



回答2:

You don't need to worry about reseeding etc if you use a Set (which guarantees unique values):

Random generator = new Random();
Set<Double> numbers = new HashSet<Double>();
while (numbers.size() < n)
    numbers.add(generator.nextDouble());

Despite what you might think, this executes quite quickly: 60 milliseconds for 100000 numbers on a my (typical) PC.

If you really want an array, you can extract it from the set.
If you want to maintain the order they were generated in, use a LinkedHashSet (it had similar performance)



回答3:

I am sorry I can't directly answer your question. I don't remember the cycle time of Java's random number generator. Though I do think you are cutting it close with the amount of numbers you are generating.

But, what I learned in my computer engineering statistic classes might be able to help you.

I learned that the best method for generating the most random numbers is using the Mersenne Twister random number generator. This generator will provide you with enough random numbers to not need to reseed, it has a period of (2^19937) − 1

Here is source code for MerseeneTwister

https://java2s.com/Open-Source/Java/Natural-Language-Processing/MorphAdorner/edu/northwestern/at/utils/math/randomnumbers/MersenneTwister.java.htm

Here is a class to generate your random numbers.

class RandomVariable {

/** Initialize Mersenne Twister generator. */
private static MersenneTwister rnd = new MersenneTwister();

public static double rand() {
    return rnd.nextDouble();
}

/** Generate a random number from a uniform random variable.
 *
 *  @param  min Mininum value for the random variable.
 *  @param  max Maximum value for the random variable.
 *
 *  @return     A random double between min and max.
 */
public static double uniform(double min, double max) {
    return min + (max - min) * rand();
}
}

Here is a sample to generate a random number. Please note that I removed the comments from the source. This may voliate the open source nature of the code, but I couldnt copy it all and have it formated as code.

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class sample{
public static void main(String args[]){
    RandomVariable gen = new RandomVariable();
    double num = gen.uniform(-1,1);

    int n = 10000;
    Set<Double> nums = new HashSet<Double>();
    while (numbers.size() < n)
        nums.add(gen.uniform(-1,1));

}
}
class RandomVariable {

/** Initialize Mersenne Twister generator. */
private static MersenneTwister rnd = new MersenneTwister();

public static double rand() {
    return rnd.nextDouble();
}

/** Generate a random number from a uniform random variable.
 *
 *  @param  min Mininum value for the random variable.
 *  @param  max Maximum value for the random variable.
 *
 *  @return     A random double between min and max.
 */
public static double uniform(double min, double max) {
    return min + (max - min) * rand();
}
}

class MersenneTwister extends java.util.Random implements Serializable {
// Period parameters

private static final int N = 624;
private static final int M = 397;
private static final int MATRIX_A = 0x9908b0df;   // private static final 
//* constant vector a
private static final int UPPER_MASK = 0x80000000; // most significant 
//   w-r bits
private static final int LOWER_MASK = 0x7fffffff; // least significant 
//  r bits
// Tempering parameters
private static final int TEMPERING_MASK_B = 0x9d2c5680;
private static final int TEMPERING_MASK_C = 0xefc60000;
private int mt[]; // the array for the state vector
private int mti; // mti==N+1 means mt[N] is not initialized
private int mag01[];
// a good initial seed (of int size, though stored in a long)
// private static final long GOOD_SEED = 4357;

/* implemented here because there's a bug in Random's implementation
of the Gaussian code (divide by zero, and log(0), ugh!), yet its
gaussian variables are private so we can't access them here.  :-( */
private double __nextNextGaussian;
private boolean __haveNextNextGaussian;

/**
 * Constructor using the default seed.
 */
public MersenneTwister() {
    this(System.currentTimeMillis());
}

/**
 * Constructor using a given seed.  Though you pass this seed in
 * as a long, it's best to make sure it's actually an integer.
 */
public MersenneTwister(final long seed) {
    super(seed);    /* just in case */
    setSeed(seed);
}

/**
 * Constructor using an array.
 */
public MersenneTwister(final int[] array) {
    super(System.currentTimeMillis());
    /* pick something at random just in case */
    setSeed(array);
}

/**
 * Initalize the pseudo random number generator.  Don't
 * pass in a long that's bigger than an int (Mersenne Twister
 * only uses the first 32 bits for its seed).
 */
synchronized public void setSeed(final long seed) {
    // it's always good style to call super
    super.setSeed(seed);

    // Due to a bug in java.util.Random clear up to 1.2, we're
    // doing our own Gaussian variable.
    __haveNextNextGaussian = false;

    mt = new int[N];

    mag01 = new int[2];
    mag01[0] = 0x0;
    mag01[1] = MATRIX_A;

    mt[0] = (int) (seed & 0xfffffff);
    for (mti = 1; mti < N; mti++) {
        mt[mti] =
                (1812433253 * (mt[mti - 1] ^ (mt[mti - 1] >>> 30)) + mti);

        /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */

        /* In the previous versions, MSBs of the seed affect   */

        /* only MSBs of the array mt[].                        */

        /* 2002/01/09 modified by Makoto Matsumoto             */
        mt[mti] &= 0xffffffff;

        /* for >32 bit machines */
    }
}

/**
 * An alternative, more complete, method of seeding the
 * pseudo random number generator.  array must be an
 * array of 624 ints, and they can be any value as long as
 * they're not *all* zero.
 */
synchronized public void setSeed(final int[] array) {
    int i, j, k;

    setSeed(19650218);
    i = 1;
    j = 0;
    k = (N > array.length ? N : array.length);
    for (; k != 0; k--) {
        mt[i] = (mt[i] ^ ((mt[i - 1] ^ (mt[i - 1] >>> 30)) * 1664525))
                + array[j] + j; /* non linear */
        mt[i] &= 0xffffffff; /* for WORDSIZE > 32 machines */
        i++;
        j++;
        if (i >= N) {
            mt[0] = mt[N - 1];
            i = 1;
        }
        if (j >= array.length) {
            j = 0;
        }
    }
    for (k = N - 1; k != 0; k--) {
        mt[i] = (mt[i] ^ ((mt[i - 1] ^ (mt[i - 1] >>> 30)) * 1566083941))
                - i; /* non linear */
        mt[i] &= 0xffffffff; /* for WORDSIZE > 32 machines */
        i++;
        if (i >= N) {
            mt[0] = mt[N - 1];
            i = 1;
        }
    }
    mt[0] = 0x80000000; /* MSB is 1; assuring non-zero initial array */
}

/**
 * Returns an integer with <em>bits</em> bits filled with a random number.
 */
synchronized protected int next(final int bits) {
    int y;

    if (mti >= N) // generate N words at one time
    {
        int kk;
        final int[] mt = this.mt; // locals are slightly faster
        final int[] mag01 = this.mag01; // locals are slightly faster

        for (kk = 0; kk < N - M; kk++) {
            y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK);
            mt[kk] = mt[kk + M] ^ (y >>> 1) ^ mag01[y & 0x1];
        }
        for (; kk < N - 1; kk++) {
            y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK);
            mt[kk] = mt[kk + (M - N)] ^ (y >>> 1) ^ mag01[y & 0x1];
        }
        y = (mt[N - 1] & UPPER_MASK) | (mt[0] & LOWER_MASK);
        mt[N - 1] = mt[M - 1] ^ (y >>> 1) ^ mag01[y & 0x1];

        mti = 0;
    }

    y = mt[mti++];
    y ^= y >>> 11;                          // TEMPERING_SHIFT_U(y)
    y ^= (y << 7) & TEMPERING_MASK_B;       // TEMPERING_SHIFT_S(y)
    y ^= (y << 15) & TEMPERING_MASK_C;      // TEMPERING_SHIFT_T(y)
    y ^= (y >>> 18);                        // TEMPERING_SHIFT_L(y)

    return y >>> (32 - bits);    // hope that's right!
}

/* If you've got a truly old version of Java, you can omit these
two next methods. */
private synchronized void writeObject(final ObjectOutputStream out)
        throws IOException {
    // just so we're synchronized.
    out.defaultWriteObject();
}

private synchronized void readObject(final ObjectInputStream in)
        throws IOException, ClassNotFoundException {
    // just so we're synchronized.
    in.defaultReadObject();
}

/** This method is missing from jdk 1.0.x and below.  JDK 1.1
includes this for us, but what the heck.*/
public boolean nextBoolean() {
    return next(1) != 0;
}

/** This generates a coin flip with a probability <tt>probability</tt>
of returning true, else returning false. <tt>probability</tt> must
be between 0.0 and 1.0, inclusive.  Not as precise a random real
event as nextBoolean(double), but twice as fast. To explicitly
use this, remember you may need to cast to float first. */
public boolean nextBoolean(final float probability) {
    if (probability < 0.0f || probability > 1.0f) {
        throw new IllegalArgumentException("probability must be between 0.0"
                + " and 1.0 inclusive.");
    }
    if (probability == 0.0f) {
        return false;            // fix half-open issues
    } else if (probability == 1.0f) {
        return true;        // fix half-open issues
    }
    return nextFloat() < probability;
}

/** This generates a coin flip with a probability <tt>probability</tt>
of returning true, else returning false. <tt>probability</tt> must
be between 0.0 and 1.0, inclusive. */
public boolean nextBoolean(final double probability) {
    if (probability < 0.0 || probability > 1.0) {
        throw new IllegalArgumentException("probability must be between 0.0"
                + " and 1.0 inclusive.");
    }
    if (probability == 0.0) {
        return false;             // fix half-open issues
    } else if (probability == 1.0) {
        return true; // fix half-open issues
    }
    return nextDouble() < probability;
}

/** This method is missing from JDK 1.1 and below.  JDK 1.2
includes this for us, but what the heck. */
public int nextInt(final int n) {
    if (n <= 0) {
        throw new IllegalArgumentException("n must be >= 0");
    }

    if ((n & -n) == n) {
        return (int) ((n * (long) next(31)) >> 31);
    }

    int bits, val;

    do {
        bits = next(31);
        val = bits % n;
    } while (bits - val + (n - 1) < 0);
    return val;
}

/** This method is for completness' sake.
Returns a long drawn uniformly from 0 to n-1.  Suffice it to say,
n must be > 0, or an IllegalArgumentException is raised. */
public long nextLong(final long n) {
    if (n <= 0) {
        throw new IllegalArgumentException("n must be >= 0");
    }

    long bits, val;

    do {
        bits = (nextLong() >>> 1);
        val = bits % n;
    } while (bits - val + (n - 1) < 0);
    return val;
}

/** A bug fix for versions of JDK 1.1 and below.  JDK 1.2 fixes
this for us, but what the heck. */
public double nextDouble() {
    return (((long) next(26) << 27) + next(27))
            / (double) (1L << 53);
}

/** A bug fix for versions of JDK 1.1 and below.  JDK 1.2 fixes
this for us, but what the heck. */
public float nextFloat() {
    return next(24) / ((float) (1 << 24));
}

/** A bug fix for all versions of the JDK.  The JDK appears to
use all four bytes in an integer as independent byte values!
Totally wrong. I've submitted a bug report. */
public void nextBytes(final byte[] bytes) {
    for (int x = 0; x < bytes.length; x++) {
        bytes[x] = (byte) next(8);
    }
}

/** For completeness' sake, though it's not in java.util.Random.  */
public char nextChar() {
    // chars are 16-bit UniCode values
    return (char) (next(16));
}

/** For completeness' sake, though it's not in java.util.Random. */
public short nextShort() {
    return (short) (next(16));
}

/** For completeness' sake, though it's not in java.util.Random.  */
public byte nextByte() {
    return (byte) (next(8));
}

/** A bug fix for all JDK code including 1.2.  nextGaussian can theoretical
 * ly
ask for the log of 0 and divide it by 0! See Java bug
<a href="http://developer.java.sun.com/developer/bugParade/bugs/4254501.h
 * tml">
http://developer.java.sun.com/developer/bugParade/bugs/4254501.html</a>
 */
synchronized public double nextGaussian() {
    if (__haveNextNextGaussian) {
        __haveNextNextGaussian = false;
        return __nextNextGaussian;
    } else {
        double v1, v2, s;

        do {
            v1 = 2 * nextDouble() - 1; // between -1.0 and 1.0
            v2 = 2 * nextDouble() - 1; // between -1.0 and 1.0
            s = v1 * v1 + v2 * v2;
        } while (s >= 1 || s == 0);
        double multiplier = /* Strict*/ Math.sqrt(-2
                * /* Strict*/ Math.log(s) / s);

        __nextNextGaussian = v2 * multiplier;
        __haveNextNextGaussian = true;
        return v1 * multiplier;
    }
}
}


标签: java random