forked from apple/foundationdb
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDeterministicRandom.h
134 lines (117 loc) · 3.76 KB
/
DeterministicRandom.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
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
/*
* DeterministicRandom.h
*
* This source file is part of the FoundationDB open source project
*
* Copyright 2013-2018 Apple Inc. and the FoundationDB project authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FLOW_DETERIMINISTIC_RANDOM_H
#define FLOW_DETERIMINISTIC_RANDOM_H
#pragma once
#include <cinttypes>
#include "flow/IRandom.h"
#include "flow/Error.h"
#include "flow/Trace.h"
#include "flow/FastRef.h"
#include <random>
class DeterministicRandom : public IRandom, public ReferenceCounted<DeterministicRandom> {
private:
std::mt19937 random;
uint64_t next;
bool useRandLog;
uint64_t gen64() {
uint64_t curr = next;
next = (uint64_t(random()) << 32) ^ random();
if (TRACE_SAMPLE()) TraceEvent(SevSample, "Random");
return curr;
}
public:
DeterministicRandom( uint32_t seed, bool useRandLog=false ) : random( (unsigned long)seed ), next( (uint64_t(random()) << 32) ^ random() ), useRandLog(useRandLog) {
UNSTOPPABLE_ASSERT( seed != 0 ); // docs for mersenne twister say x0>0
};
double random01() {
double d = gen64() / double(uint64_t(-1));
if (randLog && useRandLog) fprintf(randLog, "R01 %f\n", d);
return d;
}
int randomInt(int min, int maxPlusOne) {
ASSERT(min < maxPlusOne);
unsigned int range;
if (maxPlusOne < 0)
range = std::abs(maxPlusOne - min);
else {
range = maxPlusOne;
range -= min;
}
uint64_t v = (gen64() % range);
int i;
if (min < 0 && ((unsigned int) -min) > v)
i = -(int)(((unsigned int) -min) - v);
else
i = v + min;
if (randLog && useRandLog) fprintf(randLog, "Rint %d\n", i);
return i;
}
int64_t randomInt64(int64_t min, int64_t maxPlusOne) {
ASSERT(min < maxPlusOne);
uint64_t range;
if (maxPlusOne < 0)
range = std::abs(maxPlusOne - min);
else {
range = maxPlusOne;
range -= min;
}
uint64_t v = (gen64() % range);
int64_t i;
if (min < 0 && ((uint64_t) -min) > v)
i = -(int64_t)(((uint64_t) -min) - v);
else
i = v + min;
if (randLog && useRandLog) fprintf(randLog, "Rint64 %" PRId64 "\n", i);
return i;
}
uint32_t randomUInt32() { return gen64(); }
uint32_t randomSkewedUInt32(uint32_t min, uint32_t maxPlusOne) {
std::uniform_real_distribution<double> distribution( std::log(min), std::log(maxPlusOne-1) );
double logpower = distribution(random);
uint32_t loguniform = static_cast<uint32_t>( std::pow( 10, logpower ) );
// doubles can be imprecise, so let's make sure we don't violate an edge case.
return std::max(std::min(loguniform, maxPlusOne-1), min);
}
UID randomUniqueID() {
uint64_t x,y;
x = gen64();
y = gen64();
if (randLog && useRandLog) fprintf(randLog, "Ruid %" PRIx64 " %" PRIx64 "\n", x, y);
return UID(x,y);
}
char randomAlphaNumeric() {
static const char alphanum[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
char c = alphanum[ gen64() % 62 ];
if (randLog && useRandLog) fprintf(randLog, "Rchar %c\n", c);
return c;
}
std::string randomAlphaNumeric( int length ) {
std::string s;
s.reserve( length );
for( int i = 0; i < length; i++ )
s += randomAlphaNumeric();
return s;
}
uint64_t peek() const { return next; }
virtual void addref() { ReferenceCounted<DeterministicRandom>::addref(); }
virtual void delref() { ReferenceCounted<DeterministicRandom>::delref(); }
};
#endif