Skip to content

Commit d8df6a7

Browse files
authored
Merge pull request #10 from mrdav30/develop
features: add thread-safe deterministic random generator (#9)
2 parents 183fd45 + 9a4d5ba commit d8df6a7

File tree

1 file changed

+116
-0
lines changed

1 file changed

+116
-0
lines changed
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
using System;
2+
using System.Threading;
3+
4+
namespace FixedMathSharp.Utilities
5+
{
6+
/// <summary>
7+
/// Provides thread-safe, deterministic random number generation for use in simulations, games,
8+
/// and physics engines. This utility ensures randomness is consistent across multiple threads,
9+
/// avoiding common pitfalls of shared Random instances and aiding reproducible calculations.
10+
/// </summary>
11+
public static class ThreadLocalRandom
12+
{
13+
/// <summary>
14+
/// Random number generator used to generate seeds,
15+
/// which are then used to create new random number
16+
/// generators on a per-thread basis.
17+
/// </summary>
18+
private static readonly Random globalRandom = new Random(Guid.NewGuid().GetHashCode());
19+
private static readonly object globalLock = new object();
20+
21+
/// <summary>
22+
/// Random number generator
23+
/// </summary>
24+
private static readonly ThreadLocal<Random> threadRandom = new ThreadLocal<Random>(NewRandom);
25+
26+
/// <summary>
27+
/// Creates a new instance of Random. The seed is derived
28+
/// from a global (static) instance of Random, rather
29+
/// than time.
30+
/// </summary>
31+
public static Random NewRandom()
32+
{
33+
lock (globalLock)
34+
return new Random(globalRandom.Next());
35+
}
36+
37+
/// <summary>
38+
/// Returns an instance of Random which can be used freely
39+
/// within the current thread.
40+
/// </summary>
41+
public static Random Instance => threadRandom.Value;
42+
43+
/// <summary>See <see cref="Random.Next()" /></summary>
44+
public static int Next()
45+
{
46+
return Instance.Next();
47+
}
48+
49+
/// <summary>See <see cref="Random.Next(int)" /></summary>
50+
public static int Next(int maxValue)
51+
{
52+
return Instance.Next(maxValue);
53+
}
54+
55+
/// <summary>See <see cref="Random.Next(int, int)" /></summary>
56+
public static int Next(int minValue, int maxValue)
57+
{
58+
return Instance.Next(minValue, maxValue);
59+
}
60+
61+
/// <summary>
62+
/// Returns a random Fixed64 number that is less than `max`.
63+
/// </summary>
64+
/// <param name="max"></param>
65+
public static Fixed64 NextFixed64(Fixed64 max = default)
66+
{
67+
if (max == Fixed64.Zero)
68+
throw new ArgumentException("Max value must be greater than zero.");
69+
70+
byte[] buf = new byte[8];
71+
Instance.NextBytes(buf);
72+
73+
// Use bitwise operation to ensure a non-negative long.
74+
long longRand = BitConverter.ToInt64(buf, 0) & long.MaxValue;
75+
76+
return Fixed64.FromRaw(longRand % max.m_rawValue);
77+
}
78+
79+
/// <summary>
80+
/// Returns a random Fixed64 number that is greater than or equal to `min`, and less than `max`.
81+
/// </summary>
82+
/// <param name="min"></param>
83+
/// <param name="max"></param>
84+
public static Fixed64 NextFixed64(Fixed64 min, Fixed64 max)
85+
{
86+
if (min >= max)
87+
throw new ArgumentException("Min value must be less than max.");
88+
89+
byte[] buf = new byte[8];
90+
Instance.NextBytes(buf);
91+
92+
// Ensure non-negative random long.
93+
long longRand = BitConverter.ToInt64(buf, 0) & long.MaxValue;
94+
95+
return Fixed64.FromRaw(longRand % (max.m_rawValue - min.m_rawValue)) + min;
96+
}
97+
98+
/// <summary>See <see cref="Random.NextDouble()" /></summary>
99+
public static double NextDouble()
100+
{
101+
return Instance.NextDouble();
102+
}
103+
104+
/// <summary>See <see cref="Random.NextDouble()" /></summary>
105+
public static double NextDouble(double min, double max)
106+
{
107+
return Instance.NextDouble() * (max - min) + min;
108+
}
109+
110+
/// <summary>See <see cref="Random.NextBytes(byte[])" /></summary>
111+
public static void NextBytes(byte[] buffer)
112+
{
113+
Instance.NextBytes(buffer);
114+
}
115+
}
116+
}

0 commit comments

Comments
 (0)