实例化PRNG的前几个值接近0

时间:2018-06-14 02:33:18

标签: f#

朋友,从以下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;
}

1 个答案:

答案 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位。