F# 实例化PRNG的前几个值接近0
朋友们,从下面的PRNG生成的第一个(可能是两个)值要么是0,要么接近它,不管种子是什么。有没有一种方法可以用构造函数或者更好的方法来初始化它,而不必烧掉几个值F# 实例化PRNG的前几个值接近0,f#,F#,朋友们,从下面的PRNG生成的第一个(可能是两个)值要么是0,要么接近它,不管种子是什么。有没有一种方法可以用构造函数或者更好的方法来初始化它,而不必烧掉几个值 type PRNGXXX(seed) = let mutable s : uint64[] = Array.zeroCreate 2 let rotl(x : uint64, k : int) = (x <<< k) ||| (x >>> (64 - k))
type PRNGXXX(seed) =
let mutable s : uint64[] = Array.zeroCreate 2
let rotl(x : uint64, k : int) =
(x <<< k) ||| (x >>> (64 - k))
do s.[1] <- uint64 seed
let sample() : uint64 =
let s0 : uint64 = s.[0]
let mutable s1 : uint64 = s.[1]
let result : uint64 = s0 + s1
s1 <- s1 ^^^ s0
s.[0] <- rotl(s0, 24) ^^^ s1 ^^^ (s1 <<< 16)
s.[1] <- rotl(s1, 37)
result
member x.NextDouble() = (float (sample())) / float System.UInt64.MaxValue
类型PRNGXXX(种子)=
让可变的s:uint64[]=Array.zeroCreate 2
let rotl(x:uint64,k:int)=
(x>(64-k))
do s.[1]答案在您发布的链接的评论中:“必须对状态进行种子设定,以使其并非处处为零。如果您有64位种子,我们建议对splitmix64生成器进行种子设定,并使用其输出填充s。”您所做的只是对128位状态的下半部分进行种子设定,因此上半部分为零。结果:对next()
的第一次调用将精确返回您输入的种子(注意Result
在s0
和s1
混合在一起之前是如何计算的:在第一次调用时,s0
是0,s1
是您的初始种子)
两种解决方案:一种是修改PRNG类以采用两个uint64值,如下所示:
type PRNGXXX(seed0, seed1) =
let mutable s : uint64[] = Array.zeroCreate 2
// ...
do
s.[0] <- uint64 seed0
s.[1] <- uint64 seed1
// ...
我建议使用两个64位的值作为种子,而不是通过splitmix运行的一个64位的值,因为在后一种情况下,真正的熵只有64位,而不是128位。答案在您发布的链接的评论中:“国家必须被播种,这样它就不会到处都是零。如果您有64位种子,我们建议为splitmix64生成器设定种子,并使用其输出填充s。“您所做的只是设定128位状态的下半部分,因此上半部分为零。结果:对next()
的第一次调用将准确返回您输入的种子(注意在将s0
和s1
混合在一起之前如何计算result
:在第一次调用时,s0
是0,s1
是您的初始种子)
两种解决方案:一种是修改PRNG类以采用两个uint64值,如下所示:
type PRNGXXX(seed0, seed1) =
let mutable s : uint64[] = Array.zeroCreate 2
// ...
do
s.[0] <- uint64 seed0
s.[1] <- uint64 seed1
// ...
我建议使用两个64位值作为种子,而不是通过splitmix运行的一个64位值,因为在后一种情况下,真正的熵只有64位,而不是128位。问题已解决。谢谢。msft是否开源实现System.Random()?谷歌搜索建议使用mersenne_twister_引擎,但似乎找不到实现..Net Framework实现:和.Net核心实现:问题已解决。谢谢。msft是否开放源代码实现System.Random()?谷歌搜索建议使用mersenne_twister_引擎,但似乎找不到实现..Net框架实现:和.Net核心实现:
uint64_t next() {
uint64_t z = (x += UINT64_C(0x9E3779B97F4A7C15));
z = (z ^ (z >> 30)) * UINT64_C(0xBF58476D1CE4E5B9);
z = (z ^ (z >> 27)) * UINT64_C(0x94D049BB133111EB);
return z ^ (z >> 31);
}