1. 程式人生 > >隨機數字生成器(RNG)和Hash函式組合武器背後的黑暗祕密

隨機數字生成器(RNG)和Hash函式組合武器背後的黑暗祕密

  文章題目之所以叫“黑暗祕密”,只是我覺得這個名字比較酷=。=然而並沒有涉及到太多背後的數學原理,只是對其分佈作了一些有趣的實驗~
  進入正題,在遊戲程式設計當中,總是會不可避免地用上隨機數生成器(簡稱RNG,RandomNumberGenerators)。但是,RNG 這東西可不是隨便用的,你需要根據實際應用的場景進行一些合理的選擇。比方說,隨機數是否允許重複?
  我相信,絕大多數情況下我們是不希望生成的隨機數出現重複的,比方說,在一些消除類遊戲當中,


這裡寫圖片描述
開心消消樂遊戲截圖

  出現的遊戲方塊都是利用隨機數產生的,然而開發者並不希望遊戲出現太多重複的遊戲方塊,這樣會影響開發者預期的玩家得分流程,甚至出現b

ug。總的來說,什麼場景下我們不希望重複隨機數的出現?最主要的一點便是:

  • 不希望玩家能夠重新審視同一世界。例如,在一些沙盒遊戲當中,當你從特定的種子創建出某個世界時, 如果再次使用了相同的種子,則會再次獲得相同的世界。

  我們提到了“種子”這個概念。一般來說,種子可以是intstring 型別的資料,也可以是其它型別的資料,以此作為輸入獲得一個隨機的輸出。種子最大的特點便是:相同的種子會得到相同的隨機數序列,但當種子發生輕微變化時,得到的隨機數序列便與原來的相比大相徑庭。
  在本文中,我將研究兩種不同方法產生的隨機數分佈:隨機數生成器RNGHash 函式,並嘗試將其結合起來。其中,利用C#

產生資料,利用Matlab 繪製圖形。具體程式碼可以參見我的Github 專案:RNGHash 函式相關程式碼

