朋友,从以下PRNG生成的第一个(可能是一对)值无论是种子还是0或接近它。有没有一种方法可以使用构造函数或更好的方法,而不必刻录几个值?
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
在http://xoshiro.di.unimi.it/xoroshiro128plus.c
从C ++翻译#include <stdint.h>
static inline uint64_t rotl(const uint64_t x, int k) {
return (x << k) | (x >> (64 - k));
}
static uint64_t s[2];
uint64_t next(void) {
const uint64_t s0 = s[0];
uint64_t s1 = s[1];
const uint64_t result = s0 + s1;
s1 ^= s0;
s[0] = rotl(s0, 24) ^ s1 ^ (s1 << 16); // a, b
s[1] = rotl(s1, 37); // c
return result;
}
答案 0 :(得分:4)
答案在你发布的链接的评论中:&#34;州必须播种,以便它不是到处都是零。如果您有64位种子,我们建议播种splitmix64生成器并使用其输出来填充s。&#34;你正在做的只是播种128位状态的下半部分,所以上半部分为零。结果:第一次调用next()
将返回您放入的种子(注意 result
之前计算{em>}的方式s0
混合在一起:在第一次通话时,s1
为0,s0
是您的初始种子。
两个解决方案:一个是修改您的PRNG类以获取两个 uint64值,如下所示:
s1
另一个是做原始代码的作者建议并使用splitmix64 function从一个64位种子中获取两个64位值。这是该链接(公共域)中该算法的C版本:
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位。