forked from dlang/phobos
-
Notifications
You must be signed in to change notification settings - Fork 0
/
random.d
151 lines (126 loc) · 3.63 KB
/
random.d
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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
// Written in the D programming language
/**
* Macros:
* WIKI = Phobos/StdRandom
*/
// random.d
// www.digitalmars.com
module std.random;
// Segments of the code in this file Copyright (c) 1997 by Rick Booth
// From "Inner Loops" by Rick Booth, Addison-Wesley
version (Win32)
{
extern(Windows) int QueryPerformanceCounter(ulong *count);
}
version (linux)
{
private import std.c.linux.linux;
}
/* ===================== Random ========================= */
// BUG: not multithreaded
private uint seed; // starting seed
private uint index; // ith random number
/**
* The random number generator is seeded at program startup with a random value.
This ensures that each program generates a different sequence of random
numbers. To generate a repeatable sequence, use rand_seed() to start the
sequence. seed and index start it, and each successive value increments index.
This means that the $(I n)th random number of the sequence can be directly
generated
by passing index + $(I n) to rand_seed().
Note: This is more random, but slower, than C's rand() function.
To use C's rand() instead, import std.c.stdlib.
*/
void rand_seed(uint seed, uint index)
{
.seed = seed;
.index = index;
}
/**
* Get the next random number in sequence.
* BUGS: shares a global single state, not multithreaded
*/
uint rand()
{
static uint xormix1[20] =
[
0xbaa96887, 0x1e17d32c, 0x03bcdc3c, 0x0f33d1b2,
0x76a6491d, 0xc570d85d, 0xe382b1e3, 0x78db4362,
0x7439a9d4, 0x9cea8ac5, 0x89537c5c, 0x2588f55d,
0x415b5e1d, 0x216e3d95, 0x85c662e7, 0x5e8ab368,
0x3ea5cc8c, 0xd26a0f74, 0xf3a9222b, 0x48aad7e4
];
static uint xormix2[20] =
[
0x4b0f3b58, 0xe874f0c3, 0x6955c5a6, 0x55a7ca46,
0x4d9a9d86, 0xfe28a195, 0xb1ca7865, 0x6b235751,
0x9a997a61, 0xaa6e95c8, 0xaaa98ee1, 0x5af9154c,
0xfc8e2263, 0x390f5e8c, 0x58ffd802, 0xac0a5eba,
0xac4874f6, 0xa9df0913, 0x86be4c74, 0xed2c123b
];
uint hiword, loword, hihold, temp, itmpl, itmph, i;
loword = seed;
hiword = index++;
for (i = 0; i < 4; i++) // loop limit can be 2..20, we choose 4
{
hihold = hiword; // save hiword for later
temp = hihold ^ xormix1[i]; // mix up bits of hiword
itmpl = temp & 0xffff; // decompose to hi & lo
itmph = temp >> 16; // 16-bit words
temp = itmpl * itmpl + ~(itmph * itmph); // do a multiplicative mix
temp = (temp >> 16) | (temp << 16); // swap hi and lo halves
hiword = loword ^ ((temp ^ xormix2[i]) + itmpl * itmph); //loword mix
loword = hihold; // old hiword is loword
}
return hiword;
}
static this()
{
ulong s;
version(Win32)
{
QueryPerformanceCounter(&s);
}
version(linux)
{
// time.h
// sys/time.h
timeval tv;
if (gettimeofday(&tv, null))
{ // Some error happened - try time() instead
s = time(null);
}
else
{
s = cast(ulong)((cast(long)tv.tv_sec << 32) + tv.tv_usec);
}
}
rand_seed(cast(uint) s, cast(uint)(s >> 32));
}
unittest
{
static uint results[10] =
[
0x8c0188cb,
0xb161200c,
0xfc904ac5,
0x2702e049,
0x9705a923,
0x1c139d89,
0x346b6d1f,
0xf8c33e32,
0xdb9fef76,
0xa97fcb3f
];
int i;
uint seedsave = seed;
uint indexsave = index;
rand_seed(1234, 5678);
for (i = 0; i < 10; i++)
{ uint r = rand();
//printf("0x%x,\n", rand());
assert(r == results[i]);
}
seed = seedsave;
index = indexsave;
}