2012-11-09 143 views
8

好的,所以我正在研究如何使用Math.random方法生成隨機數。到目前爲止,我瞭解到它從一個「隨機」種子開始,並且該種子被插入一些複雜的等式中以創建一個隨機數。如果種子永遠是一樣的,結果總是一樣的嗎?預測Javascript的Math.random種子

我聽說Math.random的種子是通過當前時間生成的,對嗎?他們必須將當前時間一直用到毫秒或其他事情上,因爲如果你不這樣做,你會得到相同的結果。

究竟是什麼種子?是「10:45」還是時間和日期,如「10:45 11/8/12」還是某種組合?

如何找到種子,以便我可以預測輸出?

我希望能夠堵塞這樣的:

alert(Math.floor((Math.random()*10)+1)); 

到我的地址欄,並能夠預測的結果。那可能嗎?

+0

'Math.random()'的重點是你不能預測它(至少,並非沒有很大的困難)。 –

+1

有沒有人在這裏閱讀'v8'的源代碼給我們一個明確的答案? – TiansHUo

+0

@TiansHUo - 我讀了犀牛的源代碼,並根據我閱讀的內容回答了這個問題:http://stackoverflow.com/a/13303029/783743 –

回答

14

我翻過犀牛source code找出他們使用哪個僞隨機函數。顯然他們fall backMath.random功能定義在Java standard library

Math.random文檔說:

返回帶有正號,大於或等於0.0且小於1.0的雙精度值。返回值是從該範圍內以近似均勻分佈僞隨機選擇的。

當此方法中,首先調用時,它創建單個新的僞隨機數生成器,彷彿完全按表達式

new java.util.Random 

新的僞隨機數發生器此後用於所有的呼叫到這個方法,並沒有其他地方使用。

此方法已正確同步以允許多個線程正確使用。但是,如果許多線程需要以很快的速率生成僞隨機數,則可能會減少每個線程擁有自己的僞隨機數生成器的爭用。

於是我查了文檔java.util.Random,發現this(默認構造函數):

創建一個新的隨機數發生器。它的種子被初始化爲基於當前時間的值:

public Random() { this(System.currentTimeMillis()); } 

兩個同一毫秒內創建隨機的對象將隨機數的順序相同。

所以現在我們確定種子是以毫秒爲單位的當前時間。此外,對於second constructor的文件說:

public Random(long seed) { setSeed(seed); } 

明年方法用於保存僞隨機數的狀態:

使用單個long種子創建一個新的隨機數生成器發電機。

documentationsetSeed方法表示:

設置此隨機數生成器的使用單個長種子種子。 setSeed的一般契約是它改變了這個隨機數字生成器對象的狀態,以便處於完全相同的狀態,就好像它剛剛以參數seed作爲種子創建的一樣。該方法過setSeed由類隨機實現如下:

synchronized public void setSeed(long seed) { 
    this.seed = (seed^0x5DEECE66DL) & ((1L << 48) - 1); 
    haveNextNextGaussian = false; 
} 

的由類隨機的setSeed實施碰巧只使用48給定的種子的比特。但是,一般來說,覆蓋方法可能會將長參數的所有64位用作種子值。注意:雖然種子值是一個AtomicLong,但此方法仍必須同步以確保hasNextNextGaussian的正確語義。

用於生成隨機數的actual methodnextDouble

返回下一個僞,均勻地從該隨機數生成器的序列分佈在0.0和1.0之間的雙值。

nextDouble功能的實現如下:

public double nextDouble() { 
    return (((long)next(26) << 27) + next(27)) 
     /(double)(1L << 53); 
} 

顯然,這dependsnext功能:

生成下一個僞隨機數。子類應該覆蓋這個,因爲這被所有其他方法使用。

next功能的實現如下:

synchronized protected int next(int bits) { 
    seed = (seed * 0x5DEECE66DL + 0xBL) & ((1L << 48) - 1); 
    return (int)(seed >>> (48 - bits)); 
} 

這就是你正在尋找的僞隨機函數。因爲它在文檔中據說:

這是一個線性同餘僞隨機數發生器,由DH萊默所定義並且由Donald E. Knuth的在計算機程序設計,第2卷的技術中說明:半數值算法,第3.2節。 1。

但請注意,這只是犀牛使用的隨機數生成器。 Spidermonkey和V8等其他實現可能有自己的僞隨機數生成器。

+0

+1,精彩的答案,所以這意味着至少我可以根據時間的精確性列舉一系列可能的時間,至少我可以得到一個可能的隨機數列表(由於安全原因肯定是不安全的)。但對於原來的問題,可能不是,除非你能準確地獲得毫秒。 – TiansHUo

+0

@Aadit你是正確的,它取決於實現,如果你正在使用JavaScript編寫一個Web應用程序,不同的Web瀏覽器使用不同的僞隨機數生成器。對於特定的應用程序這可能會造成嚴重破壞。線性同餘方法在具有所有期望的「隨機」特性 - 強串行相關性方面非常糟糕。請參閱http://stackoverflow.com/questions/19507469/math-random-and-web-programming-in-javascript。好的答案順便說一句。 – MHH

0

種子是一個數字值,所以我的猜測是,如果您撥打Date.now()(或new Date().getTime()用於舊版瀏覽器),就會得到這個數字。

但是,我不確定何時該種子被採集,或者種子是否與當前頁面分離或者與整個瀏覽器進程相同。預測隨機數據應該是非常困難或不可能的,這就是他們隨機的全部要點。

6

這很可能是因爲您可以在同一個毫秒內多次調用Math.random(),並且每次都會返回一個不同的值,因此種子的數量可能比毫秒計數還多。

for (var i = 0; i < 3; i++) { 
    console.log(Math.random(), (new Date()).getTime()); 
}; 

我的輸出:

0.0617244818713516 1352433709108 
0.8024995378218591 1352433709108 
0.2409922298975289 1352433709108 

如果我實現它,我可能使初始種子基於毫秒數,然後會在每次調用時加1,這樣你就不會得到相同的種子值兩次。

下面是從Math.random()預測輸出的100%準確的方法:

Math.random = function() { return .5; }; 

現在Math.random()總是返回.5

+0

@ 43.52.4D。有一種方法可以找到。開始這樣做,十年後我們會得到答案,意思是說,如果可能或不可以......你是真的嗎?! – gdoron

+0

下面是Chrome的Math.random()後面的代碼:http://code.google.com/p/v8/source/browse/trunk/src/v8.cc#170它看起來基本上會使用您的系統隨機數發生器,所以它最終取決於你的操作系統的RNG。 – evan