自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

如何用 Java 高效的生成隨機數(shù)?Random 的原理是什么?

開發(fā)
?在 JDK的java.util包里提供了一個用于生成隨機數(shù)的Random類,它是如何生成隨機數(shù)的?為什么它生成的隨機數(shù)是均勻的?今天我們一起來聊聊其背后的原理。

在 JDK的java.util包里提供了一個用于生成隨機數(shù)的Random類,它是如何生成隨機數(shù)的?為什么它生成的隨機數(shù)是均勻的?今天我們一起來聊聊其背后的原理。

本文基于Java語言,jdk 11。

1. java.util.Random

Random是 java.util 包提供的一個用于生成隨機數(shù)的類,首先,我們看看官方對它的描述:

通過源碼,我們總結(jié)出幾個核心點:

  • Random類的實例是用來生成一系列的偽隨機數(shù);
  • Random類使用一個 48位的種子(seed),通過線性同余算法進行修改;
  • Random類的特定算法被指定,所以,兩個Random類的實例使用相同的種子創(chuàng)建,并且對于每個實例都調(diào)用相同順序的方法,它們將生成并返回相同的數(shù)字序列
  • Random類是線程安全的,但是,跨線程同時使用同一個java.util.Random實例可能會遇到競爭和相應(yīng)的性能問題;
  • 在多線程設(shè)計中,考慮使用java.util.concurrent.ThreadLocalRandom;
  • Random類的實例不是密碼安全的,對于安全敏感的應(yīng)用程序,考慮使用java.security.SecureRandom;

2. 什么是偽隨機數(shù)?

偽隨機數(shù)指的是一種看起來像隨機數(shù)的序列,但實際上是由確定性算法生成的。這種算法稱為偽隨機數(shù)生成器(PRNG,Pseudo-Random Number Generator)。

PRNG使用一個稱為”種子”的初始值,然后通過一系列的數(shù)學(xué)運算來生成一個序列,這個序列看起來具有隨機性的特征,比如均勻分布、無序性等。

3. 什么是種子(seed)?

在隨機數(shù)生成器中,種子(seed)其實就是一個起始值,它用于初始化隨機數(shù)生成器的狀態(tài)。隨機數(shù)生成器使用這個種子來確定生成隨機數(shù)的序列。種子決定了隨機數(shù)生成器的初始狀態(tài),因此給定相同的種子,將會生成相同的隨機數(shù)序列。

4. 線性同余算法

線性同余算法(LCG,Linear Congruential Generator)是最基本的偽隨機數(shù)生成算法之一,該算法通常使用如下方程表示:

????+1 = (a * ???? + c) mod m

其中:

  • ???? 是當(dāng)前的隨機數(shù)
  • ????+1 是下一個隨機數(shù)
  • a、c 和 m 是事先選定的常數(shù)
  • a、c 和 m 是正整數(shù)

為了更好地理解這個方程,我們通過一個具體的例子來進行說明:

假設(shè):a = 4, c = 1, m = 7,X? = 3,即種子 seed = 3
則:
   X? = (4 * X? + 1) mod 5 = (4 * 3 + 1) mod 7 = 6
   X? = (4 * X? + 1) mod 5 = (4 * 6 + 1) mod 7 = 4
   X? = (4 * X? + 1) mod 5 = (4 * 4 + 1) mod 7 = 3
   X? = (4 * X? + 1) mod 5 = (4 * 3 + 1) mod 7 = 6 (6,4,3)循環(huán)開始
   X? = (4 * X? + 1) mod 5 = (4 * 6 + 1) mod 7 = 4
   X? = (4 * X? + 1) mod 5 = (4 * 4 + 1) mod 7 = 3
   ...

說明:mod是取余操作,等同于 %

通過上面的示例可以看出:如果我們設(shè)定一個種子seed = 3,后面每一次獲取隨機數(shù)都可以通過該方程計算出來,而且按照(6,4,3)這個周期進行循環(huán),整個過程獲取的數(shù)字看起來是隨機的,實際上又是通過固定的方法計算而來,因此叫做偽隨機數(shù)。

對于線性同余算法,需要重點考慮以下 5個因素:

  • 種子(Seed): 線性同余算法的運行依賴于一個種子,改變該種子會產(chǎn)生不同的隨機數(shù)序列,但給定相同的種子和參數(shù),將會生成相同的序列。
  • 數(shù)選擇參: a、c 和 m 的選擇是至關(guān)重要的,不同的參數(shù)會導(dǎo)致不同質(zhì)量的隨機數(shù)序列,包括周期長度、統(tǒng)計特性等。
  • 周期性: 線性同余算法生成隨機數(shù)序列是周期性的,通過上面的例子也可以看出。
  • 統(tǒng)計特性: 線性同余算法的生成的隨機數(shù)序列可能不滿足一些統(tǒng)計特性,如均勻分布、獨立性等。
  • 效率: 線性同余算法是一種非常高效的隨機數(shù)生成算法,因為它只涉及簡單的數(shù)學(xué)運算。這使得它在許多情況下都是一個合適的選擇,尤其是對于需要大量隨機數(shù)的應(yīng)用。

好了,理解了線性同余算法的實現(xiàn)原理,接下來我們來分析 Random是如何計算隨機數(shù)。

5. Random如何生成隨機數(shù)?

Random類包含兩個構(gòu)造方法,如下:

// 無參構(gòu)造器
public Random() {
    this(seedUniquifier() ^ System.nanoTime());
}

// 接收一個 seed參數(shù)的構(gòu)造器
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);
    }
}

