随機數,接觸程式時就會接觸到他,第一次知道随機數隐約記得是和同學在讨論彩票搖獎時知道的,現在看着自己那一把厚厚的彩票就知道當時有多天真了,天真的以為那玩意真随機。好了,言歸正傳。
幾乎我接觸過的每一種語言都提供産生随機數的系統方法,我平時用的時候直接拉來用了,今天突然看見群裡有人在問,就想着那就研究到底,看看random到底是個什麼鬼。
産生随機數的方法:
Random屬于system下的類,想仔細研究,那就F12戳進去,看看他都有什麼方法。
Next()方法用來傳回一個随機數。同樣的代碼你執行和我的結果很可能不一樣,而且我多次運作的結果也很可能不一樣,這就是随機數。
1、不是bug的bug:
當我想使用上面的方法生成多個随機數時,我自然而然的想到了for循環,于是我就循環一百次,生成100個随機數,但結果讓我有點卵碎。
<pre name="code" class="csharp">if (Input.GetKeyDown(KeyCode.T))
{
for (int i = 0; i < 100; i++)
{
System.Random rand = new System.Random();
Debug.Log("随機數 = " + rand.Next());
}
}
你會發現,出現了大量的重複數字。這還真是見了鬼了。于是我想着rand就是個對象,為什麼要每次去執行個體化,看網上說可以把執行個體化的代碼放在for循環外邊,試了試:
if (Input.GetKeyDown(KeyCode.T))
{
System.Random rand = new System.Random();
for (int i = 0; i < 100; i++)
{
Debug.Log("随機數 = " + rand.Next());
}
}
還真歐克了
2、Why出現重複的現象:
這得扯一扯計算機生成随機數的原理了,隐約記得之前了解過“随機種子”的概念,于是百度了下,原理是生成随機數的算法有很多種,最簡單也是最常用的就是 "線性同餘法": 第n+1個數=(第n個數*29+37) % 1000,而“第n個數”就稱之為随機種子,而重複的根本原因就是預設的随機種子是CPU時鐘,現在硬體這麼發達,一微妙執行幾遍函數都不是問題,是以同一時間段,出現多個重複的随機數也就能了解了。我用代碼解釋一下公式吧,MyJiLeiRandom是我自定義的一個功能極其雞肋的生成随機數的類,你調用Next()就會給你生成雞肋的随機數:
public class MyJiLeiRandom
{
private int seed = 2;
public int Next()
{
int next = (seed * 29 + 37) % 1000;
seed = next;
return next;
}
}
他的确看起來是随機的:
那我們平時怎麼讓這個雞肋的随機數真的很随機呢,其實有很多辦法,比如讓随機種子等于遊戲自打開以來運作的時長、目前使用者滑鼠在螢幕上的坐标、設定本機處理器ID+啟動時長-滑鼠坐标.x*滑鼠坐标.y。各種方法,就怕你把自己也搞随機了。
用場景加載時長來作為“随機種子”,來産生看似“真正”的随機數。
if (Input.GetKeyDown(KeyCode.Y))
{
MyJiLeiRandom myRand = new MyJiLeiRandom();
myRand.seed = (int)Time.timeSinceLevelLoad * Screen.currentResolution.height;
for (int i = 0; i < 100; i++)
{
Debug.Log("雞肋類随機數 = " + myRand.Next());
}
}
關于真随機數,看過一個文章,它确實生成了,它主要依據目前程序Id、目前線程Id、系統啟動後的TickCount、目前時間、QueryPerformanceCounter傳回的高性能計數器值、使用者名、計算機名、CPU計數器的值等等來計算。不過一般的項目上确實用不到,如果要用,可自行百度。但萬變不離其宗,無非是把“随機種子”搞的幾乎不可能重複。