This commit is contained in:
Thorsten Sommer 2024-05-29 11:36:02 +02:00
parent a8121a306e
commit 817895015f
No known key found for this signature in database
GPG Key ID: B0B7E2FC074BF1F5
2 changed files with 17 additions and 23 deletions

View File

@ -36,13 +36,12 @@ public sealed class MultiChannelRng<TNum> : IRandom<TNum>, IDisposable where TNu
#region Constructors #region Constructors
/// <summary> /// <summary>
/// Creates a multi-threaded random number generator. /// Creates a multithreaded random number generator.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// This constructor uses the user's current local time /// This constructor uses the user's current local time
/// to derive necessary parameters for the generator. /// to derive the necessary parameters for the generator.
/// Thus, the results are depending on the time, where /// Thus, the results depend on the time when the generator was created.
/// the generator was created.
/// </remarks> /// </remarks>
public MultiChannelRng() public MultiChannelRng()
{ {
@ -58,7 +57,7 @@ public sealed class MultiChannelRng<TNum> : IRandom<TNum>, IDisposable where TNu
} }
/// <summary> /// <summary>
/// Creates a multi-threaded random number generator. /// Creates a multithreaded random number generator.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// A multi-threaded random number generator created by this constructor is /// A multi-threaded random number generator created by this constructor is

View File

