一田篇、Random類的構(gòu)造函數(shù)峦椰,官方文檔如下:
Random類的構(gòu)造函數(shù)
1.無參的構(gòu)造函數(shù)徒扶,源碼如下:
/**
* Creates a new random number generator. This constructor sets
* the seed of the random number generator to a value very likely
* to be distinct from any other invocation of this constructor.
*/
public Random() {
this(seedUniquifier() ^ System.nanoTime());
}
其中seedUniquifier()
函數(shù)趣席,個人認為是產(chǎn)生一個隨機數(shù)兵志,System.nanoTime()
函數(shù)返回一個納秒級的時間值(這個時間代表什么不重要,此函數(shù)多用來計算流逝的時間宣肚,精度很高想罕,詳見源碼及參考資料),源碼中定義分別如下:
private static long seedUniquifier() {
// L'Ecuyer, "Tables of Linear Congruential Generators of
// Different Sizes and Good Lattice Structure", 1999
for (;;) {
long current = seedUniquifier.get();
long next = current * 181783497276652981L;
if (seedUniquifier.compareAndSet(current, next))
return next;
}
}
/**
* Returns the current value of the running Java Virtual Machine's
* high-resolution time source, in nanoseconds.
*
* <p>This method can only be used to measure elapsed time and is
* not related to any other notion of system or wall-clock time.
* The value returned represents nanoseconds since some fixed but
* arbitrary <i>origin</i> time (perhaps in the future, so values
* may be negative). The same origin is used by all invocations of
* this method in an instance of a Java virtual machine; other
* virtual machine instances are likely to use a different origin.
*
* <p>This method provides nanosecond precision, but not necessarily
* nanosecond resolution (that is, how frequently the value changes)
* - no guarantees are made except that the resolution is at least as
* good as that of {@link #currentTimeMillis()}.
*
* <p>Differences in successive calls that span greater than
* approximately 292 years (2<sup>63</sup> nanoseconds) will not
* correctly compute elapsed time due to numerical overflow.
*
* <p>The values returned by this method become meaningful only when
* the difference between two such values, obtained within the same
* instance of a Java virtual machine, is computed.
*
* <p> For example, to measure how long some code takes to execute:
* <pre> {@code
* long startTime = System.nanoTime();
* // ... the code being measured ...
* long estimatedTime = System.nanoTime() - startTime;}</pre>
*
* <p>To compare two nanoTime values
* <pre> {@code
* long t0 = System.nanoTime();
* ...
* long t1 = System.nanoTime();}</pre>
*
* one should use {@code t1 - t0 < 0}, not {@code t1 < t0},
* because of the possibility of numerical overflow.
*
* @return the current value of the running Java Virtual Machine's
* high-resolution time source, in nanoseconds
* @since 1.5
*/
public static native long nanoTime();
「注:其中nanoTime()
函數(shù)霉涨,用native關(guān)鍵字修飾按价,由本地代碼實現(xiàn)。」
兩者異或運算后笙瑟,初始化類成員變量seed
楼镐,此變量會成為隨機函數(shù)的種子,所有的隨機算法都由種子數(shù)算起往枷,定義如下:
/**
* The internal state associated with this pseudorandom number generator.
* (The specs for the methods in this class describe the ongoing
* computation of this value.)
*/
private final AtomicLong seed;
2.有參的構(gòu)造函數(shù)框产,源碼如下:
/**
* Creates a new random number generator using a single {@code long} seed.
* The seed is the initial value of the internal state of the pseudorandom
* number generator which is maintained by method {@link #next}.
*
* <p>The invocation {@code new Random(seed)} is equivalent to:
* <pre> {@code
* Random rnd = new Random();
* rnd.setSeed(seed);}</pre>
*
* @param seed the initial seed
* @see #setSeed(long)
*/
public Random(long seed) {
if (getClass() == Random.class)
this.seed = new AtomicLong(initialScramble(seed));
else {
// subclass might have overriden setSeed
this.seed = new AtomicLong();
setSeed(seed);
}
}
構(gòu)造函數(shù)由傳入的種子參數(shù)進行初始化,不難理解错洁,值得注意的是秉宿,由同一個種子初始化的Random對象,相同次數(shù)調(diào)用時屯碴,產(chǎn)生的隨機數(shù)相同描睦。舉例如下:
public static void main(String[] args) {
Random random = new Random(47);
for(int i = 0; i < 3; i++){
System.out.print(random.nextInt(20) + " ");
}
System.out.println();
Random randomII = new Random(47);
for(int i = 0; i < 3; i++){
System.out.print(randomII.nextInt(20)+ " ");
}
}
輸出如下:
18 15 13
18 15 13
二、Java隨機數(shù)原理
大多數(shù)語言實現(xiàn)偽隨機數(shù)导而,均采用線性同余方程(linear congruential generator)忱叭,詳細內(nèi)容參照「資料1」.
Java中使用的是48-bit的種子,然后調(diào)用線性同余方程嗡载,源碼如下:
protected int next(int bits) {
long oldseed, nextseed;
AtomicLong seed = this.seed;
do {
oldseed = seed.get();
nextseed = (oldseed * multiplier + addend) & mask; //此處為核心窑多,線性同余方程的實現(xiàn)
} while (!seed.compareAndSet(oldseed, nextseed));
return (int)(nextseed >>> (48 - bits));
}
經(jīng)常在隨機數(shù)中調(diào)用的函數(shù)nextInt()
,源碼如下:
public int nextInt(int bound) {
if (bound <= 0)
throw new IllegalArgumentException(BadBound);
int r = next(31);
int m = bound - 1;
if ((bound & m) == 0) // i.e., bound is a power of 2
r = (int)((bound * (long)r) >> 31);
else {
for (int u = r;
u - (r = u % bound) + m < 0;
u = next(31))
;
}
return r;
}
此處實現(xiàn)應(yīng)該是最新版洼滚,與資料中提供的源碼略有不同埂息,函數(shù)中幾處細節(jié)尚未理解,想清楚之后再回來補充遥巴。
Reference: