2 回答
TA贡献2012条经验 获得超12个赞
您需要的转换公式是:
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
范围:
这可能看起来很神奇,但您可以说服自己它适用于uint16
:
https://go.dev/play/p/EKB6SH3-SGu
(因为uint64
需要相当多的资源才能运行 :-)
更新:
对于带符号的数字(即int64
),逻辑没有什么不同。因为我们知道我们有一个独特的一对一映射,uint64
其中一种方法就是将输入和输出从 转换为uint64
,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
TA贡献1865条经验 获得超7个赞
要添加到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 整除。
这三个要求被称为 Hull-Dobell 定理。
对于 64 位 LCG,Knuth 的 a=6364136223846793005 和 c=1442695040888963407 看起来不错。
请注意,LCG 映射是一对一的,它将整个 [0...2 64 -1] 区域映射到自身。如果你愿意,你可以反转它。作为RNG,它具有独特的跳跃能力。
- 2 回答
- 0 关注
- 82 浏览
添加回答
举报