-
Notifications
You must be signed in to change notification settings - Fork 2
/
ThreadsafeRandom.cs
199 lines (186 loc) · 7.21 KB
/
ThreadsafeRandom.cs
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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
/*
* Vision.NET 2.1 Computer Vision Library
* Copyright (C) 2009 Matthew Johnson
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.Threading;
using System.Linq;
namespace VisionNET
{
/// <summary>
/// The .NET Random class will create hard to trace, truly heinous bugs if called asynchronously from multiple threads. In order to avoid this, I have
/// included this class for those who need to do so. Also, it has several utility methods for those who want to generate more than a random integer
/// or double value.
/// </summary>
public static class ThreadsafeRandom
{
private static Random _init;
private static ThreadLocal<Random> _rand;
private static Semaphore _sem;
/// <summary>
/// Selects a random member of a list. This is an extension method for all classes which implement <see cref="T:IEnumerable"/>.
/// </summary>
/// <typeparam name="T">Type of the list</typeparam>
/// <param name="list">The list from which to select</param>
/// <returns>A random member of the list</returns>
public static T SelectRandom<T>(this IEnumerable<T> list)
{
int count = list.Count();
int index = Next(count);
return list.ElementAt(index);
}
static ThreadsafeRandom()
{
_sem = new Semaphore(1, 1);
_init = new Random();
_rand = new ThreadLocal<Random>(() =>
{
_sem.WaitOne();
try
{
return new Random(_init.Next());
}
finally { _sem.Release(); }
});
}
/// <summary>
/// Initializes the randomizer with <paramref name="newSeed"/>.
/// </summary>
/// <param name="newSeed">The new seed to use</param>
public static void Initialize(int newSeed)
{
_sem.WaitOne();
_init = new Random(newSeed);
_sem.Release();
}
/// <summary>
/// Generates a random double.
/// </summary>
/// <returns>A random double value</returns>
public static double NextDouble()
{
return _rand.Value.NextDouble();
}
/// <summary>
/// Generates a random integer.
/// </summary>
/// <returns>A random integer value</returns>
public static int Next()
{
return _rand.Value.Next();
}
/// <summary>
/// Generates a random integer in the range of <paramref name="minValue"/> to <paramref name="maxValue"/>.
/// </summary>
/// <param name="minValue">The minimum value to generate</param>
/// <param name="maxValue">The maximum value to generate</param>
/// <returns>A random integer</returns>
public static int Next(int minValue, int maxValue)
{
return _rand.Value.Next(minValue, maxValue);
}
/// <summary>
/// Generates a random integer between 0 and <paramref name="maxValue"/>.
/// </summary>
/// <param name="maxValue">The maximum value to generate</param>
/// <returns>A random integer</returns>
public static int Next(int maxValue)
{
return _rand.Value.Next(maxValue);
}
/// <summary>
/// Generates a random float between 0 and <paramref name="maxValue"/>.
/// </summary>
/// <param name="maxValue">The maximum value to generate</param>
/// <returns>A random float</returns>
public static float NextFloat(float maxValue)
{
return NextFloat(0, maxValue);
}
/// <summary>
/// Generates a random float in the range of <paramref name="minValue"/> to <paramref name="maxValue"/>.
/// </summary>
/// <param name="minValue">The minimum value to generate</param>
/// <param name="maxValue">The maximum value to generate</param>
/// <returns>A random float</returns>
public static float NextFloat(float minValue, float maxValue)
{
return NextFloat() * (maxValue - minValue) + minValue;
}
/// <summary>
/// Generates a random float.
/// </summary>
/// <returns>A random float value</returns>
public static float NextFloat()
{
return (float)NextDouble();
}
/// <summary>
/// Generates a random double between 0 and <paramref name="maxValue"/>.
/// </summary>
/// <param name="maxValue">The maximum value to generate</param>
/// <returns>A random double</returns>
public static double NextDouble(double maxValue)
{
return NextDouble(0, maxValue);
}
/// <summary>
/// Generates a random double in the range of <paramref name="minValue"/> to <paramref name="maxValue"/>.
/// </summary>
/// <param name="minValue">The minimum value to generate</param>
/// <param name="maxValue">The maximum value to generate</param>
/// <returns>A random double</returns>
public static double NextDouble(double minValue, double maxValue)
{
return NextDouble() * (maxValue - minValue) + minValue;
}
/// <summary>
/// Returns true if a random value is less than <paramref name="threshold"/>.
/// </summary>
/// <param name="threshold">A threshold between 0 and 1</param>
/// <returns>True if a random value is less than <paramref name="threshold"/>, false if otherwise</returns>
public static bool Test(double threshold)
{
return NextDouble() < threshold;
}
/// <summary>
/// Generate a random distribution of the provided length.
/// </summary>
/// <param name="length">The length of desired distribution</param>
/// <returns>The randomized distribution</returns>
public static double[] GenerateRandomDistribution(int length)
{
double[] dist = new double[length];
for (int i = 0; i < length; i++)
{
double val = 3 * Math.Log(NextDouble());
dist[i] = val;
}
double min = dist.Min();
double sum = 0;
for (int i = 0; i < length; i++)
{
dist[i] = Math.Exp(dist[i] - min);
sum += dist[i];
}
double norm = 1.0 / sum;
for (int i = 0; i < length; i++)
dist[i] *= norm;
return dist;
}
}
}