Added possibility to get integers out of the RNG
This commit is contained in:
		
							parent
							
								
									f9ea837f68
								
							
						
					
					
						commit
						b2d8e2b5ed
					
				@ -18,4 +18,29 @@ public interface IRandom<TNum> : IDisposable where TNum : IFloatingPointIeee754<
 | 
				
			|||||||
    /// by using multiple threads at the same time. 
 | 
					    /// by using multiple threads at the same time. 
 | 
				
			||||||
    /// </remarks>
 | 
					    /// </remarks>
 | 
				
			||||||
    public TNum GetUniform(CancellationToken cancel = default);
 | 
					    public TNum GetUniform(CancellationToken cancel = default);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// Get a uniform distributed pseudo-random number from the interval [0, max).
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <remarks>
 | 
				
			||||||
 | 
					    /// This method is thread-safe. You can consume numbers from the same generator
 | 
				
			||||||
 | 
					    /// by using multiple threads at the same time. 
 | 
				
			||||||
 | 
					    /// </remarks>
 | 
				
			||||||
 | 
					    /// <param name="max">The maximum value (exclusive). The max value returned will be max - 1.</param>
 | 
				
			||||||
 | 
					    /// <param name="cancel">The cancellation token.</param>
 | 
				
			||||||
 | 
					    /// <returns>A pseudo-random number from the interval [0, max).</returns>
 | 
				
			||||||
 | 
					    public int GetUniformInt(int max, CancellationToken cancel = default);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// Get a uniform distributed pseudo-random number from the interval [min, max).
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <remarks>
 | 
				
			||||||
 | 
					    /// This method is thread-safe. You can consume numbers from the same generator
 | 
				
			||||||
 | 
					    /// by using multiple threads at the same time. 
 | 
				
			||||||
 | 
					    /// </remarks>
 | 
				
			||||||
 | 
					    /// <param name="min">The minimum value (inclusive).</param>
 | 
				
			||||||
 | 
					    /// <param name="max">The maximum value (exclusive). The max value returned will be max - 1.</param>
 | 
				
			||||||
 | 
					    /// <param name="cancel">The cancellation token.</param>
 | 
				
			||||||
 | 
					    /// <returns>A pseudo-random number from the interval [min, max).</returns> 
 | 
				
			||||||
 | 
					    public int GetUniformInt(int min, int max, CancellationToken cancel = default);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -165,6 +165,20 @@ public sealed class MultiChannelRng<TNum> : IRandom<TNum>, IDisposable where TNu
 | 
				
			|||||||
        return valueTask.AsTask().Result;
 | 
					        return valueTask.AsTask().Result;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc />
 | 
				
			||||||
 | 
					    public int GetUniformInt(int max, CancellationToken cancel = default)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        var valueTask = this.channelIntegers.Reader.ReadAsync(cancel);
 | 
				
			||||||
 | 
					        return (int) (valueTask.AsTask().Result % (uint) max);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc />
 | 
				
			||||||
 | 
					    public int GetUniformInt(int min, int max, CancellationToken cancel = default)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        var valueTask = this.channelIntegers.Reader.ReadAsync(cancel);
 | 
				
			||||||
 | 
					        return (int) (valueTask.AsTask().Result % (uint) (max - min) + (uint) min);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #endregion
 | 
					    #endregion
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    #endregion
 | 
					    #endregion
 | 
				
			||||||
 | 
				
			|||||||
@ -61,6 +61,8 @@ public sealed class MultiThreadedRng<TNum> : IRandom<TNum>, IDisposable where TN
 | 
				
			|||||||
        
 | 
					        
 | 
				
			||||||
    // The uniform float producer thread:
 | 
					    // The uniform float producer thread:
 | 
				
			||||||
    private Thread producerRandomUniformDistributedFloat;
 | 
					    private Thread producerRandomUniformDistributedFloat;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    private readonly UIntChannelProducer independentUIntProducer = new();
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
    // Variable w and z for the uint generator. Both get used
 | 
					    // Variable w and z for the uint generator. Both get used
 | 
				
			||||||
    // as seeding variable as well (cf. constructors)
 | 
					    // as seeding variable as well (cf. constructors)
 | 
				
			||||||
