我記得有關在數學導向網站上的文章中有效使用隨機位的方法,但我似乎無法在Google中獲得正確的關鍵字找到它了,它不在我的瀏覽器歷史記錄中。按位高效,統一,加密安全的隨機數生成
正被提出問題的要點是採取隨機數的序列中的結構域[domainStart
,domainEnd
)和有效地使用該隨機數序列的比特均勻地伸入範圍[rangeStart
,rangeEnd
) 。域和範圍都是整數(更準確地說,是long
而不是Z)。 這是什麼算法?
實現的角度來看,我有與此簽名的函數:,我需要使用
long doRead(InputStream in, long rangeStart, long rangeEnd);
in
是基於CSPRNG(由硬件RNG,通過SecureRandom的空調供給);返回的值必須是rangeStart
和rangeEnd
之間,但這種明顯的實現是一種浪費:
long doRead(InputStream in, long rangeStart, long rangeEnd) {
long retVal = 0;
long range = rangeEnd - rangeStart;
// Fill until we get to range
for (int i = 0; (1 << (8 * i)) < range; i++) {
int in = 0;
do {
in = in.read();
// but be sure we don't exceed range
} while(retVal + (in << (8 * i)) >= range);
retVal += in << (8 * i);
}
return retVal + rangeStart;
}
我相信這是實際上是相同的想法亨利指出,這個代碼偏向0和257;班塔爾在一個例子中演示了它。(rand() * (max - min)) + min
,只有我們丟棄它可以讓我們在max
位。我們丟棄這些位並重試,而不是使用可能錯誤地將結果偏置到較低值的模運算符。由於觸發CSPRNG可能會觸發重新播種(可能會阻塞InputStream),因此我想避免浪費隨機位。
首先編輯:亨利提醒我,求和調用中心極限定理。我修正了上面的代碼來解決這個問題。
第二次編輯:機械蝸牛建議我查看Random.nextInt()的源代碼。在閱讀了一段時間之後,我意識到這個問題與基本轉換問題類似。見下面的答案。
「明顯的實現」不僅浪費,而且在概念上也是錯誤的(除了一些實現錯誤)。通過添加隨機數字,您可以更改分配。如果添加足夠的數字,它將變成高斯。例如,投擲兩個骰子會比2多產生7次。 – Henry
謝謝。我知道我在算法上做了一些非常錯誤的事情。 :我應該睡一會兒。 – user314104
看看java.util.Random.nextInt的實現。 –