僞隨機的理解

僞隨機

計算機世界是無數個0和1組成的,非黑即白。不存在不確定的數,所以計算機壓根就無法生成真正的(不確定的)隨機數。

但是實際場景又需要一個隨機數,這時候就開始想辦法,常是利用計算機抓取一些數值,然後將這些數值輸入至一個複雜算法當中,通過一系列運算得出一個數字,這就是平常說的贗隨機數了。
這個抓取的數值,叫做種子

因爲這個是通過算法得到的隨機數,所以輸入一個特定的值,必然得到一個特定的結果,要是通過算法逆推回去,就暴露了種子值,這樣就可以復現,能復現的話,就太恐怖了,就比如在賭場就可以瘋狂贏錢了。所以就需要讓這個輸入的值,無法復現,所以這個種子怎麼選就很關鍵,

最常用的是把時間去當做種子,因爲時間一直在變,當然,還有更高級的 一些硬件隨機數卡,靠的是根據天線收集環境中的電磁波噪音。 還有一些硬件甚至依靠檢測內部的放射性元素衰變計數來產生隨機數。

僞隨機在遊戲中又不能這樣隨機,例如LOL中的暴擊率50%,那麼我不可能讓運氣王刀刀暴擊,因爲這樣對手的體驗非常差,所以就添加了更多的限制條件,第一刀沒暴擊,那麼第二刀的概率就會更大一點。
還有在聽歌的時候,就需要根據用戶的需求去隨機,在晚上的時候隨機更安靜的音樂,隨機用戶更喜歡的音樂,隨機過的音樂不能再次出現,一般常用的算法,洗牌算法。

下面介紹一下java中的random的實現原理:(引用)
在java當中有時我們會常用Random來生成任意的隨機數,以來滿足某些需求。但是可能我們並不知道random內部的實現機制,今天將同大家一起深入研究random的源碼。

Random類本身有兩個構造函數,一個帶參的一個不帶參的。

public Random() {
    this(seedUniquifier() ^ System.nanoTime());
}

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);
}
}
可以看到不帶參的構造函數內部調用了帶參的構造。傳入的參數爲seeduniquifier方法生成的seed和獲取到的當前原子時鐘的當前時間的與操作後的值,

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

方法裏面是一個for循環,但是沒有任何循環條件,也就意味着和while(true)差不多,是一個無限循環的條件,循環中結束的條件是seedUniquifier的值和seedUniquifier.get()後獲得的值是一樣的,然後把current和一個常量值的乘積賦值給seedUniquifier,很明顯可以看到,每次循環後seedUniquifier的值都會變成一個新的next,而且終止循環,把新的值返回。原子時鐘獲取到的當前時間是一直變大的,所以無參構造有參傳入的參數一定是每次都不一樣的。

看完無參可以看下有參的,進入方法體裏面發現裏面進行了邏輯判斷,getClass()和Random.class進行比對,那麼首先進行比對的原因是爲了防止子類自己重寫了setSeed方法,如果針對常量的話,則是直接比較值的大小,而對於對象則是比較對象的地址是否相同,equals不能用於基本類型的比較,其實equals內部也是用比對的。AtomicLong是原子long,根據java中原子的操作性可知,不能同時操作它。

原文鏈接:https://blog.csdn.net/wangluotianxi/article/details/79670680

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章