This repository has been archived by the owner on Jul 29, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
kissrandom.h
106 lines (91 loc) · 2.31 KB
/
kissrandom.h
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
96
97
98
99
100
101
102
103
104
105
106
#ifndef KISSRANDOM_H
#define KISSRANDOM_H
#if defined(_MSC_VER) && _MSC_VER == 1500
typedef unsigned __int32 uint32_t;
typedef unsigned __int64 uint64_t;
#else
#include <stdint.h>
#endif
// KISS = "keep it simple, stupid", but high quality random number generator
// http://www0.cs.ucl.ac.uk/staff/d.jones/GoodPracticeRNG.pdf -> "Use a good RNG and build it into your code"
// http://mathforum.org/kb/message.jspa?messageID=6627731
// https://de.wikipedia.org/wiki/KISS_(Zufallszahlengenerator)
// 32 bit KISS
struct Kiss32Random {
uint32_t x;
uint32_t y;
uint32_t z;
uint32_t c;
// seed must be != 0
Kiss32Random(uint32_t seed = 123456789) {
x = seed;
y = 362436000;
z = 521288629;
c = 7654321;
}
uint32_t kiss() {
// Linear congruence generator
x = 69069 * x + 12345;
// Xor shift
y ^= y << 13;
y ^= y >> 17;
y ^= y << 5;
// Multiply-with-carry
uint64_t t = 698769069ULL * z + c;
c = t >> 32;
z = (uint32_t) t;
return x + y + z;
}
inline int flip() {
// Draw random 0 or 1
return kiss() & 1;
}
inline size_t index(size_t n) {
// Draw random integer between 0 and n-1 where n is at most the number of data points you have
return kiss() % n;
}
inline void set_seed(uint32_t seed) {
x = seed;
}
};
// 64 bit KISS. Use this if you have more than about 2^24 data points ("big data" ;) )
struct Kiss64Random {
uint64_t x;
uint64_t y;
uint64_t z;
uint64_t c;
// seed must be != 0
Kiss64Random(uint64_t seed = 1234567890987654321ULL) {
x = seed;
y = 362436362436362436ULL;
z = 1066149217761810ULL;
c = 123456123456123456ULL;
}
uint64_t kiss() {
// Linear congruence generator
z = 6906969069LL*z+1234567;
// Xor shift
y ^= (y<<13);
y ^= (y>>17);
y ^= (y<<43);
// Multiply-with-carry (uint128_t t = (2^58 + 1) * x + c; c = t >> 64; x = (uint64_t) t)
uint64_t t = (x<<58)+c;
c = (x>>6);
x += t;
c += (x<t);
return x + y + z;
}
inline int flip() {
// Draw random 0 or 1
return kiss() & 1;
}
inline size_t index(size_t n) {
// Draw random integer between 0 and n-1 where n is at most the number of data points you have
return kiss() % n;
}
inline void set_seed(uint32_t seed) {
x = seed;
}
};
#endif
// vim: tabstop=2 shiftwidth=2