// initialScramble方法是用于對種子進行初始的混淆處理,以增加生成的隨機數(shù)的隨機性
private static long initialScramble(long seed) {
    return (seed ^ multiplier) & mask;
}
   ... 

當(dāng)使用Random的無參構(gòu)造器時,Random內(nèi)部會生成一個seed,生成方式如下:

seed = current * 1181783497276652981L ^ System.nanoTime()

如果 current沒有設(shè)置,默認的初始值是:1181783497276652981L。然后,用新生成的seed再調(diào)用帶參構(gòu)造方法,構(gòu)造器內(nèi)部有initialScramble(long seed)方法,用于對種子進行初始的混淆處理,以增加生成的隨機數(shù)的隨機性,保證了其均勻性。

為了更好的說明java.util.Random是如何生成隨機數(shù),這里以其nextDouble()為例進行講解,其源碼如下:

public double nextDouble() {
    return (((long) (next(26)) << 27) + next(27)) * DOUBLE_UNIT;
}

protected int next(int bits) {
    long oldseed, nextseed;
    AtomicLong seed = this.seed;
    do {
        oldseed = seed.get();
        nextseed = (oldseed * multiplier + addend) & mask;
    } while (!seed.compareAndSet(oldseed, nextseed));
    return (int) (nextseed >>> (48 - bits));
}

nextDouble()方法用于生成一個介于[0, 1.0)之間的隨機數(shù),nextDouble()方法可以體現(xiàn)出Random對線性同余算法的具體實現(xiàn)如下:

線性同余算法:????+1 = (a * ???? + c) mod m 
Random的具體實現(xiàn):(seed ^ 0x5DEECE66DL) & ((1L << 48) - 1)

其中 a, c, m都是指定的值,分別為:

  • a 是 0x5DEECE66DL(16進制),轉(zhuǎn)換成 10進制為25214903917,
  • c 是 11(0xB),
  • m 是 2??,即 281474976710656(10進制) 或 0x1000000000000L(16進制)。

另外,java.util.Random還包含另外一些常用的方法,如下:

public int nextInt() {
    return next(32);
}

public boolean nextBoolean() {
    return next(1) != 0;
}

public void nextBytes(byte[] bytes) {
    for (int i = 0, len = bytes.length; i < len; )
        for (int rnd = nextInt(),
             n = Math.min(len - i, Integer.SIZE / Byte.SIZE);
             n-- > 0; rnd >>= Byte.SIZE)
            bytes[i++] = (byte) rnd;
}

6. Math.random()

Math.random()方法是日常開發(fā)中生成隨機數(shù)使用最多的方法,其本質(zhì)是對Random類的包裝,下面為 Math.random()的源碼實現(xiàn):

public static double random() {
    return RandomNumberGeneratorHolder.randomNumberGenerator.nextDouble();
}

private static final class RandomNumberGeneratorHolder {
    static final Random randomNumberGenerator = new Random();
}

通過Math.random()的源碼可以發(fā)現(xiàn):Math.random() 的實現(xiàn)其實就是 (new Random()).nextDouble(),在這里就不贅述了,另外,日常開發(fā)中對Math.random()對真實使用方式,這里也以一副手稿來總結(jié):

解釋:

  • Math.random()生成一個介于[0, 1)的隨機數(shù)字,即 0~0.999…
  • Math.random() * 8生成一個介于[0, 8)的隨機數(shù)字,即 0~7.999…

到此,Random生成隨機數(shù)講解完成,下面我們進行總結(jié):

7. 總結(jié)

上述我們分析了幾種常見的隨機數(shù)生成方式,具體選用哪種可以根據(jù)自身業(yè)務(wù):

  • 偽隨機數(shù)指的是一種看起來像隨機數(shù)的序列,但實際上是由確定性算法生成的,這種算法稱為偽隨機數(shù)生成器。
  • 線性同余算法是一種生成偽隨機數(shù)的常用方法,其實現(xiàn)方程為????+1 = (a * ???? + c) mod m;
  • java.util.Random是 JDK提供的一種隨機數(shù)生成類,其核心算法就是線性同余算法;
  • Math.random() 本質(zhì)上是對 java.util.Random的包裝;
責(zé)任編輯:趙寧寧 來源: 猿java
相關(guān)推薦

2022-12-15 08:54:28

JAVA性能JDK

2019-09-11 10:09:00

Java虛擬機算法

2021-04-06 08:54:13

Random線程安全數(shù)生成器

2017-05-29 09:56:25

2024-11-01 15:51:06

2024-06-28 13:57:34

2010-03-22 19:41:31

2019-12-26 14:07:19

隨機數(shù)偽隨機多線程

2012-03-22 09:31:14

Java

2009-12-02 17:01:01

PHP隨機數(shù)rand()

2021-06-15 07:59:01

Java生成隨機數(shù)Java編程

2010-03-11 12:48:25

Python生成隨機數(shù)

2011-07-08 15:11:03

JAVA

2015-10-13 10:00:58

Swift隨機數(shù)使用總結(jié)

2009-12-08 12:58:33

PHP隨機數(shù)類

2010-07-15 13:34:32

Perl隨機數(shù)

2017-05-18 10:00:40

Linuxpandom隨機數(shù)生成器

2023-01-03 07:49:45

Java隨機數(shù)線程

2021-12-27 09:31:20

HashtableJava隨機數(shù)

2009-06-11 15:16:18

不重復(fù)隨機數(shù)Java
點贊
收藏

51CTO技術(shù)棧公眾號