@ -12,18 +12,15 @@ namespace FastRng;
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// Please note, that Math.NET's (https://www.mathdotnet.com/) random number generator is in some situations faster. /// Please note, that Math.NET's (https://www.mathdotnet.com/) random number generator is in some situations faster.
/// Unlike Math.NET, MultiThreadedRng is multi-threaded. Consumers can use a token to cancel e.g. timeout an operation.<br/><br/> /// Unlike Math.NET, MultiThreadedRng is multithreaded. Consumers can use a token to cancel an operation.<br/><br/>
/// ///
/// MultiThreadedRng using a shape fitter (a rejection sampler) to enforce arbitrary shapes of probabilities for /// MultiThreadedRng using a shape fitter (a rejection sampler) to enforce arbitrary shapes of probabilities for
/// desired distributions. By using the shape fitter, it is even easy to define discontinuous, arbitrary functions /// desired distributions. By using the shape fitter, it is even easier to define discontinuous, arbitrary functions
/// as shapes. Any consumer can define and use own distributions.<br/><br/> /// as shapes. Any consumer can define and use own distributions.<br/><br/>
/// ///
/// This class uses the George Marsaglia's MWC algorithm. The algorithm's implementation based loosely on John D. /// This class uses the George Marsaglia's MWC algorithm. The algorithm's implementation is based loosely on John D.
/// Cook's (johndcook.com) implementation (https://www.codeproject.com/Articles/25172/Simple-Random-Number-Generation). /// Cook's (johndcook.com) implementation (https://www.codeproject.com/Articles/25172/Simple-Random-Number-Generation).
/// Thanks John for the inspiration.<br/><br/> /// Thanks, John, for the inspiration.<br/><br/>
///
/// Please notice: When using the debug environment, MultiThreadedRng might uses a smaller buffer size. Please ensure,
/// that the production environment uses a release build, though.
/// </remarks> /// </remarks>
public sealed class MultiThreadedRng<TNum> : IRandom<TNum>, IDisposable where TNum : IFloatingPointIeee754<TNum>, IAdditionOperators<TNum, TNum, TNum> public sealed class MultiThreadedRng<TNum> : IRandom<TNum>, IDisposable where TNum : IFloatingPointIeee754<TNum>, IAdditionOperators<TNum, TNum, TNum>
{ {
@ -33,10 +30,10 @@ public sealed class MultiThreadedRng<TNum> : IRandom<TNum>, IDisposable where TN
private const int BUFFER_SIZE = 1_000_000; private const int BUFFER_SIZE = 1_000_000;
#endif #endif
// The queue size means, how many buffer we store in a queue at the same time: // The queue size means, how many buffers we store in a queue at the same time:
private const int QUEUE_SIZE_FLOAT = 2; private const int QUEUE_SIZE_FLOAT = 2;
// The queue size means, how many buffer we store in a queue at the same time: // The queue size means, how many buffers we store in a queue at the same time:
private const int QUEUE_SIZE_INT = QUEUE_SIZE_FLOAT * 2; private const int QUEUE_SIZE_INT = QUEUE_SIZE_FLOAT * 2;
private static readonly TNum CONST_FLOAT_CONVERSION = TNum.CreateChecked(2.328306435454494e-10f); private static readonly TNum CONST_FLOAT_CONVERSION = TNum.CreateChecked(2.328306435454494e-10f);
@ -65,7 +62,7 @@ public sealed class MultiThreadedRng<TNum> : IRandom<TNum>, IDisposable where TN
private uint mW; private uint mW;
private uint mZ; private uint mZ;
// This is the current buffer for the consumer side i.e. the public interfaces: // This is the current buffer for the consumer side, i.e., the public interfaces:
private TNum[] currentBuffer = []; private TNum[] currentBuffer = [];
// The current pointer to the next current buffer's address to read from: // The current pointer to the next current buffer's address to read from:
@ -77,10 +74,8 @@ public sealed class MultiThreadedRng<TNum> : IRandom<TNum>, IDisposable where TN
/// Creates a multi-threaded random number generator. /// Creates a multi-threaded random number generator.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// This constructor uses the user's current local time /// This constructor uses the user's current local time to derive the necessary parameters for the generator.
/// to derive necessary parameters for the generator. /// Thus, the results depend on the time when the generator was created.
/// Thus, the results are depending on the time, where
/// the generator was created.
/// </remarks> /// </remarks>
public MultiThreadedRng() public MultiThreadedRng()
{ {
@ -171,7 +166,7 @@ public sealed class MultiThreadedRng<TNum> : IRandom<TNum>, IDisposable where TN
{ {
try try
{ {
// Ensure, that we do not produce more buffers, as configured: // Ensure that we do not produce more buffers, as configured:
if (this.queueIntegers.Count < QUEUE_SIZE_INT) if (this.queueIntegers.Count < QUEUE_SIZE_INT)
{ {
this.queueIntegers.Enqueue(nextBuffer); this.queueIntegers.Enqueue(nextBuffer);
@ -224,7 +219,7 @@ public sealed class MultiThreadedRng<TNum> : IRandom<TNum>, IDisposable where TN
{ {
try try
{ {
// Ensure, that the queue contains only the configured number of buffers: // Ensure that the queue contains only the configured number of buffers:
if (this.queueFloats.Count < QUEUE_SIZE_FLOAT) if (this.queueFloats.Count < QUEUE_SIZE_FLOAT)
{ {
this.queueFloats.Enqueue(nextBuffer); this.queueFloats.Enqueue(nextBuffer);
@ -273,7 +268,7 @@ public sealed class MultiThreadedRng<TNum> : IRandom<TNum>, IDisposable where TN
// can get the next buffer: // can get the next buffer:
lock (LOCKER) lock (LOCKER)
{ {
// We are might not the first thread, which has to get the next buffer. // We might not the first thread, which has to get the next buffer.
// When some other thread has already got the next buffer, the pointer // When some other thread has already got the next buffer, the pointer
// was already reset to zero. In this case, we start over again: // was already reset to zero. In this case, we start over again:
if(this.currentBufferPointer < BUFFER_SIZE) if(this.currentBufferPointer < BUFFER_SIZE)
@ -295,7 +290,7 @@ public sealed class MultiThreadedRng<TNum> : IRandom<TNum>, IDisposable where TN
// Made a local copy of the current pointer: // Made a local copy of the current pointer:
var myPointer = this.currentBufferPointer; var myPointer = this.currentBufferPointer;
// Issue #8: This might happens when the current thread was interrupted by another thread, and // Issue #8: This might happen when another thread interrupted the current thread, and
// the other thread has already updated the pointer. In this case, we start over again. // the other thread has already updated the pointer. In this case, we start over again.
if (myPointer >= BUFFER_SIZE) if (myPointer >= BUFFER_SIZE)
goto Start; goto Start;