2012-04-18 1 views
7

난 Java에서 Random 클래스를 의사 난수 생성기로 사용하고 있습니다. nextDouble 함수를 많이 사용하고 있습니다 (~ 10^5). 동일한 번호를 얻지 못하게하기 위해 다시 채워야하는 횟수는 몇 번입니까? 다시 시드해야합니까?다시 시드해야하기 전에 randomGenerator.nextDouble()을 몇 번 사용할 수 있습니까?

이것은 실험을위한 것으로 숫자는 공백의 점에 대한 좌표로 사용되므로 가능한 한 균일하게 분포 시키길 원합니다.

어떻게 다시 시드합니까? 어디에서 int 시드를 얻을 수 있습니까?

+0

http://stackoverflow.com/questions/7291911/을 보셨습니까? –

+2

일반적으로 좋은 의사 난수 생성기는 반복하기 전에 나타내는 모든 정수 집합을 순환합니다. Random은 48 개의 유효 비트의 내부 정수를 갖는 것으로 보입니다. –

+0

http://stackoverflow.com/questions/453479/how-good-is-java-util-random – Cratylus

답변

5

LinkedHashSet. 내부 시드는 48 비트이므로 무작위 순서는 2^48 int 값 또는 2^47 이중 값 다음에 반복됩니다.

+0

+1 : SecureRandom을 사용하는 경우 다시 시드하지 않아도됩니다. –

0

죄송합니다. 직접 질문에 답변 할 수 없습니다. Java의 난수 생성기의 순환 시간을 기억하지 못합니다. 비록 당신이 생성하고있는 숫자의 양과 가까이서 자르고 있다고 생각합니다.

하지만 컴퓨터 공학 통계 수업에서 내가 배운 것은 당신을 도울 수 있습니다.

대부분의 난수를 생성하는 가장 좋은 방법은 Mersenne Twister 난수 생성기를 사용하는 것입니다. 이 발전기는 시드 할 필요가 없습니다 충분한 임의의 숫자를 제공 할 것, 그것의 기간 (2^19937)이있다 - 여기

1 MerseeneTwister

에 대한 소스 코드를 여기에

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

는 클래스이다 임의의 숫자를 생성합니다.

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(); 
} 
} 

다음은 임의의 숫자를 생성하는 샘플입니다. 소스에서 주석을 제거했음을 유의하십시오. 이것은 코드의 오픈 소스 성격을 자극 할 수도 있지만, 모든 것을 복사 할 수는 없으며 코드로 형식화해야합니다.

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; 
    } 
} 
} 
2
당신이 (고유 값을 보장)를 설정 사용하는 경우가 시드 등에 대해 걱정할 필요가 없습니다

: 당신이 생각하는 것 무엇에도 불구하고

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

, 이것은 매우 빠르게 실행 : 60 밀리 초 동안을 내 (일반) PC의 100000 번호.

정말로 원하는 배열이 있으면 집합에서 추출 할 수 있습니다.
사용, 그들은에서 생성 된 질서를 유지하려는 경우 난수 생성기는 임의의 두 INT 값에서 임의의 두 배를 생성합니다 (이 유사한 성능을 가지고 있었다)

+0

흠. 그래서이 멈춤의 단순한 사실은 사이클이 10^5보다 큰 것 같다고 말하는 겁니까? – Uri

+0

@ 보헤미안 어떻게 발전기의 기간 길이에 대한 질문에 대답합니까? –

+0

@ChristianSemrau 질문을 읽었을 때, 그가 실제로 묻는 것은 10^5 * different * double입니다. 이 impl을 사용하면 대답은 "다시 채울 필요가 없습니다"입니다. – Bohemian

관련 문제