summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/asg.cc
blob: d8eed592d827634e62fb8882e540b3befc152ece (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
/* This class implements a 160-bit pseudo-random number generator.
 * This generator combines David Jone's JKISS generator with an alternating
 * step generator utilizing a 32-bit Galois m_lfsr as a gate.
 * It passes all tests in TestU01 BigCrush.
 * This software is derived from LibRNG, a public domain pseudo-random number
 * library. (http://www.github.com/bhickey/librng)
 */

#include "AppHdr.h"
#include "asg.h"

static AsgKISS asg_rng[2];

uint32_t
AsgKISS::get_uint32()
{
    m_lcg = (314527869 * m_lcg + 1234567);
    m_lfsr = (m_lfsr >> 1) ^ (-(int32_t)(m_lfsr & 1U) & 0xD0000001U);

    if (m_lfsr & 1)
    {
        m_xorshift ^= m_xorshift << 5;
        m_xorshift ^= m_xorshift >> 7;
        m_xorshift ^= m_xorshift << 22;
    }
    else
    {
        uint64_t t = 4294584393ULL * m_mwcm + m_mwcc;
        m_mwcc = t >> 32;
        m_mwcm = t;
    }

    return m_lcg + m_mwcm + m_xorshift;
}

AsgKISS::AsgKISS()
{
    m_lcg = 12345678;
    m_mwcm = 43219876;
    m_mwcc = 6543217;
    m_xorshift = 987654321;
    m_lfsr = 76543210;
}

AsgKISS::AsgKISS(uint32_t init_key[], int key_length)
{
    m_lcg = (key_length > 0 ? init_key[0] : 12345678);
    m_mwcm = (key_length > 1 ? init_key[1] : 43219876);
    m_mwcc = (key_length > 2 ? init_key[2] : 6543217);
    m_xorshift = (key_length > 3 ? init_key[3] : 987654321);
    m_lfsr = (key_length > 4 ? init_key[4] : 7654321);

    // m_lfsr must not be set to  zero.
    if (!m_lfsr)
    {
        m_lfsr = 7654321;
        while (!(m_lfsr = get_uint32()));
    }
}

uint32_t get_uint32(int generator)
{
    ASSERT(generator >= 0);
    ASSERT((size_t) generator < ARRAYSZ(asg_rng));
    return asg_rng[generator].get_uint32();
}

void seed_asg(uint32_t seed_array[], int seed_len)
{
    {
        const AsgKISS seeded(seed_array, seed_len);
        asg_rng[0] = seeded;
    }

    // Use the just seeded RNG to initialize the rest.
    for (size_t i = 1; i < ARRAYSZ(asg_rng); ++i)
    {
        uint32_t key[5];
        for (size_t j = 0; j < ARRAYSZ(key); ++j)
            key[j] = asg_rng[0].get_uint32();
        const AsgKISS seeded(key, ARRAYSZ(key));
        asg_rng[i] = seeded;
    }
}