RNG

  產生隨機數最常用的方法便是使用隨機數生成器(簡稱RNG)。 許多程式語言(如本文使用的C#)都提供了隨機數的生成方法。
  隨機數生成器根據初始種子產生一系列隨機數。 在許多面向物件的語言中,隨機數生成器通常是一個經種子初始化的物件,然後可以重複呼叫該物件的方法來產生隨機數。


  在這種情況下,我們可以利用C#Random 類提供的Next() 方法得到0~1000000之間的隨機整數值。之所以選擇1000000作為最大值,主要是為了圖形繪製的方便,後面可以看到,我會將每一個隨機數對映到一個邊長為100單位的立方體上的某個格點上。
  如下所示的影象,包含由種子0生成的100000個隨機數。其中,每個隨機數表示一個立方體上的一個位置,以行序為主。立方體每一個格點的畫素值範圍為(0,0,0)→(1,1,1),初始R

GB 值為(0,0,0),每當有一個隨機數落在該處時,該處畫素點的RGB 三個通道值均會自增0.1,直到達到1為止。


這裡寫圖片描述

  這裡需要注意的是如果沒有第一個和第二個隨機數,你就不能得到第三個隨機數。 就其性質而言,RNG 使用先前的隨機數產生每個隨機數作為計算的一部分。 因此我們研究RNG,研究的物件都應該是一個隨機序列。


這裡寫圖片描述

  這樣一來,使用RNG 就會有一個明顯的缺點:如果你僅需要一個特定的隨機數(比如序列中的第100個隨機數),那麼你就需要呼叫Next() 方法26次,並使用最後一個數字,但這是非常不方便的。

為什麼你需要序列中的特定隨機數?

  如果你一次性生成所有的東西,你可能不需要一個序列中的特定隨機數。然而存在這樣一種情形:
  假設你的世界中有三個部分:A,BC。其中A 部分使用0號種子生成的隨機數序列前100個隨機數生成。然後玩家進入B 部分,使用第101-200個隨機數生成。此時部分A 被銷燬以釋放記憶體。最後玩家進入C 區,使用第201-300個隨機數生成。同樣地,部分B 被銷燬。
  然而,如果玩家現在又回到B 部分,那麼為了使部分B 看起來不變,應該使用與第一次相同的100個隨機數生成。然而因為A 已經被銷燬,所以我們無法直接得到第101-200個隨機數,需要利用0號種子重新生成整個隨機數序列。

不能只使用具有不同種子值的隨機數生成器嗎?

  需要澄清的是,這是對於RNG 的一個非常常見的誤解。 事實是,儘管同一序列中的不同隨機數字可以說是相互獨立的,但是來自不同隨機序列的相同索引的數字彼此之間並不是獨立的,它們之間可能呈現某種分佈。


這裡寫圖片描述

  所以如果你有100個序列,並從每個序列中取出第i(i1) 個隨機數數,那麼這100個隨機數就不會是相互獨立的隨機數。 它們之間可能會服從某種分佈。
  不妨做一下實驗看看~我將0到99999這100000個數字作為RNG 的種子,得到100000個隨機序列,分別取每一個隨機序列的第一個隨機數將其對映到一個邊長為100單位的立方體上,如下圖所示:


這裡寫圖片描述

  顯然此時的模式分佈已經不再均勻,相反呈現出一個直線族!如果分佈已知,那還不如直接用一個線性函式去進行隨機數的生成23333……
  顯然,這樣一種使用具有不同種子值的隨機數生成器的操作是不大可行的。最起碼,我們也應該保證輸出在肉眼上看起來是隨機的,因為玩家通常不會認真跟你去計算具體的隨機數分佈……想象一下,如果你通過上述操作生成隨機數建立座標,用於在一塊平地上種植樹木。現在,所有的樹木都被被排成一條直線,其餘的平地部分都是空的!相信這會是一件十分尷尬的事囧。
  為了解決這個問題,我覺得我們有必要引入雜湊函式。

Hash函式

  通常,Hash 函式是將把原空間的一個數據集對映到像空間的一個函式。且像空間一般要比原空間更小,以方便處理。
  與隨機數生成器RNG 不同,使用Hash 函式生成隨機數是不需要隨機序列的,即可以按任意順序得到隨機數,只要你提供了一個輸入~


這裡寫圖片描述

  Hash 函式的設計是非常講究的,其中核心的設計原則便是降低碰撞的概率,常用的做法便是降低card(X)card(X)的大小,其中X 是原空間,X 是像空間,card(X) 表示X 的勢,card(X) 表示X 的勢,沒學過實變函式的沒關係=。=就理解為集合的數量即可。顯然,當card(X)=card(X) 的時候我們可以實現無碰撞。
  有一篇文章對於雜湊表的數學原理是講得十分透徹的,有興趣的同學可以看看:雜湊表之數學原理
  偷懶了一下,我僅僅測試了兩種十分經典的Hash 函式:MD5SHA1 函式。

  • MD5:這可能是最著名的Hash 函式之一了。 在生成隨機數時,我們通常只需要一個32位int 值作為返回值,而MD5 會返回一個更大的雜湊值,其中大部分我們只是扔掉。儘管如此,我覺得MD5還是值得測試一波的。
  • SHA1:這也是一個十分經典的Hash 函式,通常返回20位元組(160位)的資料摘要。由於它產生的資料摘要的長度更長,因此更難以發生碰撞,因此也更為安全,但也因此在一定程度上降低了它的運算速度。

  我將0到99999這100000個數字分別作為MD5SHA1 函式的輸入,得到100000個隨機數,依舊是將其對映到一個邊長為100單位的立方體上。如下兩圖是MD5SHA1 函式的測試結果:


這裡寫圖   
 
 </div> 
 <div class=

相關推薦

隨機數字生成器RNGHash函式組合武器背後黑暗祕密

  文章題目之所以叫“黑暗祕密”,只是我覺得這個名字比較酷=。=然而並沒有涉及到太多背後的數學原理,只是對其分佈作了一些有趣的實驗~   進入正題,在遊戲程式設計當中,總是會不可避免地用上隨機數生成器(簡稱RNG,RandomNumberGenerator

Python生成器Generatoryield用法詳解

通過列表生成式,我們可以直接建立一個列表。但是,受到記憶體限制,列表容量肯定是有限的。而且,建立一個包含100萬個元素的列表,不僅佔用很大的儲存空間,如果我們僅僅需要訪問前面幾個元素,那後面絕大多數元素佔用的空間都白白浪費了。 所以,如果列表元素可以按照某種演算法推算出來,那我們是否可以在迴圈的

PHP 知識補全 —— 生成器 generator協程的實現

先說一些廢話 PHP 5.5 以來,新的諸多特性又一次令 PHP 煥發新的光彩,雖然在本文寫的時候已是 PHP 7 alpha 2 釋出後的一段時間,但此時國內依舊是 php 5.3 的天下。不過我認為新的特性遲早會因為舊的版本的逐漸消失而變得越發重要,尤其是 PHP 7 的正式版出來後,因此本

python生成器generator列表生成式

列表生成式 list1 是一個可迭代的物件。當使用一個列表生成式來簡歷一個列表的時候,就建立了一個可迭代物件: <<<list1 = [x*x for x in range(1, 11)] <<<list1 [1, 4, 9, 16, 25, 36

Python:迭代器、生成器yield、iter函式

# 首先理解迭代器(iterators),迭代器是⼀個讓程式設計師可以遍歷的⼀個容# 器(特別是列表)的物件。然⽽,⼀個迭代器在遍歷並讀取⼀個容器的資料元素時,並不# 會執⾏⼀個迭代。這裡有三個部分要說明:# 可迭代物件(Iterable)# 迭代器(Iterator)# 迭代(Iteration)# 可迭代

執行緒篇---Task任務執行緒池不得不說的祕密

整理自部落格園一大佬的文章 :https://www.cnblogs.com/tuyile006/p/7154924.html 和碼農之家一匿名大佬 https://www.e-learn.cn/content/net/1114080 和部落格園大佬 https://www.cnblogs.

c++虛擬函式override過載函式overload的比較

1. 過載函式要求函式有相同的函式名稱,並有不同的引數序列;而虛擬函式則要求完全相同; 2. 過載函式可以是成員函式或友元函式,而虛擬函式只能是成員函式; 3. 過載函式的呼叫是以所傳遞引數的差別作為呼叫不同函式的依據,虛擬函式是根據物件動態型別的不同去呼叫不同

mysql 儲存過程 procedure常用函式function

一, 基本知識 1, 定義 一組為了完成特定功能的SQL語句集,經編譯後儲存在資料庫中,使用者通過指定儲存過程的名字並給定引數(如果該儲存過程帶有引數)來呼叫執行它。 2,demo DELIMITER // DROP PROCEDURE

監督學習:隨機梯度下降算法sgd批梯度下降算法bgd

這就是 影響 個數 執行 類型 http 關系 col pla 線性回歸 首先要明白什麽是回歸。回歸的目的是通過幾個已知數據來預測另一個數值型數據的目標值。 假設特征和結果滿足線性關系,即滿足一個計算公式h(x),這個公式的自變量就是已知的數據x,

TypeScript筆記:迭代器生成器

可迭代性 當一個物件實現了Symbol.iterator屬性時,我們認為它是可迭代的。 一些內建的型別如 Array,Map,Set,String,Int32Array,Uint32Array等都已經實現了各自的Symbol.iterator。 物件上的Symbol.it

OSI模型中物理層的通訊形式總結之模擬傳輸數字傳輸

模擬傳輸與數字傳輸[檢視定義] 1.模擬傳輸系統 背景 儘管模擬傳輸劣於數字傳輸(傳輸過程中,模擬傳輸容易受干擾,訊號易衰減,安全性也不高),但由於採用模擬傳輸技術的電話網在計算機網路出現以前就已運行了近一個世紀,因此世界各地幾乎都有這種電話網,雖然數字傳輸和數字網是今後網路

Python的迭代器iterator生成器generator

前言: 迭代的意思是重複做一些事很多次-就像迴圈中那樣,for迴圈中對序列和字典進行迭代,但是實際上也能對其他的物件進行迭代:實現__iter__方法的物件。 迭代器 __iter__方法返回一個迭代器。所謂的迭代器就是具有next方法(方法不需要引數)的物件。在呼叫next方法時,

Python中的容器container、迭代器iterator生成器generator:yield

1、容器迭代器iterator  以list容器(tuple,range,file類似)為例,list容器可以呼叫自己的__iter__()方法獲取用來迭代自己內部元素的迭代器。例如: # list容器 myList = [1, 2, 3] # 獲取list容器的迭代器 it

oracle-安裝11GR2-隨機啟動

本文件提供CentOS 6.6作業系統下Oracle 11.2.0.4的安裝說明,以便於相關人員順利安裝Oracle 11.2.0.4資料 一 安裝準備 1、已安裝完成的CentOS 6.6作業系統; 2、Oracle 11.2.0.4 For Linux 64位安裝程式

python中的迭代器生成器精華

參考: 1、http://www.runoob.com/python3/python3-iterator-generator.html(菜鳥教程,最好理解) 1、https://anandology.com/python-practice-book/iterators.html#iterto

只讀儲存器ROM隨機存取儲存器RAM有什麼相同點不同點?

RAM-RamdomAccessMemory易揮發性隨機存取儲存器,高速存取,讀寫時間相等,且與地址無關,如計算機記憶體等。 ROM-Read Only Memory只讀儲存器。斷電後資訊不丟失,如計算機啟動用的BIOS晶片。存取速度很低,(較RAM而言)且不能改寫。由於不能改寫資訊,不能升級,現已

【ML筆記】梯度提升決策樹GBDT隨機森林RF的異同

GBDT和RF簡介 GBDT(Gradient Boosting Decision Tree) DT + Boosting = GBDT GBDT是一種boosting演算法。boosting工作機制:先從初始訓練集訓練處一個基學習器,然後在根據基學習器的表現對訓練樣本分佈

XMLXSLT實現程式碼生成器V

XML和XSLT實現程式碼生成器(V)完 生成JDOM文件<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /> 當我們定義好資料模型後,下一步就是將資料模型轉換為

數據庫索引BTree索引Hash索引

就是 strong 存儲引擎 sql 基於 條件 mysql b+ tree 索引   索引是為了方便查找我們所需要的數據。 mysql支持的索引數據類型 B-Tree索引的特點 B-Tree索引以B+Tree(樹)的結構存儲數據。 B-Tree索引能夠加快

python學習-day6-生成器generator

expr 無法 color 循環調用 限制 10個 數列 例子 ner 一,列表生成式 ls = [i*i for i in range(10)]ls[0, 1, 4, 9, 16, 25, 36, 49, 64, 81] ge = (i*i for i in range(