隨機數產生器
每個值機率嚴格相同 —— 而且附上分布表讓你自己驗。
本機處理設定範圍後按「產生」
這個範圍抽出的每一個數 —— 分布你可以自己核對
抽出的數落在哪裡
| 區間 | 次數 | 佔比 | 期望次數 |
|---|
完全在你的瀏覽器裡執行 —— 打開開發者工具的 Network 分頁就能驗證
設定範圍、選要幾個、按下產生。真正把「正確的產生器」跟「看起來像的產生器」分開的不是介面,是底下兩件事:隨機從哪裡來,以及它怎麼被折進你指定的範圍。大多數線上工具在第二件事上是錯的,而那個錯不去找就看不到。
模數偏差,以及為什麼幾乎每個線上工具都有
取隨機整數的標準寫法是 Math.floor(Math.random() * n)。它看起來無可挑剔,但它有一個細微的錯。底層來源產生的值來自一個固定大小的池,而那個池的大小幾乎永遠不是 n 的整數倍。把池折到 n 個結果上時,前面幾個結果會各多拿到一個位置,於是它們出現的次數比其他結果多一點。這就是模數偏差。
影響有多大,取決於 n 跟池大小有多接近。範圍是 6 的時候,偏差遠低於任何你能察覺的程度;但當範圍佔了來源值域一個有意義的比例時,它就變成量得出來的東西,而且贏家永遠是你範圍裡最小的那幾個數。
解法是拒絕取樣,這一頁就是這樣做的。折疊之前先算出「最大的、能被你的範圍大小整除的值」。抽到大於或等於那個界的就丟掉重抽。被丟掉的區間極小,而剩下的部分可以被完美等分 —— 所以範圍內每個值的機率是「完全相同」,不是「大致相同」。
分布你可以自己核對
一個你無法驗證的機率主張沒什麼價值,所以這一頁會保留當前範圍抽出的每一個數,並顯示它們落在哪裡。範圍被切成等寬的區間,每個區間應該裝到差不多的數量。面板也會告訴你「預期的擺盪幅度」有多大 —— 因為一張只有次數的表格,在不知道多少變異算正常的情況下毫無用處。
你要找的不是每個區間都完美齊平 —— 那是警訊而不是保證。你要找的是某一種特定型態的缺席:最低的那幾個區間一輪又一輪持續偏高。那是模數偏差的指紋,也正是那個天真寫法會產生的東西。
範圍一改,統計就從零重新開始。這是刻意的。把 1 到 6 的抽樣和 1 到 100 的抽樣混在一起,會做出一張什麼都沒描述的分布表;而一個什麼都沒描述的統計比沒有統計更糟,因為它看起來像證據。
不重複抽出,以及它細微的地方
打開「不重複」之後,產生器改成抽出不放回:一個值出來過就不會再出來。抽獎、排順序、選樂透號碼要的都是這個,而它跟「抽好幾個彼此獨立的數」是真的不同的運算。
它也帶來一個硬限制,而很多工具處理得很糟。如果你要 1 到 10 之間五十個不重複的數,那沒有答案 —— 誠實的回應是講出來,而不是無限迴圈、悄悄回傳重複的值、或安靜地只給你十個。這一頁會告訴你這個範圍只有十個值,然後停下來。
底層依請求的形狀用兩種策略。當你要從很寬的範圍抽少少幾個,就抽出後拒絕重複;當你要的量佔了一個窄範圍的一大部分,就改用部分 Fisher–Yates 洗牌 —— 否則拒絕法會把大部分時間花在重抽已經出現過的值。兩種在「所有可能結果的集合」上都是均勻的,選哪一種是速度問題,不是公正性問題。
為什麼這件事不該在伺服器上跑
隨機是少數幾件「瀏覽器明確比伺服器更適合提供」的事。crypto.getRandomValues 直接取用你自己作業系統的熵池,而那個池是由你自己機器上的硬體播種的。把請求繞去別人的電腦,多換到的是一次網路往返、一筆 log、以及一個知道你抽到什麼的第三方 —— 而結果一點也沒有變得更隨機。
只要這件事有一點利害關係,那筆 log 就是該想一想的地方。如果一次抽出決定誰拿到什麼,「第三方比你更早看到結果」就是一個值得避免的性質。這裡完全沒有請求:打開開發者工具的 Network 分頁,想產生多少就產生多少,那份清單會一直是空的。
常見問題
一句話解釋模數偏差?
當隨機來源的值池無法被你的範圍大小整除時,範圍裡最前面幾個值會各多一次機會,於是出現得比較頻繁。拒絕取樣在折疊之前先把除不盡的餘數區間丟掉,偏差就完全消失了。
這些數字是密碼學安全的嗎?
來源是:crypto.getRandomValues 背後是你作業系統的 CSPRNG,再配上拒絕取樣,後面也不會引入偏差。但要注意,顯示在畫面上的數字不是祕密 —— 如果你需要一個祕密,請用密碼產生器,那一頁不會保留任何歷史。
我的統計為什麼歸零了?
因為你改了範圍。把不同範圍的抽樣混進同一張分布表,會做出一張什麼都沒描述、卻看起來像證據的圖,所以範圍一變統計就重新開始。
可以用來選樂透號碼嗎?
可以 —— 把範圍設成你玩的那個遊戲,並打開「不重複」,因為樂透開獎是抽出不放回。它不會提高你的中獎率。每一種組合的機率都相同,而那正是「沒有任何選號方法會比別的方法好」的原因。
範圍最大可以到多少?
最多 2^53 個值,那是 JavaScript 整數不再精確的界線。超過就直接拒絕,而不是悄悄回傳會跳過某些值的數字 —— 一個「安靜地產不出自己某些輸出」的產生器,比一個直接說不的更糟。
有任何東西被送到伺服器嗎?
沒有。每一個數字都由你自己的瀏覽器產生。你可以在開發者工具的 Network 分頁確認,而且這個網站的 Content-Security-Policy 本來就把連線限制在自己的來源。