成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

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

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

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

本文基于Java語(yǔ)言,jdk 11。

1. java.util.Random

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

通過(guò)源碼,我們總結(jié)出幾個(gè)核心點(diǎn):

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

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

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

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

3. 什么是種子(seed)?

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

4. 線性同余算法

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

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

其中:

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

為了更好地理解這個(gè)方程,我們通過(guò)一個(gè)具體的例子來(lái)進(jìn)行說(shuō)明:

假設(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)開(kāi)始
   X? = (4 * X? + 1) mod 5 = (4 * 6 + 1) mod 7 = 4
   X? = (4 * X? + 1) mod 5 = (4 * 4 + 1) mod 7 = 3
   ...

說(shuō)明:mod是取余操作,等同于 %

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

對(duì)于線性同余算法,需要重點(diǎn)考慮以下 5個(gè)因素:

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

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

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

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

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

// 接收一個(gè) 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方法是用于對(duì)種子進(jìn)行初始的混淆處理,以增加生成的隨機(jī)數(shù)的隨機(jī)性
private static long initialScramble(long seed) {
    return (seed ^ multiplier) & mask;
}
   ... 

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

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

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

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

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()方法用于生成一個(gè)介于[0, 1.0)之間的隨機(jī)數(shù),nextDouble()方法可以體現(xiàn)出Random對(duì)線性同余算法的具體實(shí)現(xiàn)如下:

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

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

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

另外,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()方法是日常開(kāi)發(fā)中生成隨機(jī)數(shù)使用最多的方法,其本質(zhì)是對(duì)Random類的包裝,下面為 Math.random()的源碼實(shí)現(xiàn):

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

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

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

解釋:

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

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

7. 總結(jié)

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

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

2022-12-15 08:54:28

JAVA性能JDK

2019-09-11 10:09:00

Java虛擬機(jī)算法

2017-05-29 09:56:25

2021-04-06 08:54:13

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

2024-06-28 13:57:34

2010-03-22 19:41:31

2024-11-01 15:51:06

2019-12-26 14:07:19

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

2012-03-22 09:31:14

Java

2009-12-02 17:01:01

PHP隨機(jī)數(shù)rand()

2021-06-15 07:59:01

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

2010-03-11 12:48:25

Python生成隨機(jī)數(shù)

2011-07-08 15:11:03

JAVA

2015-10-13 10:00:58

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

2009-12-08 12:58:33

PHP隨機(jī)數(shù)類

2010-07-15 13:34:32

Perl隨機(jī)數(shù)

2017-05-18 10:00:40

Linuxpandom隨機(jī)數(shù)生成器

2021-12-27 09:31:20

HashtableJava隨機(jī)數(shù)

2025-01-17 00:00:00

Java隨機(jī)數(shù)服務(wù)

2021-06-01 22:31:57

區(qū)塊鏈隨機(jī)數(shù)技術(shù)
點(diǎn)贊
收藏

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

主站蜘蛛池模板: 国产日韩欧美一区 | a在线v| 国产污视频在线 | 久久国产精品一区二区三区 | 欧美激情一区 | 国产精品jizz在线观看老狼 | 亚洲图片一区二区三区 | av中文字幕在线观看 | 91日b| 亚洲三区在线观看 | 久久一区二区三区四区 | 日韩一二区 | 奇米四色影视 | 欧美综合国产精品久久丁香 | 欧美一级二级三级 | 亚洲一区二区三区免费观看 | 99热国产精品| 国产黄色在线观看 | 日本超碰| 在线观看中文字幕亚洲 | 色综合一区二区 | 成人免费在线观看 | 在线视频91 | 亚洲欧美成人影院 | 日韩在线视频观看 | 久久久久国产精品一区二区 | 精品一区电影 | 波多野结衣一区二区 | 久久精品免费 | 欧美日韩视频 | 欧美激情视频一区二区三区免费 | 亚洲成人精品国产 | 欧美中文字幕一区二区三区亚洲 | 国产成人精品亚洲日本在线观看 | 国产农村一级国产农村 | 亚洲一二三在线观看 | 精品国产一区久久 | 亚洲视频自拍 | 久久国产精品-国产精品 | 免费能直接在线观看黄的视频 | 网站黄色在线免费观看 |