2017-07-02 89 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