@ -312,6 +314,20 @@ public sealed class MultiThreadedRng<TNum> : IRandom<TNum>, IDisposable where TN
 | 
				
			|||||||
        //
 | 
					        //
 | 
				
			||||||
        return this.currentBuffer[myPointer];
 | 
					        return this.currentBuffer[myPointer];
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc />
 | 
				
			||||||
 | 
					    public int GetUniformInt(int max, CancellationToken cancel = default)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        var valueTask = this.independentUIntProducer.GetNextAsync(cancel);
 | 
				
			||||||
 | 
					        return (int) (valueTask.AsTask().Result % (uint) max);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc />
 | 
				
			||||||
 | 
					    public int GetUniformInt(int min, int max, CancellationToken cancel = default)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        var valueTask = this.independentUIntProducer.GetNextAsync(cancel);
 | 
				
			||||||
 | 
					        return (int) (valueTask.AsTask().Result % (uint) (max - min) + (uint) min);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
    private void StopProducer() => this.producerTokenSource.Cancel();
 | 
					    private void StopProducer() => this.producerTokenSource.Cancel();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -320,7 +336,11 @@ public sealed class MultiThreadedRng<TNum> : IRandom<TNum>, IDisposable where TN
 | 
				
			|||||||
    /// when it is no longer needed. Otherwise, the background threads
 | 
					    /// when it is no longer needed. Otherwise, the background threads
 | 
				
			||||||
    /// are still running.
 | 
					    /// are still running.
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    public void Dispose() => this.StopProducer();
 | 
					    public void Dispose()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        this.independentUIntProducer.Dispose();
 | 
				
			||||||
 | 
					        this.StopProducer();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #endregion
 | 
					    #endregion
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
							
								
								
									
										121
									
								
								FastRng/UIntChannelProducer.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								FastRng/UIntChannelProducer.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,121 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Diagnostics.CodeAnalysis;
 | 
				
			||||||
 | 
					using System.Threading;
 | 
				
			||||||
 | 
					using System.Threading.Channels;
 | 
				
			||||||
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace FastRng;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					internal sealed class UIntChannelProducer : IDisposable
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					#if DEBUG
 | 
				
			||||||
 | 
					    private const int BUFFER_SIZE = 1_000_000;
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					    private const int BUFFER_SIZE = 1_000_000;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    private readonly Channel<uint> channelIntegers = Channel.CreateBounded<uint>(new BoundedChannelOptions(capacity: BUFFER_SIZE * 2) { FullMode = BoundedChannelFullMode.Wait, SingleWriter = true, SingleReader = true });
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    // Gets used to stop the producer thread:
 | 
				
			||||||
 | 
					    private readonly CancellationTokenSource producerTokenSource = new();
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    // The uint producer thread:
 | 
				
			||||||
 | 
					    private Thread producerRandomUint;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    // Variable w and z for the uint generator. Both get used
 | 
				
			||||||
 | 
					    // as seeding variable as well (cf. constructors)
 | 
				
			||||||
 | 
					    private uint mW;
 | 
				
			||||||
 | 
					    private uint mZ;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    #region Constructors
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    public UIntChannelProducer()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        //
 | 
				
			||||||
 | 
					        // Initialize the mW and mZ by using
 | 
				
			||||||
 | 
					        // the system's time.
 | 
				
			||||||
 | 
					        //
 | 
				
			||||||
 | 
					        var now = DateTime.Now;
 | 
				
			||||||
 | 
					        var ticks = now.Ticks;
 | 
				
			||||||
 | 
					        this.mW = (uint) (ticks >> 16);
 | 
				
			||||||
 | 
					        this.mZ = (uint) (ticks % 4_294_967_296);
 | 
				
			||||||
 | 
					        this.StartProducerThread();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// Creates a multithreaded random number generator.
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <remarks>
 | 
				
			||||||
 | 
					    /// A multi-threaded random number generator created by this constructor is
 | 
				
			||||||
 | 
					    /// deterministic. It's behaviour is not depending on the time of its creation.<br/><br/>
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// <b>Please note:</b> Although the number generator and all distributions are deterministic,
 | 
				
			||||||
 | 
					    /// the behavior of the consuming application might be non-deterministic. This is possible if
 | 
				
			||||||
 | 
					    /// the application with multiple threads consumes the numbers. The scheduling of the threads
 | 
				
			||||||
 | 
					    /// is up to the operating system and might not be predictable. 
 | 
				
			||||||
 | 
					    /// </remarks>
 | 
				
			||||||
 | 
					    /// <param name="seedU">A seed value to generate a deterministic generator.</param>
 | 
				
			||||||
 | 
					    public UIntChannelProducer(uint seedU)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        this.mW = seedU;
 | 
				
			||||||
 | 
					        this.mZ = 362_436_069;
 | 
				
			||||||
 | 
					        this.StartProducerThread();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// Creates a multi-threaded random number generator.
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <remarks>
 | 
				
			||||||
 | 
					    /// A multi-threaded random number generator created by this constructor is
 | 
				
			||||||
 | 
					    /// deterministic. It's behaviour is not depending on the time of its creation.<br/><br/>
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// <b>Please note:</b> Although the number generator and all distributions are deterministic,
 | 
				
			||||||
 | 
					    /// the behavior of the consuming application might be non-deterministic. This is possible if
 | 
				
			||||||
 | 
					    /// the application with multiple threads consumes the numbers. The scheduling of the threads
 | 
				
			||||||
 | 
					    /// is up to the operating system and might not be predictable. 
 | 
				
			||||||
 | 
					    /// </remarks>
 | 
				
			||||||
 | 
					    /// <param name="seedU">The first seed value.</param>
 | 
				
			||||||
 | 
					    /// <param name="seedV">The second seed value.</param>
 | 
				
			||||||
 | 
					    public UIntChannelProducer(uint seedU, uint seedV)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        this.mW = seedU;
 | 
				
			||||||
 | 
					        this.mZ = seedV;
 | 
				
			||||||
 | 
					        this.StartProducerThread();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void StartProducerThread()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        this.producerRandomUint = new Thread(() => this.RandomProducerUint(this.producerTokenSource.Token)) {IsBackground = true};
 | 
				
			||||||
 | 
					        this.producerRandomUint.Start();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #endregion
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    [ExcludeFromCodeCoverage]
 | 
				
			||||||
 | 
					    private async void RandomProducerUint(CancellationToken cancellationToken)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        try
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            while (!cancellationToken.IsCancellationRequested)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                this.mZ = 36_969 * (this.mZ & 65_535) + (this.mZ >> 16);
 | 
				
			||||||
 | 
					                this.mW = 18_000 * (this.mW & 65_535) + (this.mW >> 16);
 | 
				
			||||||
 | 
					                await this.channelIntegers.Writer.WriteAsync((this.mZ << 16) + this.mW, cancellationToken);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (OperationCanceledException)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    public async ValueTask<uint> GetNextAsync(CancellationToken cancellationToken = default) => await this.channelIntegers.Reader.ReadAsync(cancellationToken);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    #region Implementation of IDisposable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void StopProducer() => this.producerTokenSource.Cancel();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc />
 | 
				
			||||||
 | 
					    public void Dispose() => this.StopProducer();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #endregion
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										327
									
								
								FastRngTests/GetIntTests.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										327
									
								
								FastRngTests/GetIntTests.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,327 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Diagnostics.CodeAnalysis;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using FastRng;
 | 
				
			||||||
 | 
					using FastRng.Distributions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using NUnit.Framework;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace FastRngTests;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[ExcludeFromCodeCoverage]
 | 
				
			||||||
 | 
					public class GetIntTests
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    #region Channel-Based
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    [Test]
 | 
				
			||||||
 | 
					    [Category(TestCategories.COVER)]
 | 
				
			||||||
 | 
					    [Category(TestCategories.NORMAL)]
 | 
				
			||||||
 | 
					    [Category(TestCategories.INT)]
 | 
				
			||||||
 | 
					    public void ChannelGetMax()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        var random = new Random();
 | 
				
			||||||
 | 
					        var randomMax = random.Next();
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        using var rng = new MultiChannelRng<float>();
 | 
				
			||||||
 | 
					        for(var n = 0; n < 10_000; n++)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var value = rng.GetUniformInt(randomMax);
 | 
				
			||||||
 | 
					            Assert.That(value, Is.GreaterThanOrEqualTo(0));
 | 
				
			||||||
 | 
					            Assert.That(value, Is.LessThanOrEqualTo(randomMax));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    [Test]
 | 
				
			||||||
 | 
					    [Category(TestCategories.COVER)]
 | 
				
			||||||
 | 
					    [Category(TestCategories.NORMAL)]
 | 
				
			||||||
 | 
					    [Category(TestCategories.INT)]
 | 
				
			||||||
 | 
					    public void ChannelGetMaxDistributionCheck()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        var random = new Random();
 | 
				
			||||||
 | 
					        var randomMax = random.Next(3, 33);
 | 
				
			||||||
 | 
					        var freqCheck = new IntFrequencyAnalysis(randomMax);
 | 
				
			||||||
 | 
					        using var rng = new MultiChannelRng<float>();
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        for(var n = 0; n < 10_000; n++)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var value = rng.GetUniformInt(randomMax);
 | 
				
			||||||
 | 
					            freqCheck.CountThis(value);
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            Assert.That(value, Is.GreaterThanOrEqualTo(0));
 | 
				
			||||||
 | 
					            Assert.That(value, Is.LessThanOrEqualTo(randomMax));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        var distribution = freqCheck.NormalizeAndPlotEvents(TestContext.WriteLine);
 | 
				
			||||||
 | 
					        var max = distribution.Max();
 | 
				
			||||||
 | 
					        var min = distribution.Min();
 | 
				
			||||||
 | 
					        Assert.That(max - min, Is.LessThanOrEqualTo(0.27f));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    [Test]
 | 
				
			||||||
 | 
					    [Category(TestCategories.COVER)]
 | 
				
			||||||
 | 
					    [Category(TestCategories.NORMAL)]
 | 
				
			||||||
 | 
					    [Category(TestCategories.INT)]
 | 
				
			||||||
 | 
					    public void ChannelGetMinMax()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        var random = new Random();
 | 
				
			||||||
 | 
					        var randomMin = random.Next();
 | 
				
			||||||
 | 
					        int randomMax;
 | 
				
			||||||
 | 
					        do
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            randomMax = random.Next();
 | 
				
			||||||
 | 
					        } while (randomMax < randomMin);
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        using var rng = new MultiChannelRng<float>();
 | 
				
			||||||
 | 
					        for(var n = 0; n < 10_000; n++)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var value = rng.GetUniformInt(randomMin, randomMax);
 | 
				
			||||||
 | 
					            Assert.That(value, Is.GreaterThanOrEqualTo(randomMin));
 | 
				
			||||||
 | 
					            Assert.That(value, Is.LessThanOrEqualTo(randomMax));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    [Test]
 | 
				
			||||||
 | 
					    [Category(TestCategories.COVER)]
 | 
				
			||||||
 | 
					    [Category(TestCategories.NORMAL)]
 | 
				
			||||||
 | 
					    [Category(TestCategories.INT)]
 | 
				
			||||||
 | 
					    public void ChannelGetMinMaxDistributionCheck()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        var random = new Random();
 | 
				
			||||||
 | 
					        var randomMin = random.Next(0, 16);
 | 
				
			||||||
 | 
					        var randomMax = random.Next(randomMin + 10, 33);
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        var freqCheck = new IntFrequencyAnalysis(randomMax - randomMin);
 | 
				
			||||||
 | 
					        using var rng = new MultiChannelRng<float>();
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        for(var n = 0; n < 10_000; n++)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var value = rng.GetUniformInt(randomMin, randomMax);
 | 
				
			||||||
 | 
					            freqCheck.CountThis(value - randomMin);
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            Assert.That(value, Is.GreaterThanOrEqualTo(randomMin));
 | 
				
			||||||
 | 
					            Assert.That(value, Is.LessThanOrEqualTo(randomMax));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        var distribution = freqCheck.NormalizeAndPlotEvents(TestContext.WriteLine);
 | 
				
			||||||
 | 
					        var max = distribution.Max();
 | 
				
			||||||
 | 
					        var min = distribution.Min();
 | 
				
			||||||
 | 
					        Assert.That(max - min, Is.LessThanOrEqualTo(0.27f));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    [Test]
 | 
				
			||||||
 | 
					    [Category(TestCategories.COVER)]
 | 
				
			||||||
 | 
					    [Category(TestCategories.NORMAL)]
 | 
				
			||||||
 | 
					    [Category(TestCategories.INT)]
 | 
				
			||||||
 | 
					    public void ChannelCheckMinMax01()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        var expectedMax = 3;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        var max = int.MinValue;
 | 
				
			||||||
 | 
					        var min = int.MaxValue;
 | 
				
			||||||
 | 
					        using var rng = new MultiChannelRng<float>();
 | 
				
			||||||
 | 
					        for(var n = 0; n < 10_000; n++)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var value = rng.GetUniformInt(expectedMax);
 | 
				
			||||||
 | 
					            if (value < min)
 | 
				
			||||||
 | 
					                min = value;
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            if (value > max)
 | 
				
			||||||
 | 
					                max = value;
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            Assert.That(value, Is.GreaterThanOrEqualTo(0));
 | 
				
			||||||
 | 
					            Assert.That(value, Is.LessThanOrEqualTo(expectedMax));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        Assert.That(min, Is.EqualTo(0));
 | 
				
			||||||
 | 
					        Assert.That(max, Is.EqualTo(expectedMax - 1));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    [Test]
 | 
				
			||||||
 | 
					    [Category(TestCategories.COVER)]
 | 
				
			||||||
 | 
					    [Category(TestCategories.NORMAL)]
 | 
				
			||||||
 | 
					    [Category(TestCategories.INT)]
 | 
				
			||||||
 | 
					    public void ChannelCheckMinMax02()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        var expectedMin = 2;
 | 
				
			||||||
 | 
					        var expectedMax = 6;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        var max = int.MinValue;
 | 
				
			||||||
 | 
					        var min = int.MaxValue;
 | 
				
			||||||
 | 
					        using var rng = new MultiChannelRng<float>();
 | 
				
			||||||
 | 
					        for(var n = 0; n < 10_000; n++)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var value = rng.GetUniformInt(expectedMin, expectedMax);
 | 
				
			||||||
 | 
					            if (value < min)
 | 
				
			||||||
 | 
					                min = value;
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            if (value > max)
 | 
				
			||||||
 | 
					                max = value;
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            Assert.That(value, Is.GreaterThanOrEqualTo(expectedMin));
 | 
				
			||||||
 | 
					            Assert.That(value, Is.LessThanOrEqualTo(expectedMax));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        Assert.That(min, Is.EqualTo(expectedMin));
 | 
				
			||||||
 | 
					        Assert.That(max, Is.EqualTo(expectedMax - 1));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    #endregion
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    #region Multithreaded
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    [Test]
 | 
				
			||||||
 | 
					    [Category(TestCategories.COVER)]
 | 
				
			||||||
 | 
					    [Category(TestCategories.NORMAL)]
 | 
				
			||||||
 | 
					    [Category(TestCategories.INT)]
 | 
				
			||||||
 | 
					    public void MultithreadedGetMax()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        var random = new Random();
 | 
				
			||||||
 | 
					        var randomMax = random.Next();
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        using var rng = new MultiThreadedRng<float>();
 | 
				
			||||||
 | 
					        for(var n = 0; n < 10_000; n++)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var value = rng.GetUniformInt(randomMax);
 | 
				
			||||||
 | 
					            Assert.That(value, Is.GreaterThanOrEqualTo(0));
 | 
				
			||||||
 | 
					            Assert.That(value, Is.LessThanOrEqualTo(randomMax));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    [Test]
 | 
				
			||||||
 | 
					    [Category(TestCategories.COVER)]
 | 
				
			||||||
 | 
					    [Category(TestCategories.NORMAL)]
 | 
				
			||||||
 | 
					    [Category(TestCategories.INT)]
 | 
				
			||||||
 | 
					    public void MultithreadedGetMaxDistributionCheck()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        var random = new Random();
 | 
				
			||||||
 | 
					        var randomMax = random.Next(3, 33);
 | 
				
			||||||
 | 
					        var freqCheck = new IntFrequencyAnalysis(randomMax);
 | 
				
			||||||
 | 
					        using var rng = new MultiThreadedRng<float>();
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        for(var n = 0; n < 10_000; n++)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var value = rng.GetUniformInt(randomMax);
 | 
				
			||||||
 | 
					            freqCheck.CountThis(value);
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            Assert.That(value, Is.GreaterThanOrEqualTo(0));
 | 
				
			||||||
 | 
					            Assert.That(value, Is.LessThanOrEqualTo(randomMax));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        var distribution = freqCheck.NormalizeAndPlotEvents(TestContext.WriteLine);
 | 
				
			||||||
 | 
					        var max = distribution.Max();
 | 
				
			||||||
 | 
					        var min = distribution.Min();
 | 
				
			||||||
 | 
					        Assert.That(max - min, Is.LessThanOrEqualTo(0.27f));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    [Test]
 | 
				
			||||||
 | 
					    [Category(TestCategories.COVER)]
 | 
				
			||||||
 | 
					    [Category(TestCategories.NORMAL)]
 | 
				
			||||||
 | 
					    [Category(TestCategories.INT)]
 | 
				
			||||||
 | 
					    public void MultithreadedGetMinMax()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        var random = new Random();
 | 
				
			||||||
 | 
					        var randomMin = random.Next();
 | 
				
			||||||
 | 
					        int randomMax;
 | 
				
			||||||
 | 
					        do
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            randomMax = random.Next();
 | 
				
			||||||
 | 
					        } while (randomMax < randomMin);
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        using var rng = new MultiThreadedRng<float>();
 | 
				
			||||||
 | 
					        for(var n = 0; n < 10_000; n++)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var value = rng.GetUniformInt(randomMin, randomMax);
 | 
				
			||||||
 | 
					            Assert.That(value, Is.GreaterThanOrEqualTo(randomMin));
 | 
				
			||||||
 | 
					            Assert.That(value, Is.LessThanOrEqualTo(randomMax));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    [Test]
 | 
				
			||||||
 | 
					    [Category(TestCategories.COVER)]
 | 
				
			||||||
 | 
					    [Category(TestCategories.NORMAL)]
 | 
				
			||||||
 | 
					    [Category(TestCategories.INT)]
 | 
				
			||||||
 | 
					    public void MultithreadedGetMinMaxDistributionCheck()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        var random = new Random();
 | 
				
			||||||
 | 
					        var randomMin = random.Next(0, 16);
 | 
				
			||||||
 | 
					        var randomMax = random.Next(randomMin + 10, 33);
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        var freqCheck = new IntFrequencyAnalysis(randomMax - randomMin);
 | 
				
			||||||
 | 
					        using var rng = new MultiThreadedRng<float>();
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        for(var n = 0; n < 10_000; n++)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var value = rng.GetUniformInt(randomMin, randomMax);
 | 
				
			||||||
 | 
					            freqCheck.CountThis(value - randomMin);
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            Assert.That(value, Is.GreaterThanOrEqualTo(randomMin));
 | 
				
			||||||
 | 
					            Assert.That(value, Is.LessThanOrEqualTo(randomMax));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        var distribution = freqCheck.NormalizeAndPlotEvents(TestContext.WriteLine);
 | 
				
			||||||
 | 
					        var max = distribution.Max();
 | 
				
			||||||
 | 
					        var min = distribution.Min();
 | 
				
			||||||
 | 
					        Assert.That(max - min, Is.LessThanOrEqualTo(0.27f));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    [Test]
 | 
				
			||||||
 | 
					    [Category(TestCategories.COVER)]
 | 
				
			||||||
 | 
					    [Category(TestCategories.NORMAL)]
 | 
				
			||||||
 | 
					    [Category(TestCategories.INT)]
 | 
				
			||||||
 | 
					    public void MultithreadedCheckMinMax01()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        var expectedMax = 3;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        var max = int.MinValue;
 | 
				
			||||||
 | 
					        var min = int.MaxValue;
 | 
				
			||||||
 | 
					        using var rng = new MultiThreadedRng<float>();
 | 
				
			||||||
 | 
					        for(var n = 0; n < 10_000; n++)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var value = rng.GetUniformInt(expectedMax);
 | 
				
			||||||
 | 
					            if (value < min)
 | 
				
			||||||
 | 
					                min = value;
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            if (value > max)
 | 
				
			||||||
 | 
					                max = value;
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            Assert.That(value, Is.GreaterThanOrEqualTo(0));
 | 
				
			||||||
 | 
					            Assert.That(value, Is.LessThanOrEqualTo(expectedMax));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        Assert.That(min, Is.EqualTo(0));
 | 
				
			||||||
 | 
					        Assert.That(max, Is.EqualTo(expectedMax - 1));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    [Test]
 | 
				
			||||||
 | 
					    [Category(TestCategories.COVER)]
 | 
				
			||||||
 | 
					    [Category(TestCategories.NORMAL)]
 | 
				
			||||||
 | 
					    [Category(TestCategories.INT)]
 | 
				
			||||||
 | 
					    public void MultithreadedCheckMinMax02()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        var expectedMin = 2;
 | 
				
			||||||
 | 
					        var expectedMax = 6;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        var max = int.MinValue;
 | 
				
			||||||
 | 
					        var min = int.MaxValue;
 | 
				
			||||||
 | 
					        using var rng = new MultiThreadedRng<float>();
 | 
				
			||||||
 | 
					        for(var n = 0; n < 10_000; n++)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var value = rng.GetUniformInt(expectedMin, expectedMax);
 | 
				
			||||||
 | 
					            if (value < min)
 | 
				
			||||||
 | 
					                min = value;
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            if (value > max)
 | 
				
			||||||
 | 
					                max = value;
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            Assert.That(value, Is.GreaterThanOrEqualTo(expectedMin));
 | 
				
			||||||
 | 
					            Assert.That(value, Is.LessThanOrEqualTo(expectedMax));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        Assert.That(min, Is.EqualTo(expectedMin));
 | 
				
			||||||
 | 
					        Assert.That(max, Is.EqualTo(expectedMax - 1));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    #endregion
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -5,6 +5,7 @@ public static class TestCategories
 | 
				
			|||||||
    public const string COVER = "cover";
 | 
					    public const string COVER = "cover";
 | 
				
			||||||
    public const string PERFORMANCE = "performance";
 | 
					    public const string PERFORMANCE = "performance";
 | 
				
			||||||
    public const string NORMAL = "normal";
 | 
					    public const string NORMAL = "normal";
 | 
				
			||||||
 | 
					    public const string INT = "int";
 | 
				
			||||||
    public const string EXAMPLE = "example";
 | 
					    public const string EXAMPLE = "example";
 | 
				
			||||||
    public const string LONG_RUNNING = "long running";
 | 
					    public const string LONG_RUNNING = "long running";
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user