我正在尋找一個確定性數字生成函式,其中輸入數字將始終生成相同的數字,但沒有兩個數字最終會生成相同的結果。
例如:
1 -> 3
2 -> 5
3 -> 4
4 -> 2
5 -> 1
但是,我需要它適用于可以由特定資料型別表示的所有數字,例如 int64。
這感覺像是應該非常簡單或完全不可能的事情。是否有一些亂數生成方案可以保證這種分布,而我不必創建一個包含所有可能數字的陣列,隨機排序,然后使用索引(同時讓我記憶體不足)?
非常感謝 F
uj5u.com熱心網友回復:
您需要的轉換公式是:
f(P) = (mP s) mod n
// n = range - so for uint64 2^64
// s < range i.e. < 2^64
// m = must be coprime with n
這是仿射密碼中使用的模運算。
mod確保它在所需范圍內,是s一個簡單的移位,m應該與互質n。Coprime 僅表示n且m不應共享任何共同因素。由于n是 2^64,它的唯一因素是數字2- 所以m基本上不應該是偶數(即不能被 2 整除):
所以對于uint64范圍:
var (
m = uint64(39293) // some non-even number
s = uint64(75321908) // some random number below 2^64
)
func transform(p uint64) uint64 {
return p*m s // implicitly mod'ed 2^64 by the type's size
}
這可能看起來很神奇,但您可以說服自己它適用于uint16:
https://go.dev/play/p/EKB6SH3-SGu
(因為uint64運行需要相當多的資源:-)
更新:
對于有符號數(即int64),邏輯沒有什么不同。由于我們知道我們有一個獨特的一對一映射,uint64其中一種方法就是將輸入和輸出從uint64to轉換int64,反之亦然:
// original unsigned version
func transform(p uint64) uint64 {
return m*p s
}
func signedTransform(p int64) int64 {
return int64(transform(uint64(p)))
}
再舉一個int16例子,證明沒有碰撞:
https://go.dev/play/p/Fkw5FLMK0Fu
uj5u.com熱心網友回復:
添加到colm.anseo答案中,這種映射也稱為Linear congruential generator。
X n 1 = (aX n c) mod m
當 c ≠ 0 時,正確選擇的引數允許所有種子值的周期等于 m。當且僅當:
- m 和 c 互質,
- a-1 能被 m 的所有素因子整除,
- 如果 m 能被 4 整除,則 a-1 能被 4 整除。
這三個要求被稱為赫爾-多貝爾定理。
對于 64 位 LCG,來自 Knuth 的 a=6364136223846793005 和 c=1442695040888963407 看起來不錯。
請注意,LCG 映射是一對一的,它將整個 [0...2 64 -1] 區域映射到自身。如果你愿意,你可以把它倒過來。作為RNG,它具有獨特的跳躍能力。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/473049.html
上一篇:從Go中的函式回傳指向結構的指標
