日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

随机数字生成器(RNG)和Hash函数组合武器背后的黑暗秘密

發布時間:2024/3/24 编程问答 73 豆豆
生活随笔 收集整理的這篇文章主要介紹了 随机数字生成器(RNG)和Hash函数组合武器背后的黑暗秘密 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

  本文主要的參考文獻為:
1. 游戲編程中的數學——隨機數字生成(RNG)的黑暗秘密
2. A Primer on Repeatable Random Numbers

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



開心消消樂游戲截圖

  出現的游戲方塊都是利用隨機數產生的,然而開發者并不希望游戲出現太多重復的游戲方塊,這樣會影響開發者預期的玩家得分流程,甚至出現bug。總的來說,什么場景下我們不希望重復隨機數的出現?最主要的一點便是:

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

  我們提到了“種子”這個概念。一般來說,種子可以是intstring 類型的數據,也可以是其它類型的數據,以此作為輸入獲得一個隨機的輸出。種子最大的特點便是:相同的種子會得到相同的隨機數序列,但當種子發生輕微變化時,得到的隨機數序列便與原來的相比大相徑庭。
  在本文中,我將研究兩種不同方法產生的隨機數分布:隨機數生成器RNGHash 函數,并嘗試將其結合起來。其中,利用C# 產生數據,利用Matlab 繪制圖形。具體代碼可以參見我的Github 項目:RNGHash 函數相關代碼。

RNG

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


  在這種情況下,我們可以利用C#Random 類提供的Next() 方法得到0~1000000之間的隨機整數值。之所以選擇1000000作為最大值,主要是為了圖形繪制的方便,后面可以看到,我會將每一個隨機數映射到一個邊長為100單位的立方體上的某個格點上。
  如下所示的圖像,包含由種子0生成的100000個隨機數。其中,每個隨機數表示一個立方體上的一個位置,以行序為主。立方體每一個格點的像素值范圍為(0,0,0)→(1,1,1),初始RGB 值為(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 函數的測試結果:



MD5 測試結果



SHA1 測試結果

  容易看出,MD5 函數生成的數字具有良好的隨機性,而SHA1 函數生成的數字卻再次呈現出一個直線族的分布!!!總能與直線扯上關系,細思極恐……相信背后一定有深刻的數學原理,若有時間,會再深入研究一波~
  然而,這并不能說明SHA1 函數不適用于隨機數的生成。因為在實際操作當中,每生成一個隨機數就得調用一次Hash 函數,這太消耗性能了。。。我們不妨將RNGHash 函數結合起來,這便有了下面的討論。

RNGHash函數的合體

  RNGHash 函數也可以結合使用。 我們前面已經說到,一個明智的方法是使用不同種子的隨機數生成器,但為了使輸出結果在肉眼上看起來盡可能地隨機,種子(例如在創建迷宮世界時,種子可以是迷宮位置坐標)必須首先通過Hash 函數的處理而非直接使用,否則會使輸出結果呈現出直線族分布。


  再做一波實驗,分別測試一下經MD5 函數和SHA1 函數處理的隨機數生成器效果,如下兩圖所示:



MD5 函數處理的隨機數生成器效果



SHA1 函數處理的隨機數生成器效果

  可以看出,使用經MD5 函數和SHA1 函數處理的隨機數生成器進行隨機數的生成時,隨機數的分布已經能夠呈現出不錯的隨機性,這是滿足我們的預期目標的。

總結

  總而言之,如果你需要一堆隨機數,最簡單的方法就是使用隨機數生成器(RNG),例如C 中的System.Random 類。 為了使所有的隨機數相互之間是隨機的,要么只使用一個隨機序列(即用一個種子初始化,但是當需要序列中的特定隨機數時它便顯得不是很方便,具體原因文中已經解釋),要么使用多個種子,但是在使用這堆種子之前需要先通過一個Hash 函數進行處理。個人還是比較推薦第二種方法的~

總結

以上是生活随笔為你收集整理的随机数字生成器(RNG)和Hash函数组合武器背后的黑暗秘密的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。