2017-07-02 94 views
2

我有以下代码(the xorshift128+ code from Wikipedia修改为使用向量类型):我的矢量xorshift +不是非常随机

#include <immintrin.h> 
#include <climits> 

__v8si rand_si() { 
    static auto s0 = __v4du{4, 8, 15, 16}, 
     s1 = __v4du{23, 34, 42, 69}; 
    auto x = s0, y = s1; 
    s0 = y; 
    x ^= x << 23; 
    s1 = x^y^(x >> 17)^(y >> 26); 
    return (__v8si)(s1 + y); 
} 

#include <iostream> 
#include <iomanip> 
void foo() { 
    //Shuffle a bit. The result is much worse without this. 
    rand_si(); rand_si(); rand_si(); rand_si(); 
    auto val = rand_si(); 

    for (auto it = reinterpret_cast<int*>(&val); 
     it != reinterpret_cast<int*>(&val + 1); 
     ++it) 
     std::cout << std::hex << std::setfill('0') << std::setw(8) << *it << ' '; 
    std::cout << '\n'; 
} 

其输出

09e2a657 000b8020 1504cc3b 00110040 1360ff2b 00150078 2a9998b7 00228080 

每隔数是很小的,并且没有具有领先的位集。在另一方面,使用xorshift *代替:

__v8si rand_si() { 
    static auto x = __v4du{4, 8, 15, 16}; 
    x ^= x >> 12; 
    x ^= x << 25; 
    x ^= x >> 27; 
    return x * (__v4du)_mm256_set1_epi64x(0x2545F4914F6CDD1D); 
} 

我得到更好的输出

0889632e a938b990 1e8b2f79 832e26bd 11280868 2a22d676 275ca4b8 10954ef9 

但根据维基百科,xorshift +是一个很好的PRNG,而且比xorshift产生更好的伪随机性* 。那么,在我的RNG代码中是否存在一个错误,或者我错误地使用了它?

+2

您正在用'clang'构建,对不对? [gcc说](https://godbolt.org/g/qLUFuz)* :11:17:注意:-flax-vector-conversions允许具有不同元素类型或子元素数量的向量之间的转换* for'return s1 + y;' –

+0

@PeterCordes,是的,这是正确的。 – Dan

+0

为什么使用'__v8si'和'__v4du'代替标准的Intel定义类型? –

回答

3

我想你不应该通过查看它生成的8个数字来判断一个随机生成器。此外,发电机通常需要良好的播种(你的播种可以被认为是不好的 - 你的种子开始几乎所有的比特零。仅仅几次调用rand_si()是不足以让这些比特“传播”)。

因此,我建议您使用适当的播种(例如,一个简单的解决方案是拨打rand_si()甚至更​​多次)。

xorshift*看起来像因为最终的乘法而表现得更好,所以它不容易发现由于播种不充分而导致的不良行为。

提示:将您的代码生成的数字与原始实现进行比较。这样你可以确定你的实现是正确的。

2

geza的答案是完全正确的,播种是罪魁祸首。使用标准的64位PRNG对其进行种子处理要好得多:

void seed(uint64_t s) { 
    std::mt19937_64 e(s); 
    s0 = __v4du{e(), e(), e(), e()}; 
    s1 = __v4du{e(), e(), e(), e()}; 
} 
+0

这里只是一些挑剔:e()调用的顺序在s0和s1中是未指定的(编译器可以自由决定调用构造函数的e()调用)。因此,如果在不同的编译器/编译器版本中需要可重现的结果,则需要首先将e()的结果放入变量中。 – geza

+1

@geza虽然不是命令[在braced-init-list中定义](https://stackoverflow.com/q/14060264/603688)? – Dan

+0

哎呀,你完全正确!我对这些不好的信息感到抱歉。该标准对这种情况例外。有趣... – geza