-
Notifications
You must be signed in to change notification settings - Fork 0
/
xorshift.cpp
95 lines (72 loc) · 2.2 KB
/
xorshift.cpp
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
85
86
87
88
89
90
91
92
93
94
95
#include <catch.hpp>
#include <iostream>
#include <assert.h>
extern "C"{
#include <unif01.h>
#include <bbattery.h>
}
constexpr uint64_t bitmask(int bits) {
if (bits == 0) {
return 0;
}
return (bitmask(bits - 1) << 1) + 1;
}
template<typename T>
class xorshift64star;
template<>
class xorshift64star<uint64_t> {
public:
explicit xorshift64star(uint64_t seed) : seed_(seed) { assert(seed != 0); }
uint64_t operator()() {
seed_ ^= seed_ >> 12; // a
seed_ ^= seed_ << 25; // b
seed_ ^= seed_ >> 27; // c
return seed_ * 2685821657736338717ULL;
}
private:
uint64_t seed_;
};
template<typename T>
class xorshift64star {
public:
explicit xorshift64star(uint64_t seed) : gen_(seed) {
assert(seed != 0);
}
T operator()() {
return std::ldexp(static_cast<T>(gen_() & MANTISSA_MASK), -DIGITS);
}
static constexpr int DIGITS = std::numeric_limits<T>::digits;
static constexpr uint64_t MANTISSA_MASK = bitmask(DIGITS);
static_assert(std::is_floating_point<T>::value,
"T expected to be a floating point type");
static_assert(DIGITS <= 64, "T is too big");
private:
xorshift64star<uint64_t> gen_;
};
TEST_CASE("xorshift64star smoke test", "[xorshift64star]")
{
std::cout << std::setprecision(100);
xorshift64star<uint64_t> gen1(1);
REQUIRE(gen1() % 10000U == 5165);
REQUIRE(gen1() % 10000U == 1517);
xorshift64star<double> gen2(1);
REQUIRE(static_cast<int>(gen2() * 10000) == 1501);
REQUIRE(static_cast<int>(gen2() * 10000) == 4890);
xorshift64star<float> gen3(1);
REQUIRE(static_cast<int>(gen3() * 10000) == 4252);
REQUIRE(static_cast<int>(gen3() * 10000) == 4741);
}
xorshift64star<double> gen(1);
double genfun(void) {
return gen();
}
// Runtime of this test on my mid 2014 macbook pro is 4h, so I've disabled it.
// Tested with https://www.iro.umontreal.ca/~simardr/testu01/tu01.html.
TEST_CASE("xorshift64star testu01 bigcrush", "[.][bigcrush][xorshift64star]")
{
const char* genname = "xorshift64star";
auto gen = unif01_CreateExternGen01(const_cast<char*>(genname), genfun);
bbattery_BigCrush(gen);
unif01_DeleteExternGen01(gen);
REQUIRE(true);
}