簡體   English   中英

預測Javascript的Math.random的種子

[英]Predict the Seed of Javascript's Math.random

好的,所以我正在研究如何使用Math.random方法生成隨機數。 到目前為止,我學會了它從一個“隨機”種子開始,並將該種子插入到一些復雜的方程中以創建一個隨機數。 如果種子總是一樣,結果總是一樣嗎?

我聽說Math.random的種子是通過當前時間生成的,這是正確的嗎? 他們必須使用當前時間一直到mili-seconds或其他東西,因為如果你沒有,你會得到相同的結果。

種子究竟是什么? 是“10:45”之類的時間,還是“10月11日10:45”或某種組合的時間和日期?

我怎樣才能找到種子,所以我可以預測輸出?

我希望能夠插入這個:

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

進入我的網址欄,並能夠預測結果。 那可能嗎?

我瀏覽了Rhino 源代碼 ,找出他們使用的偽隨機函數。 顯然,它們回退到 Java標准庫中定義的Math.random函數。

Math.random的文檔說:

返回帶有正號的double值,大於或等於0.0且小於1.0。 返回值是偽隨機選擇的,具有來自該范圍的(近似)均勻分布。

首次調用此方法時,它會創建一個新的偽隨機數生成器,就像表達式一樣

new java.util.Random

此后,此新偽隨機數生成器用於對此方法的所有調用,並且在其他任何地方都不使用。

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

所以我檢查了java.util.Random的文檔並找到了這個 (對於默認的構造函數):

創建一個新的隨機數生成器。 其種子初始化為基於當前時間的值:

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

在同一毫秒內創建的兩個隨機對象將具有相同的隨機數序列。

所以現在我們確定種子是以毫秒為單位的當前時間。 此外, 第二個構造函數的文檔說:

使用單個長種子創建新的隨機數生成器:

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

由旁邊的方法用於保持偽隨機數生成器的狀態。

setSeed方法的文檔說:

使用單個長種子設置此隨機數生成器的種子。 setSeed的一般契約是它改變了這個隨機數生成器對象的狀態,以便與剛剛用參數種子作為種子創建的狀態完全相同。 方法setSeed由Random類實現,如下所示:

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

類Random的setSeed的實現恰好只使用給定種子的48位。 然而,通常,重寫方法可以使用長參數的所有64位作為種子值。 注意:雖然種子值是AtomicLong,但仍必須同步此方法以確保hasNextNextGaussian的正確語義。

用於生成隨機數的實際方法nextDouble

返回下一個偽隨機數,從此隨機數生成器的序列中均勻分布介於0.0和1.0之間的double值。

nextDouble函數的實現如下:

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

顯然它取決於 next功能:

生成下一個偽隨機數。 子類應該覆蓋它,因為所有其他方法都使用它。

next功能的實現如下:

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

那是你正在尋找的偽隨機函數。 正如文檔中所述:

這是一個線性同余偽隨機數發生器,由DH Lehmer定義並由Donald E. Knuth在The Computer of Computer Programming,Volume 2:Seminumerical Algorithms,3.2.1節中描述。

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

種子可能比毫秒計數更多,因為你可以在相同的毫秒內多次調用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,這樣您就不會獲得兩次相同的種子值。

這是一種100%准確的方法來預測Math.random()的輸出:

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

現在Math.random()將始終返回.5

種子是一個數值,所以我的猜測是,如果你調用Date.now() (或舊的瀏覽器的new Date().getTime() ,它將是你得到的。

但是,我不確定何時使用該種子,或者種子是否被隔離到當前頁面或整個瀏覽器進程是否共同。 預測隨機數應該是非常困難或不可能的,這就是它們的隨機性。

不,你無法預測種子,但你可以預先生成足夠的數字,以便准確地強制匹配。

無論如何,通過閱讀RNG的維基頁面開始 - http://en.wikipedia.org/wiki/Random_number_generation ,看看PRNG的實際實現。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM