使用WELL512的两个整数之间的c ++随机数

时间:2014-12-13 21:22:35

标签: c++ random generator

我发现此问题可能已在此处得到解答:Random using WELL512

但是,它不是非常用户友好,并没有提供如何在“真实世界”的代码中使用它的示例。

以下是我目前的情况:

#define m (unsigned long)2147483647
#define q (unsigned long)127773    
#define a (unsigned int)16807
#define r (unsigned int)2836    

static unsigned long seed;    
void x_srandom(unsigned long initial_seed);
unsigned long x_random(void);    

void x_srandom(unsigned long initial_seed)
{
    seed = initial_seed;
}    

unsigned long x_random(void)
{
    int lo, hi, test;

    hi = (seed / q);
    lo = (seed % q);

    test = (a * lo - r * hi);

    if (test > 0)
        seed = test;
    else
        seed = (test + m);

    return (seed);
}

int RANDOM(int from, int to)
{
    if (from > to)
    {
        int tmp = from;
        from = to;
        to = tmp;
    }
    return ((x_random() % (to - from + 1)) + from);
}

// Real world function using RANDOM()
void testFunction()
{
    printf("A random number between 1 and 1000 is %d \r\n", RANDOM(1, 1000));
    printf("A random number between 36 and 100 is %d \r\n", RANDOM(36, 100));
    printf("A random number between 1 and 2147483647 is %d \r\n", RANDOM(1, 2147483647));
    printf("A random number between 1 and 5 is %d \r\n", RANDOM(1, 5));
}

上面的例子展示了实现它所需要知道的一切。

我想使用WELL512来确定我的随机数而不是我现在的方式,以上面的例子为例。

4 个答案:

答案 0 :(得分:3)

现在是时候不再使用%来生成分发了。

对我来说,你应该使用WELL512作为统一的随机数发生器(就像标准库中的mt19937一样)。将它包装在为result_type公开typedef(或using)的类中。在你的情况下,可能是无符号长。然后你需要两个constexpr用于min()和max()。那将是0和ULONG_MAX。最后,您需要公开operator(),它返回一个unsigned long。

之后,您将<random>中的功能与引擎一起使用。

class well512 {
public:
    typedef unsigned long result_type;
    static constexpr result_type min() { return 0; }
    static constexpr result_type max() { return ULONG_MAX; }
    result_type operator()() { /* return some value from the underlying well512 implementation */ }
};

int main()
{
    well512 engine();
    std::uniform_int_distribution<> dist { 1, 5 };

    for (int i = 0; i != 10; ++i)
    {
        std::cout << dist(engine) << std::endl;
    }
    return 0;
}

答案 1 :(得分:1)

这是一个完整的例子。它没有你可能想要的所有花里胡哨。例如。没有默认构造函数,也没有单个单词的构造函数。我把它留作练习。

#include <algorithm>
#include <array>
#include <cstdint>
#include <functional>
#include <iostream>
#include <iterator>
#include <limits>
#include <numeric>
#include <ostream>
#include <random>
#include <vector>

class seed_seq
{
public:
    template <typename InputIterator>
    seed_seq(InputIterator first, InputIterator last)
    {
        for (; first != last; ++first)
        {
            v.push_back(*first);
        }
    }

    template <typename RandomAccessIterator>
    void generate(RandomAccessIterator first, RandomAccessIterator last)
    {
        std::vector<unsigned int>::size_type i = 0;
        for (; first != last; ++first)
        {
            *first = v[i];
            if (++i == v.size()){ i = 0; }
        }
    }

private:
    std::vector<unsigned int> v;
};

class well512
{
public:
    using result_type = unsigned int;

    static result_type min() { return 0; }
    static result_type max() { return std::numeric_limits<std::uint32_t>::max(); }

    static const unsigned int state_size = 16;

    explicit well512(seed_seq& sequence) : index(0)
    { sequence.generate(std::begin(state), std::end(state)); }

    result_type operator()()
    {
        std::uint32_t z0 = state[(index + 15) & 0x0fU];
        std::uint32_t z1 = xsl(16, state[index]) ^ xsl(15, state[(index + 13) & 0x0fU]);
        std::uint32_t z2 = xsr(11, state[(index + 9) & 0x0fU]);
        state[index] = z1 ^ z2;
        std::uint32_t t = xslm(5, 0xda442d24U, state[index]);
        index = (index + state_size - 1) & 0x0fU;
        state[index] = xsl(2, z0) ^ xsl(18, z1) ^ (z2 << 28) ^ t;

        return state[index];
    }

private:
    // xor-shift-right
    std::uint32_t xsr(unsigned int shift, std::uint32_t value)
    { return value ^ (value >> shift); }

    // xor-shift-left
    std::uint32_t xsl(unsigned int shift, std::uint32_t value)
    { return value ^ (value << shift); }

    // xor-shift-left and mask
    std::uint32_t xslm(unsigned int shift, std::uint32_t mask, std::uint32_t value)
    { return value ^ ((value << shift) & mask); }

    unsigned int index;
    std::array<std::uint32_t, state_size> state;
};

int main()
{
    // Use a random device to generate 16 random words used as seed for the well512 engine
    std::random_device rd;

    std::vector<well512::result_type> seed_data;
    std::generate_n(std::back_inserter(seed_data), well512::state_size, std::ref(rd));

    seed_seq sequence(std::begin(seed_data), std::end(seed_data));

    // Create a well512 engine
    well512 engine(sequence);

    // Now apply it like any other random engine in C++11
    std::uniform_int_distribution<> dist{ 1, 6 };
    auto rand = std::function <int()> { std::bind(std::ref(dist), std::ref(engine)) };

    // Print out some random numbers between 1 and 6 (simulating throwing a dice)
    const int n = 100;
    std::generate_n(std::ostream_iterator<int>(std::cout, " "), n, rand);
    std::cout << std::endl;

    return 0;
}

答案 2 :(得分:0)

喜欢这个用户515430?

#define m  (unsigned long)2147483647

#define W 32
#define R 16
#define P 0
#define M1 13
#define M2 9
#define M3 5

#define MAT0POS(t,v) (v^(v>>t))
#define MAT0NEG(t,v) (v^(v<<(-(t))))
#define MAT3NEG(t,v) (v<<(-(t)))
#define MAT4NEG(t,b,v) (v ^ ((v<<(-(t))) & b))

#define V0            STATE[state_i                   ]
#define VM1           STATE[(state_i+M1) & 0x0000000fU]
#define VM2           STATE[(state_i+M2) & 0x0000000fU]
#define VM3           STATE[(state_i+M3) & 0x0000000fU]
#define VRm1          STATE[(state_i+15) & 0x0000000fU]
#define VRm2          STATE[(state_i+14) & 0x0000000fU]
#define newV0         STATE[(state_i+15) & 0x0000000fU]
#define newV1         STATE[state_i                 ]
#define newVRm1       STATE[(state_i+14) & 0x0000000fU]

#define FACT 2.32830643653869628906e-10

static unsigned int state_i = 0;
static unsigned int STATE[R];
static unsigned int z0, z1, z2;

void InitWELLRNG512a(unsigned int *init){
    int j;
    state_i = 0;
    for (j = 0; j < R; j++)
        STATE[j] = init[j];
}

double WELLRNG512a(void){
    z0 = VRm1;
    z1 = MAT0NEG(-16, V0) ^ MAT0NEG(-15, VM1);
    z2 = MAT0POS(11, VM2);
    newV1 = z1                  ^ z2;
    newV0 = MAT0NEG(-2, z0) ^ MAT0NEG(-18, z1) ^ MAT3NEG(-28, z2) ^ MAT4NEG(-5, 0xda442d24U, newV1);
    state_i = (state_i + 15) & 0x0000000fU;
    return ((double)STATE[state_i]) * FACT;
}

int RANDOM(int from, int to)
{
    if (from > to)
    {
        int tmp = from;
        from = to;
        to = tmp;
    }

    return to + (from - to) * (WELLRNG512a() / (long double)m);
}

答案 3 :(得分:0)

在两个值之间获得均匀分布的随机整数的最简单方法是使用浮点数学。

double get_uniform_rand() {
    /*Assumes unsigned 32 bit return value from myrnd in range 0 - 0xFFFFFFFF*/
    return (double)myrnd() / (double)0xFFFFFFFF;
}

int32_t get_rnd_in_range(int32_t l, int32_t h) {
    return (int32_t)((double)l + get_uniform_rand() * (double)(h-l));
}

这更像是一种C方法,因为像user515430提到的那样,有一种标准的C ++方式(虽然我个人没有使用它)。