Skip to content

Instantly share code, notes, and snippets.

@Leandros
Created July 2, 2018 05:22
Show Gist options
  • Star 27 You must be signed in to star a gist
  • Fork 8 You must be signed in to fork a gist
  • Save Leandros/6dc334c22db135b033b57e9ee0311553 to your computer and use it in GitHub Desktop.
Save Leandros/6dc334c22db135b033b57e9ee0311553 to your computer and use it in GitHub Desktop.
C++ Pseudo Random Number Generators
/* Copyright (c) 2018 Arvid Gerstmann. */
/* This code is licensed under MIT license. */
#ifndef AG_RANDOM_H
#define AG_RANDOM_H
class splitmix
{
public:
using result_type = uint32_t;
static constexpr result_type (min)() { return 0; }
static constexpr result_type (max)() { return UINT32_MAX; }
friend bool operator==(splitmix const &, splitmix const &);
friend bool operator!=(splitmix const &, splitmix const &);
splitmix() : m_seed(1) {}
explicit splitmix(std::random_device &rd)
{
seed(rd);
}
void seed(std::random_device &rd)
{
m_seed = uint64_t(rd()) << 31 | uint64_t(rd());
}
result_type operator()()
{
uint64_t z = (m_seed += UINT64_C(0x9E3779B97F4A7C15));
z = (z ^ (z >> 30)) * UINT64_C(0xBF58476D1CE4E5B9);
z = (z ^ (z >> 27)) * UINT64_C(0x94D049BB133111EB);
return result_type((z ^ (z >> 31)) >> 31);
}
void discard(unsigned long long n)
{
for (unsigned long long i = 0; i < n; ++i)
operator()();
}
private:
uint64_t m_seed;
};
bool operator==(splitmix const &lhs, splitmix const &rhs)
{
return lhs.m_seed == rhs.m_seed;
}
bool operator!=(splitmix const &lhs, splitmix const &rhs)
{
return lhs.m_seed != rhs.m_seed;
}
class xorshift
{
public:
using result_type = uint32_t;
static constexpr result_type (min)() { return 0; }
static constexpr result_type (max)() { return UINT32_MAX; }
friend bool operator==(xorshift const &, xorshift const &);
friend bool operator!=(xorshift const &, xorshift const &);
xorshift() : m_seed(0xc1f651c67c62c6e0ull) {}
explicit xorshift(std::random_device &rd)
{
seed(rd);
}
void seed(std::random_device &rd)
{
m_seed = uint64_t(rd()) << 31 | uint64_t(rd());
}
result_type operator()()
{
uint64_t result = m_seed * 0xd989bcacc137dcd5ull;
m_seed ^= m_seed >> 11;
m_seed ^= m_seed << 31;
m_seed ^= m_seed >> 18;
return uint32_t(result >> 32ull);
}
void discard(unsigned long long n)
{
for (unsigned long long i = 0; i < n; ++i)
operator()();
}
private:
uint64_t m_seed;
};
bool operator==(xorshift const &lhs, xorshift const &rhs)
{
return lhs.m_seed == rhs.m_seed;
}
bool operator!=(xorshift const &lhs, xorshift const &rhs)
{
return lhs.m_seed != rhs.m_seed;
}
class pcg
{
public:
using result_type = uint32_t;
static constexpr result_type (min)() { return 0; }
static constexpr result_type (max)() { return UINT32_MAX; }
friend bool operator==(pcg const &, pcg const &);
friend bool operator!=(pcg const &, pcg const &);
pcg()
: m_state(0x853c49e6748fea9bULL)
, m_inc(0xda3e39cb94b95bdbULL)
{}
explicit pcg(std::random_device &rd)
{
seed(rd);
}
void seed(std::random_device &rd)
{
uint64_t s0 = uint64_t(rd()) << 31 | uint64_t(rd());
uint64_t s1 = uint64_t(rd()) << 31 | uint64_t(rd());
m_state = 0;
m_inc = (s1 << 1) | 1;
(void)operator()();
m_state += s0;
(void)operator()();
}
result_type operator()()
{
uint64_t oldstate = m_state;
m_state = oldstate * 6364136223846793005ULL + m_inc;
uint32_t xorshifted = uint32_t(((oldstate >> 18u) ^ oldstate) >> 27u);
int rot = oldstate >> 59u;
return (xorshifted >> rot) | (xorshifted << ((-rot) & 31));
}
void discard(unsigned long long n)
{
for (unsigned long long i = 0; i < n; ++i)
operator()();
}
private:
uint64_t m_state;
uint64_t m_inc;
};
bool operator==(pcg const &lhs, pcg const &rhs)
{
return lhs.m_state == rhs.m_state
&& lhs.m_inc == rhs.m_inc;
}
bool operator!=(pcg const &lhs, pcg const &rhs)
{
return lhs.m_state != rhs.m_state
|| lhs.m_inc != rhs.m_inc;
}
#endif /* AG_RANDOM_H */
@jcelerier
Copy link

On line 134:

 m_state = oldstate * 6364136223846793005ULL + m_inc;

this diverges from the original PCG algorithm, which does m_inc | 1 no ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment