Applied .NET 7 syntax or feature changes
This commit is contained in:
		
							parent
							
								
									38764d5d97
								
							
						
					
					
						commit
						e8cf1284d7
					
				@ -1,17 +1,16 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace FastRng.Distributions
 | 
			
		||||
namespace FastRng.Distributions;
 | 
			
		||||
 | 
			
		||||
public sealed class BetaA2B2 : Distribution
 | 
			
		||||
{
 | 
			
		||||
    public sealed class BetaA2B2 : Distribution
 | 
			
		||||
    private const float ALPHA = 2f;
 | 
			
		||||
    private const float BETA = 2f;
 | 
			
		||||
    private const float CONSTANT = 4f;
 | 
			
		||||
 | 
			
		||||
    public BetaA2B2(IRandom rng) : base(rng)
 | 
			
		||||
    {
 | 
			
		||||
        private const float ALPHA = 2f;
 | 
			
		||||
        private const float BETA = 2f;
 | 
			
		||||
        private const float CONSTANT = 4f;
 | 
			
		||||
 | 
			
		||||
        public BetaA2B2(IRandom rng) : base(rng)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private protected override float ShapeFunction(float x) => CONSTANT * MathF.Pow(x, ALPHA - 1f) * MathF.Pow(1f - x, BETA - 1f);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private protected override float ShapeFunction(float x) => CONSTANT * MathF.Pow(x, ALPHA - 1f) * MathF.Pow(1f - x, BETA - 1f);
 | 
			
		||||
}
 | 
			
		||||
@ -1,17 +1,16 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace FastRng.Distributions
 | 
			
		||||
namespace FastRng.Distributions;
 | 
			
		||||
 | 
			
		||||
public sealed class BetaA2B5 : Distribution
 | 
			
		||||
{
 | 
			
		||||
    public sealed class BetaA2B5 : Distribution
 | 
			
		||||
    private const float ALPHA = 2f;
 | 
			
		||||
    private const float BETA = 5f;
 | 
			
		||||
    private const float CONSTANT = 12.2f;
 | 
			
		||||
 | 
			
		||||
    public BetaA2B5(IRandom rng) : base(rng)
 | 
			
		||||
    {
 | 
			
		||||
        private const float ALPHA = 2f;
 | 
			
		||||
        private const float BETA = 5f;
 | 
			
		||||
        private const float CONSTANT = 12.2f;
 | 
			
		||||
 | 
			
		||||
        public BetaA2B5(IRandom rng) : base(rng)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private protected override float ShapeFunction(float x) => CONSTANT * MathF.Pow(x, ALPHA - 1f) * MathF.Pow(1f - x, BETA - 1f);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private protected override float ShapeFunction(float x) => CONSTANT * MathF.Pow(x, ALPHA - 1f) * MathF.Pow(1f - x, BETA - 1f);
 | 
			
		||||
}
 | 
			
		||||
@ -1,17 +1,16 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace FastRng.Distributions
 | 
			
		||||
{
 | 
			
		||||
    public sealed class BetaA5B2 : Distribution
 | 
			
		||||
    {
 | 
			
		||||
        private const float ALPHA = 5f;
 | 
			
		||||
        private const float BETA = 2f;
 | 
			
		||||
        private const float CONSTANT = 12.2f;
 | 
			
		||||
namespace FastRng.Distributions;
 | 
			
		||||
 | 
			
		||||
        public BetaA5B2(IRandom rng) : base(rng)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        private protected override float ShapeFunction(float x) => CONSTANT * MathF.Pow(x, ALPHA - 1f) * MathF.Pow(1f - x, BETA - 1f);
 | 
			
		||||
public sealed class BetaA5B2 : Distribution
 | 
			
		||||
{
 | 
			
		||||
    private const float ALPHA = 5f;
 | 
			
		||||
    private const float BETA = 2f;
 | 
			
		||||
    private const float CONSTANT = 12.2f;
 | 
			
		||||
 | 
			
		||||
    public BetaA5B2(IRandom rng) : base(rng)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    private protected override float ShapeFunction(float x) => CONSTANT * MathF.Pow(x, ALPHA - 1f) * MathF.Pow(1f - x, BETA - 1f);
 | 
			
		||||
}
 | 
			
		||||
@ -1,17 +1,16 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace FastRng.Distributions
 | 
			
		||||
namespace FastRng.Distributions;
 | 
			
		||||
 | 
			
		||||
public sealed class CauchyLorentzX0 : Distribution
 | 
			
		||||
{
 | 
			
		||||
    public sealed class CauchyLorentzX0 : Distribution
 | 
			
		||||
    private const float CONSTANT = 0.31f;
 | 
			
		||||
    private const float SCALE = 0.1f;
 | 
			
		||||
    private const float MEDIAN = 0.0f;
 | 
			
		||||
 | 
			
		||||
    public CauchyLorentzX0(IRandom rng) : base(rng)
 | 
			
		||||
    {
 | 
			
		||||
        private const float CONSTANT = 0.31f;
 | 
			
		||||
        private const float SCALE = 0.1f;
 | 
			
		||||
        private const float MEDIAN = 0.0f;
 | 
			
		||||
 | 
			
		||||
        public CauchyLorentzX0(IRandom rng) : base(rng)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private protected override float ShapeFunction(float x) => CONSTANT * (1.0f / (MathF.PI * SCALE)) * ((SCALE * SCALE) / (MathF.Pow(x - MEDIAN, 2f) + (SCALE * SCALE)));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private protected override float ShapeFunction(float x) => CONSTANT * (1.0f / (MathF.PI * SCALE)) * ((SCALE * SCALE) / (MathF.Pow(x - MEDIAN, 2f) + (SCALE * SCALE)));
 | 
			
		||||
}
 | 
			
		||||
@ -1,17 +1,16 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace FastRng.Distributions
 | 
			
		||||
namespace FastRng.Distributions;
 | 
			
		||||
 | 
			
		||||
public sealed class CauchyLorentzX1 : Distribution
 | 
			
		||||
{
 | 
			
		||||
    public sealed class CauchyLorentzX1 : Distribution
 | 
			
		||||
    private const float CONSTANT = 0.31f;
 | 
			
		||||
    private const float SCALE = 0.1f;
 | 
			
		||||
    private const float MEDIAN = 1.0f;
 | 
			
		||||
 | 
			
		||||
    public CauchyLorentzX1(IRandom rng) : base(rng)
 | 
			
		||||
    {
 | 
			
		||||
        private const float CONSTANT = 0.31f;
 | 
			
		||||
        private const float SCALE = 0.1f;
 | 
			
		||||
        private const float MEDIAN = 1.0f;
 | 
			
		||||
 | 
			
		||||
        public CauchyLorentzX1(IRandom rng) : base(rng)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private protected override float ShapeFunction(float x) => CONSTANT * (1.0f / (MathF.PI * SCALE)) * ((SCALE * SCALE) / (MathF.Pow(x - MEDIAN, 2f) + (SCALE * SCALE)));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private protected override float ShapeFunction(float x) => CONSTANT * (1.0f / (MathF.PI * SCALE)) * ((SCALE * SCALE) / (MathF.Pow(x - MEDIAN, 2f) + (SCALE * SCALE)));
 | 
			
		||||
}
 | 
			
		||||
@ -1,27 +1,26 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace FastRng.Distributions
 | 
			
		||||
namespace FastRng.Distributions;
 | 
			
		||||
 | 
			
		||||
public sealed class ChiSquareK1 : Distribution
 | 
			
		||||
{
 | 
			
		||||
    public sealed class ChiSquareK1 : Distribution
 | 
			
		||||
    private const float K = 1.0f;
 | 
			
		||||
    private const float K_HALF = K * 0.5f;
 | 
			
		||||
    private const float K_HALF_MINUS_ONE = K_HALF - 1.0f;
 | 
			
		||||
    private const float CONSTANT = 0.252f;
 | 
			
		||||
 | 
			
		||||
    private static readonly float DIVISOR;
 | 
			
		||||
        
 | 
			
		||||
    static ChiSquareK1()
 | 
			
		||||
    {
 | 
			
		||||
        private const float K = 1.0f;
 | 
			
		||||
        private const float K_HALF = K * 0.5f;
 | 
			
		||||
        private const float K_HALF_MINUS_ONE = K_HALF - 1.0f;
 | 
			
		||||
        private const float CONSTANT = 0.252f;
 | 
			
		||||
 | 
			
		||||
        private static readonly float DIVISOR;
 | 
			
		||||
        
 | 
			
		||||
        static ChiSquareK1()
 | 
			
		||||
        {
 | 
			
		||||
            var twoToTheKHalf = MathF.Pow(2f, K_HALF);
 | 
			
		||||
            var gammaKHalf = MathTools.Gamma(K_HALF);
 | 
			
		||||
            DIVISOR = twoToTheKHalf * gammaKHalf;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        public ChiSquareK1(IRandom rng) : base(rng)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private protected override float ShapeFunction(float x) => CONSTANT * ((MathF.Pow(x, K_HALF_MINUS_ONE) * MathF.Exp(-x * 0.5f)) / DIVISOR);
 | 
			
		||||
        var twoToTheKHalf = MathF.Pow(2f, K_HALF);
 | 
			
		||||
        var gammaKHalf = MathTools.Gamma(K_HALF);
 | 
			
		||||
        DIVISOR = twoToTheKHalf * gammaKHalf;
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    public ChiSquareK1(IRandom rng) : base(rng)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private protected override float ShapeFunction(float x) => CONSTANT * ((MathF.Pow(x, K_HALF_MINUS_ONE) * MathF.Exp(-x * 0.5f)) / DIVISOR);
 | 
			
		||||
}
 | 
			
		||||
@ -1,27 +1,26 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace FastRng.Distributions
 | 
			
		||||
namespace FastRng.Distributions;
 | 
			
		||||
 | 
			
		||||
public sealed class ChiSquareK10 : Distribution
 | 
			
		||||
{
 | 
			
		||||
    public sealed class ChiSquareK10 : Distribution
 | 
			
		||||
    private const float K = 10.0f;
 | 
			
		||||
    private const float K_HALF = K * 0.5f;
 | 
			
		||||
    private const float K_HALF_MINUS_ONE = K_HALF - 1.0f;
 | 
			
		||||
    private const float CONSTANT = 0.252f;
 | 
			
		||||
 | 
			
		||||
    private static readonly float DIVISOR;
 | 
			
		||||
        
 | 
			
		||||
    static ChiSquareK10()
 | 
			
		||||
    {
 | 
			
		||||
        private const float K = 10.0f;
 | 
			
		||||
        private const float K_HALF = K * 0.5f;
 | 
			
		||||
        private const float K_HALF_MINUS_ONE = K_HALF - 1.0f;
 | 
			
		||||
        private const float CONSTANT = 0.252f;
 | 
			
		||||
 | 
			
		||||
        private static readonly float DIVISOR;
 | 
			
		||||
        
 | 
			
		||||
        static ChiSquareK10()
 | 
			
		||||
        {
 | 
			
		||||
            var twoToTheKHalf = MathF.Pow(2f, K_HALF);
 | 
			
		||||
            var gammaKHalf = MathTools.Gamma(K_HALF);
 | 
			
		||||
            DIVISOR = twoToTheKHalf * gammaKHalf;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        public ChiSquareK10(IRandom rng) : base(rng)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private protected override float ShapeFunction(float x) => CONSTANT * ((MathF.Pow(x, K_HALF_MINUS_ONE) * MathF.Exp(-x * 0.5f)) / DIVISOR);
 | 
			
		||||
        var twoToTheKHalf = MathF.Pow(2f, K_HALF);
 | 
			
		||||
        var gammaKHalf = MathTools.Gamma(K_HALF);
 | 
			
		||||
        DIVISOR = twoToTheKHalf * gammaKHalf;
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    public ChiSquareK10(IRandom rng) : base(rng)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private protected override float ShapeFunction(float x) => CONSTANT * ((MathF.Pow(x, K_HALF_MINUS_ONE) * MathF.Exp(-x * 0.5f)) / DIVISOR);
 | 
			
		||||
}
 | 
			
		||||
@ -1,27 +1,26 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace FastRng.Distributions
 | 
			
		||||
namespace FastRng.Distributions;
 | 
			
		||||
 | 
			
		||||
public sealed class ChiSquareK4 : Distribution
 | 
			
		||||
{
 | 
			
		||||
    public sealed class ChiSquareK4 : Distribution
 | 
			
		||||
    {
 | 
			
		||||
        private const float K = 4.0f;
 | 
			
		||||
        private const float K_HALF = K * 0.5f;
 | 
			
		||||
        private const float K_HALF_MINUS_ONE = K_HALF - 1.0f;
 | 
			
		||||
        private const float CONSTANT = 0.252f;
 | 
			
		||||
    private const float K = 4.0f;
 | 
			
		||||
    private const float K_HALF = K * 0.5f;
 | 
			
		||||
    private const float K_HALF_MINUS_ONE = K_HALF - 1.0f;
 | 
			
		||||
    private const float CONSTANT = 0.252f;
 | 
			
		||||
 | 
			
		||||
        private static readonly float DIVISOR;
 | 
			
		||||
    private static readonly float DIVISOR;
 | 
			
		||||
        
 | 
			
		||||
        static ChiSquareK4()
 | 
			
		||||
        {
 | 
			
		||||
            var twoToTheKHalf = MathF.Pow(2, K_HALF);
 | 
			
		||||
            var gammaKHalf = MathTools.Gamma(K_HALF);
 | 
			
		||||
            DIVISOR = twoToTheKHalf * gammaKHalf;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public ChiSquareK4(IRandom rng) : base(rng)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private protected override float ShapeFunction(float x) => CONSTANT * ((MathF.Pow(x, K_HALF_MINUS_ONE) * MathF.Exp(-x * 0.5f)) / DIVISOR);
 | 
			
		||||
    static ChiSquareK4()
 | 
			
		||||
    {
 | 
			
		||||
        var twoToTheKHalf = MathF.Pow(2, K_HALF);
 | 
			
		||||
        var gammaKHalf = MathTools.Gamma(K_HALF);
 | 
			
		||||
        DIVISOR = twoToTheKHalf * gammaKHalf;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public ChiSquareK4(IRandom rng) : base(rng)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private protected override float ShapeFunction(float x) => CONSTANT * ((MathF.Pow(x, K_HALF_MINUS_ONE) * MathF.Exp(-x * 0.5f)) / DIVISOR);
 | 
			
		||||
}
 | 
			
		||||
@ -2,74 +2,62 @@ using System;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace FastRng.Distributions
 | 
			
		||||
namespace FastRng.Distributions;
 | 
			
		||||
 | 
			
		||||
public abstract class Distribution : IDistribution
 | 
			
		||||
{
 | 
			
		||||
    public abstract class Distribution : IDistribution
 | 
			
		||||
    private readonly ShapeFitter fitter;
 | 
			
		||||
 | 
			
		||||
    protected Distribution(IRandom rng)
 | 
			
		||||
    {
 | 
			
		||||
        private readonly ShapeFitter fitter;
 | 
			
		||||
        private readonly IRandom random;
 | 
			
		||||
 | 
			
		||||
        protected Distribution(IRandom rng)
 | 
			
		||||
        {
 | 
			
		||||
            if (rng == null)
 | 
			
		||||
                throw new ArgumentNullException(nameof(rng), "An IRandom implementation is needed.");
 | 
			
		||||
                
 | 
			
		||||
            this.random = rng;
 | 
			
		||||
            this.fitter = new ShapeFitter(this.ShapeFunction, this.random, 100);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private protected abstract float ShapeFunction(float x);
 | 
			
		||||
        if (rng == null)
 | 
			
		||||
            throw new ArgumentNullException(nameof(rng), "An IRandom implementation is needed.");
 | 
			
		||||
        
 | 
			
		||||
        public async ValueTask<float> GetDistributedValue(CancellationToken token = default) => await this.fitter.NextNumber(token);
 | 
			
		||||
        this.fitter = new ShapeFitter(this.ShapeFunction, rng, 100);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private protected abstract float ShapeFunction(float x);
 | 
			
		||||
        
 | 
			
		||||
        public async ValueTask<uint> NextNumber(uint rangeStart, uint rangeEnd, CancellationToken cancel = default)
 | 
			
		||||
        {
 | 
			
		||||
            if (rangeStart > rangeEnd)
 | 
			
		||||
            {
 | 
			
		||||
                var tmp = rangeStart;
 | 
			
		||||
                rangeStart = rangeEnd;
 | 
			
		||||
                rangeEnd = tmp;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            var range = rangeEnd - rangeStart;
 | 
			
		||||
            var distributedValue = await this.GetDistributedValue(cancel);
 | 
			
		||||
            return (uint) ((distributedValue * range) + rangeStart);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public async ValueTask<ulong> NextNumber(ulong rangeStart, ulong rangeEnd, CancellationToken cancel = default(CancellationToken))
 | 
			
		||||
        {
 | 
			
		||||
            if (rangeStart > rangeEnd)
 | 
			
		||||
            {
 | 
			
		||||
                var tmp = rangeStart;
 | 
			
		||||
                rangeStart = rangeEnd;
 | 
			
		||||
                rangeEnd = tmp;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            var range = rangeEnd - rangeStart;
 | 
			
		||||
            var distributedValue = await this.GetDistributedValue(cancel);
 | 
			
		||||
            return (ulong) ((distributedValue * range) + rangeStart);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public async ValueTask<float> NextNumber(float rangeStart, float rangeEnd, CancellationToken cancel = default(CancellationToken))
 | 
			
		||||
        {
 | 
			
		||||
            if (rangeStart > rangeEnd)
 | 
			
		||||
            {
 | 
			
		||||
                var tmp = rangeStart;
 | 
			
		||||
                rangeStart = rangeEnd;
 | 
			
		||||
                rangeEnd = tmp;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            var range = rangeEnd - rangeStart;
 | 
			
		||||
            var distributedValue = await this.GetDistributedValue(cancel);
 | 
			
		||||
            return (distributedValue * range) + rangeStart;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public async ValueTask<float> NextNumber(CancellationToken cancel = default) => await this.NextNumber(0.0f, 1.0f, cancel);
 | 
			
		||||
    public async ValueTask<float> GetDistributedValue(CancellationToken token = default) => await this.fitter.NextNumber(token);
 | 
			
		||||
        
 | 
			
		||||
        public async ValueTask<bool> HasDecisionBeenMade(float above, float below = 1, CancellationToken cancel = default)
 | 
			
		||||
        {
 | 
			
		||||
            var number = await this.NextNumber(cancel);
 | 
			
		||||
            return number > above && number < below;
 | 
			
		||||
        }
 | 
			
		||||
    public async ValueTask<uint> NextNumber(uint rangeStart, uint rangeEnd, CancellationToken cancel = default)
 | 
			
		||||
    {
 | 
			
		||||
        // Swap the values if the range start is greater than the range end:
 | 
			
		||||
        if (rangeStart > rangeEnd)
 | 
			
		||||
            (rangeStart, rangeEnd) = (rangeEnd, rangeStart);
 | 
			
		||||
 | 
			
		||||
        var range = rangeEnd - rangeStart;
 | 
			
		||||
        var distributedValue = await this.GetDistributedValue(cancel);
 | 
			
		||||
        return (uint) ((distributedValue * range) + rangeStart);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public async ValueTask<ulong> NextNumber(ulong rangeStart, ulong rangeEnd, CancellationToken cancel = default)
 | 
			
		||||
    {
 | 
			
		||||
        // Swap the values if the range start is greater than the range end:
 | 
			
		||||
        if (rangeStart > rangeEnd)
 | 
			
		||||
            (rangeStart, rangeEnd) = (rangeEnd, rangeStart);
 | 
			
		||||
 | 
			
		||||
        var range = rangeEnd - rangeStart;
 | 
			
		||||
        var distributedValue = await this.GetDistributedValue(cancel);
 | 
			
		||||
        return (ulong) ((distributedValue * range) + rangeStart);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public async ValueTask<float> NextNumber(float rangeStart, float rangeEnd, CancellationToken cancel = default)
 | 
			
		||||
    {
 | 
			
		||||
        // Swap the values if the range start is greater than the range end:
 | 
			
		||||
        if (rangeStart > rangeEnd)
 | 
			
		||||
            (rangeStart, rangeEnd) = (rangeEnd, rangeStart);
 | 
			
		||||
 | 
			
		||||
        var range = rangeEnd - rangeStart;
 | 
			
		||||
        var distributedValue = await this.GetDistributedValue(cancel);
 | 
			
		||||
        return (distributedValue * range) + rangeStart;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public async ValueTask<float> NextNumber(CancellationToken cancel = default) => await this.NextNumber(0.0f, 1.0f, cancel);
 | 
			
		||||
        
 | 
			
		||||
    public async ValueTask<bool> HasDecisionBeenMade(float above, float below = 1, CancellationToken cancel = default)
 | 
			
		||||
    {
 | 
			
		||||
        var number = await this.NextNumber(cancel);
 | 
			
		||||
        return number > above && number < below;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,16 +1,15 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace FastRng.Distributions
 | 
			
		||||
namespace FastRng.Distributions;
 | 
			
		||||
 | 
			
		||||
public sealed class ExponentialLa10 : Distribution
 | 
			
		||||
{
 | 
			
		||||
    public sealed class ExponentialLa10 : Distribution
 | 
			
		||||
    private const float LAMBDA = 10.0f;
 | 
			
		||||
    private const float CONSTANT = 0.1106f;
 | 
			
		||||
 | 
			
		||||
    public ExponentialLa10(IRandom rng) : base(rng)
 | 
			
		||||
    {
 | 
			
		||||
        private const float LAMBDA = 10.0f;
 | 
			
		||||
        private const float CONSTANT = 0.1106f;
 | 
			
		||||
 | 
			
		||||
        public ExponentialLa10(IRandom rng) : base(rng)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private protected override float ShapeFunction(float x) => CONSTANT * LAMBDA * MathF.Exp(-LAMBDA * x);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private protected override float ShapeFunction(float x) => CONSTANT * LAMBDA * MathF.Exp(-LAMBDA * x);
 | 
			
		||||
}
 | 
			
		||||
@ -1,16 +1,15 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace FastRng.Distributions
 | 
			
		||||
namespace FastRng.Distributions;
 | 
			
		||||
 | 
			
		||||
public sealed class ExponentialLa5 : Distribution
 | 
			
		||||
{
 | 
			
		||||
    public sealed class ExponentialLa5 : Distribution
 | 
			
		||||
    private const float LAMBDA = 5.0f;
 | 
			
		||||
    private const float CONSTANT = 0.2103f;
 | 
			
		||||
 | 
			
		||||
    public ExponentialLa5(IRandom rng) : base(rng)
 | 
			
		||||
    {
 | 
			
		||||
        private const float LAMBDA = 5.0f;
 | 
			
		||||
        private const float CONSTANT = 0.2103f;
 | 
			
		||||
 | 
			
		||||
        public ExponentialLa5(IRandom rng) : base(rng)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private protected override float ShapeFunction(float x) => CONSTANT * LAMBDA * MathF.Exp(-LAMBDA * x);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private protected override float ShapeFunction(float x) => CONSTANT * LAMBDA * MathF.Exp(-LAMBDA * x);
 | 
			
		||||
}
 | 
			
		||||
@ -1,26 +1,25 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace FastRng.Distributions
 | 
			
		||||
namespace FastRng.Distributions;
 | 
			
		||||
 | 
			
		||||
public sealed class GammaA5B15 : Distribution
 | 
			
		||||
{
 | 
			
		||||
    public sealed class GammaA5B15 : Distribution
 | 
			
		||||
    {
 | 
			
		||||
        private const float ALPHA = 5.0f;
 | 
			
		||||
        private const float BETA = 15.0f;
 | 
			
		||||
        private const float CONSTANT = 0.341344210715475f;
 | 
			
		||||
    private const float ALPHA = 5.0f;
 | 
			
		||||
    private const float BETA = 15.0f;
 | 
			
		||||
    private const float CONSTANT = 0.341344210715475f;
 | 
			
		||||
 | 
			
		||||
        private static readonly float GAMMA_ALPHA;
 | 
			
		||||
        private static readonly float BETA_TO_THE_ALPHA;
 | 
			
		||||
    private static readonly float GAMMA_ALPHA;
 | 
			
		||||
    private static readonly float BETA_TO_THE_ALPHA;
 | 
			
		||||
        
 | 
			
		||||
        static GammaA5B15()
 | 
			
		||||
        {
 | 
			
		||||
            GAMMA_ALPHA = MathTools.Gamma(ALPHA);
 | 
			
		||||
            BETA_TO_THE_ALPHA = MathF.Pow(BETA, ALPHA);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public GammaA5B15(IRandom rng) : base(rng)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private protected override float ShapeFunction(float x) => CONSTANT * ((BETA_TO_THE_ALPHA * MathF.Pow(x, ALPHA - 1.0f) * MathF.Exp(-BETA * x)) / GAMMA_ALPHA);
 | 
			
		||||
    static GammaA5B15()
 | 
			
		||||
    {
 | 
			
		||||
        GAMMA_ALPHA = MathTools.Gamma(ALPHA);
 | 
			
		||||
        BETA_TO_THE_ALPHA = MathF.Pow(BETA, ALPHA);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public GammaA5B15(IRandom rng) : base(rng)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private protected override float ShapeFunction(float x) => CONSTANT * ((BETA_TO_THE_ALPHA * MathF.Pow(x, ALPHA - 1.0f) * MathF.Exp(-BETA * x)) / GAMMA_ALPHA);
 | 
			
		||||
}
 | 
			
		||||
@ -1,20 +1,19 @@
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace FastRng.Distributions
 | 
			
		||||
namespace FastRng.Distributions;
 | 
			
		||||
 | 
			
		||||
public interface IDistribution
 | 
			
		||||
{
 | 
			
		||||
    public interface IDistribution
 | 
			
		||||
    {
 | 
			
		||||
        public ValueTask<float> GetDistributedValue(CancellationToken token);
 | 
			
		||||
    public ValueTask<float> GetDistributedValue(CancellationToken token);
 | 
			
		||||
        
 | 
			
		||||
        public ValueTask<uint> NextNumber(uint rangeStart, uint rangeEnd, CancellationToken cancel = default);
 | 
			
		||||
    public ValueTask<uint> NextNumber(uint rangeStart, uint rangeEnd, CancellationToken cancel = default);
 | 
			
		||||
        
 | 
			
		||||
        public ValueTask<ulong> NextNumber(ulong rangeStart, ulong rangeEnd, CancellationToken cancel = default);
 | 
			
		||||
    public ValueTask<ulong> NextNumber(ulong rangeStart, ulong rangeEnd, CancellationToken cancel = default);
 | 
			
		||||
        
 | 
			
		||||
        public ValueTask<float> NextNumber(float rangeStart, float rangeEnd, CancellationToken cancel = default);
 | 
			
		||||
    public ValueTask<float> NextNumber(float rangeStart, float rangeEnd, CancellationToken cancel = default);
 | 
			
		||||
        
 | 
			
		||||
        public ValueTask<float> NextNumber(CancellationToken cancel = default);
 | 
			
		||||
    public ValueTask<float> NextNumber(CancellationToken cancel = default);
 | 
			
		||||
        
 | 
			
		||||
        public ValueTask<bool> HasDecisionBeenMade(float above, float below = 1.0f, CancellationToken cancel = default);
 | 
			
		||||
    }
 | 
			
		||||
    public ValueTask<bool> HasDecisionBeenMade(float above, float below = 1.0f, CancellationToken cancel = default);
 | 
			
		||||
}
 | 
			
		||||
@ -1,16 +1,15 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace FastRng.Distributions
 | 
			
		||||
namespace FastRng.Distributions;
 | 
			
		||||
 | 
			
		||||
public sealed class InverseExponentialLa10 : Distribution
 | 
			
		||||
{
 | 
			
		||||
    public sealed class InverseExponentialLa10 : Distribution
 | 
			
		||||
    private const float LAMBDA = 10.0f;
 | 
			
		||||
    private const float CONSTANT = 4.539992976248453e-06f;
 | 
			
		||||
 | 
			
		||||
    public InverseExponentialLa10(IRandom rng) : base(rng)
 | 
			
		||||
    {
 | 
			
		||||
        private const float LAMBDA = 10.0f;
 | 
			
		||||
        private const float CONSTANT = 4.539992976248453e-06f;
 | 
			
		||||
 | 
			
		||||
        public InverseExponentialLa10(IRandom rng) : base(rng)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private protected override float ShapeFunction(float x) => CONSTANT * LAMBDA * MathF.Exp(LAMBDA * x);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private protected override float ShapeFunction(float x) => CONSTANT * LAMBDA * MathF.Exp(LAMBDA * x);
 | 
			
		||||
}
 | 
			
		||||
@ -1,16 +1,15 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace FastRng.Distributions
 | 
			
		||||
namespace FastRng.Distributions;
 | 
			
		||||
 | 
			
		||||
public sealed class InverseExponentialLa5 : Distribution
 | 
			
		||||
{
 | 
			
		||||
    public sealed class InverseExponentialLa5 : Distribution
 | 
			
		||||
    private const float LAMBDA = 5.0f;
 | 
			
		||||
    private const float CONSTANT = 0.001347589399817f;
 | 
			
		||||
 | 
			
		||||
    public InverseExponentialLa5(IRandom rng) : base(rng)
 | 
			
		||||
    {
 | 
			
		||||
        private const float LAMBDA = 5.0f;
 | 
			
		||||
        private const float CONSTANT = 0.001347589399817f;
 | 
			
		||||
 | 
			
		||||
        public InverseExponentialLa5(IRandom rng) : base(rng)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private protected override float ShapeFunction(float x) => CONSTANT * LAMBDA * MathF.Exp(LAMBDA * x);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private protected override float ShapeFunction(float x) => CONSTANT * LAMBDA * MathF.Exp(LAMBDA * x);
 | 
			
		||||
}
 | 
			
		||||
@ -1,27 +1,26 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace FastRng.Distributions
 | 
			
		||||
namespace FastRng.Distributions;
 | 
			
		||||
 | 
			
		||||
public sealed class InverseGammaA3B05 : Distribution
 | 
			
		||||
{
 | 
			
		||||
    public sealed class InverseGammaA3B05 : Distribution
 | 
			
		||||
    private const float ALPHA = 3.0f;
 | 
			
		||||
    private const float BETA = 0.5f;
 | 
			
		||||
    private const float CONSTANT = 0.213922656884911f;
 | 
			
		||||
 | 
			
		||||
    private static readonly float FACTOR_LEFT;
 | 
			
		||||
        
 | 
			
		||||
    static InverseGammaA3B05()
 | 
			
		||||
    {
 | 
			
		||||
        private const float ALPHA = 3.0f;
 | 
			
		||||
        private const float BETA = 0.5f;
 | 
			
		||||
        private const float CONSTANT = 0.213922656884911f;
 | 
			
		||||
 | 
			
		||||
        private static readonly float FACTOR_LEFT;
 | 
			
		||||
        
 | 
			
		||||
        static InverseGammaA3B05()
 | 
			
		||||
        {
 | 
			
		||||
            var gammaAlpha = MathTools.Gamma(ALPHA);
 | 
			
		||||
            var betaToTheAlpha = MathF.Pow(BETA, ALPHA);
 | 
			
		||||
        var gammaAlpha = MathTools.Gamma(ALPHA);
 | 
			
		||||
        var betaToTheAlpha = MathF.Pow(BETA, ALPHA);
 | 
			
		||||
            
 | 
			
		||||
            FACTOR_LEFT = CONSTANT * (betaToTheAlpha / gammaAlpha);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        public InverseGammaA3B05(IRandom rng) : base(rng)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private protected override float ShapeFunction(float x) => FACTOR_LEFT * MathF.Pow(x, -ALPHA - 1.0f) * MathF.Exp(-BETA / x);
 | 
			
		||||
        FACTOR_LEFT = CONSTANT * (betaToTheAlpha / gammaAlpha);
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    public InverseGammaA3B05(IRandom rng) : base(rng)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private protected override float ShapeFunction(float x) => FACTOR_LEFT * MathF.Pow(x, -ALPHA - 1.0f) * MathF.Exp(-BETA / x);
 | 
			
		||||
}
 | 
			
		||||
@ -1,24 +1,23 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace FastRng.Distributions
 | 
			
		||||
{
 | 
			
		||||
    public sealed class LaplaceB01M0 : Distribution
 | 
			
		||||
    {
 | 
			
		||||
        private const float B = 0.1f;
 | 
			
		||||
        private const float MU = 0.0f;
 | 
			
		||||
        private const float CONSTANT = 0.221034183615129f;
 | 
			
		||||
        
 | 
			
		||||
        private static readonly float FACTOR_LEFT;
 | 
			
		||||
        
 | 
			
		||||
        static LaplaceB01M0()
 | 
			
		||||
        {
 | 
			
		||||
            FACTOR_LEFT = CONSTANT / (2.0f * B);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        public LaplaceB01M0(IRandom rng) : base(rng)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
namespace FastRng.Distributions;
 | 
			
		||||
 | 
			
		||||
        private protected override float ShapeFunction(float x) => FACTOR_LEFT * MathF.Exp(-MathF.Abs(x - MU) / B);
 | 
			
		||||
public sealed class LaplaceB01M0 : Distribution
 | 
			
		||||
{
 | 
			
		||||
    private const float B = 0.1f;
 | 
			
		||||
    private const float MU = 0.0f;
 | 
			
		||||
    private const float CONSTANT = 0.221034183615129f;
 | 
			
		||||
        
 | 
			
		||||
    private static readonly float FACTOR_LEFT;
 | 
			
		||||
        
 | 
			
		||||
    static LaplaceB01M0()
 | 
			
		||||
    {
 | 
			
		||||
        FACTOR_LEFT = CONSTANT / (2.0f * B);
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    public LaplaceB01M0(IRandom rng) : base(rng)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private protected override float ShapeFunction(float x) => FACTOR_LEFT * MathF.Exp(-MathF.Abs(x - MU) / B);
 | 
			
		||||
}
 | 
			
		||||
@ -1,24 +1,23 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace FastRng.Distributions
 | 
			
		||||
{
 | 
			
		||||
    public sealed class LaplaceB01M05 : Distribution
 | 
			
		||||
    {
 | 
			
		||||
        private const float B = 0.1f;
 | 
			
		||||
        private const float MU = 0.5f;
 | 
			
		||||
        private const float CONSTANT = 0.2f;
 | 
			
		||||
        
 | 
			
		||||
        private static readonly float FACTOR_LEFT;
 | 
			
		||||
        
 | 
			
		||||
        static LaplaceB01M05()
 | 
			
		||||
        {
 | 
			
		||||
            FACTOR_LEFT = CONSTANT / (2.0f * B);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        public LaplaceB01M05(IRandom rng) : base(rng)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
namespace FastRng.Distributions;
 | 
			
		||||
 | 
			
		||||
        private protected override float ShapeFunction(float x) => FACTOR_LEFT * MathF.Exp(-MathF.Abs(x - MU) / B);
 | 
			
		||||
public sealed class LaplaceB01M05 : Distribution
 | 
			
		||||
{
 | 
			
		||||
    private const float B = 0.1f;
 | 
			
		||||
    private const float MU = 0.5f;
 | 
			
		||||
    private const float CONSTANT = 0.2f;
 | 
			
		||||
        
 | 
			
		||||
    private static readonly float FACTOR_LEFT;
 | 
			
		||||
        
 | 
			
		||||
    static LaplaceB01M05()
 | 
			
		||||
    {
 | 
			
		||||
        FACTOR_LEFT = CONSTANT / (2.0f * B);
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    public LaplaceB01M05(IRandom rng) : base(rng)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private protected override float ShapeFunction(float x) => FACTOR_LEFT * MathF.Exp(-MathF.Abs(x - MU) / B);
 | 
			
		||||
}
 | 
			
		||||
@ -1,24 +1,23 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace FastRng.Distributions
 | 
			
		||||
{
 | 
			
		||||
    public sealed class LogNormalS1M0 : Distribution
 | 
			
		||||
    {
 | 
			
		||||
        private const float SIGMA = 1.0f;
 | 
			
		||||
        private const float MU = 0.0f;
 | 
			
		||||
        private const float CONSTANT = 1.51998658387455f;
 | 
			
		||||
        
 | 
			
		||||
        private static readonly float FACTOR;
 | 
			
		||||
        
 | 
			
		||||
        static LogNormalS1M0()
 | 
			
		||||
        {
 | 
			
		||||
            FACTOR = SIGMA * MathF.Sqrt(2f * MathF.PI);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        public LogNormalS1M0(IRandom rng) : base(rng)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
namespace FastRng.Distributions;
 | 
			
		||||
 | 
			
		||||
        private protected override float ShapeFunction(float x) => (CONSTANT / (x * FACTOR)) * MathF.Exp( -(MathF.Pow(MathF.Log(x) - MU, 2f) / (2f * MathF.Pow(SIGMA, 2f))));
 | 
			
		||||
public sealed class LogNormalS1M0 : Distribution
 | 
			
		||||
{
 | 
			
		||||
    private const float SIGMA = 1.0f;
 | 
			
		||||
    private const float MU = 0.0f;
 | 
			
		||||
    private const float CONSTANT = 1.51998658387455f;
 | 
			
		||||
        
 | 
			
		||||
    private static readonly float FACTOR;
 | 
			
		||||
        
 | 
			
		||||
    static LogNormalS1M0()
 | 
			
		||||
    {
 | 
			
		||||
        FACTOR = SIGMA * MathF.Sqrt(2f * MathF.PI);
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    public LogNormalS1M0(IRandom rng) : base(rng)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private protected override float ShapeFunction(float x) => (CONSTANT / (x * FACTOR)) * MathF.Exp( -(MathF.Pow(MathF.Log(x) - MU, 2f) / (2f * MathF.Pow(SIGMA, 2f))));
 | 
			
		||||
}
 | 
			
		||||
@ -1,17 +1,16 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace FastRng.Distributions
 | 
			
		||||
namespace FastRng.Distributions;
 | 
			
		||||
 | 
			
		||||
public sealed class NormalS02M05 : Distribution
 | 
			
		||||
{
 | 
			
		||||
    public sealed class NormalS02M05 : Distribution
 | 
			
		||||
    private const float SQRT_2_PI = 2.506628275f;
 | 
			
		||||
    private const float STD_DEV = 0.2f;
 | 
			
		||||
    private const float MEAN = 0.5f;
 | 
			
		||||
 | 
			
		||||
    public NormalS02M05(IRandom rng) : base(rng)
 | 
			
		||||
    {
 | 
			
		||||
        private const float SQRT_2_PI = 2.506628275f;
 | 
			
		||||
        private const float STDDEV = 0.2f;
 | 
			
		||||
        private const float MEAN = 0.5f;
 | 
			
		||||
 | 
			
		||||
        public NormalS02M05(IRandom rng) : base(rng)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private protected override float ShapeFunction(float x) => 1.0f / (STDDEV * SQRT_2_PI) * MathF.Exp(-0.5f * MathF.Pow((x - MEAN) / STDDEV, 2.0f));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private protected override float ShapeFunction(float x) => 1.0f / (STD_DEV * SQRT_2_PI) * MathF.Exp(-0.5f * MathF.Pow((x - MEAN) / STD_DEV, 2.0f));
 | 
			
		||||
}
 | 
			
		||||
@ -1,29 +1,28 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace FastRng.Distributions
 | 
			
		||||
{
 | 
			
		||||
    public sealed class StudentTNu1 : Distribution
 | 
			
		||||
    {
 | 
			
		||||
        private const float NU = 1.0f;
 | 
			
		||||
        private const float START = 0.0f;
 | 
			
		||||
        private const float COMPRESS = 1.0f;
 | 
			
		||||
        private const float CONSTANT = 3.14190548592729f;
 | 
			
		||||
        
 | 
			
		||||
        private static readonly float DIVIDEND;
 | 
			
		||||
        private static readonly float DIVISOR;
 | 
			
		||||
        private static readonly float EXPONENT;
 | 
			
		||||
        
 | 
			
		||||
        static StudentTNu1()
 | 
			
		||||
        {
 | 
			
		||||
            DIVIDEND = MathTools.Gamma((NU + 1.0f) * 0.5f);
 | 
			
		||||
            DIVISOR = MathF.Sqrt(NU * MathF.PI) * MathTools.Gamma(NU * 0.5f);
 | 
			
		||||
            EXPONENT = -((NU + 1.0f) * 0.5f);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        public StudentTNu1(IRandom rng) : base(rng)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
namespace FastRng.Distributions;
 | 
			
		||||
 | 
			
		||||
        private protected override float ShapeFunction(float x) => CONSTANT * MathF.Pow((DIVIDEND / DIVISOR) * MathF.Pow(1.0f + MathF.Pow(START + x * COMPRESS, 2f) / NU, EXPONENT), COMPRESS);
 | 
			
		||||
public sealed class StudentTNu1 : Distribution
 | 
			
		||||
{
 | 
			
		||||
    private const float NU = 1.0f;
 | 
			
		||||
    private const float START = 0.0f;
 | 
			
		||||
    private const float COMPRESS = 1.0f;
 | 
			
		||||
    private const float CONSTANT = 3.14190548592729f;
 | 
			
		||||
        
 | 
			
		||||
    private static readonly float DIVIDEND;
 | 
			
		||||
    private static readonly float DIVISOR;
 | 
			
		||||
    private static readonly float EXPONENT;
 | 
			
		||||
        
 | 
			
		||||
    static StudentTNu1()
 | 
			
		||||
    {
 | 
			
		||||
        DIVIDEND = MathTools.Gamma((NU + 1.0f) * 0.5f);
 | 
			
		||||
        DIVISOR = MathF.Sqrt(NU * MathF.PI) * MathTools.Gamma(NU * 0.5f);
 | 
			
		||||
        EXPONENT = -((NU + 1.0f) * 0.5f);
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    public StudentTNu1(IRandom rng) : base(rng)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private protected override float ShapeFunction(float x) => CONSTANT * MathF.Pow((DIVIDEND / DIVISOR) * MathF.Pow(1.0f + MathF.Pow(START + x * COMPRESS, 2f) / NU, EXPONENT), COMPRESS);
 | 
			
		||||
}
 | 
			
		||||
@ -2,70 +2,57 @@ using System;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace FastRng.Distributions
 | 
			
		||||
namespace FastRng.Distributions;
 | 
			
		||||
 | 
			
		||||
public sealed class Uniform : IDistribution
 | 
			
		||||
{
 | 
			
		||||
    public sealed class Uniform : IDistribution
 | 
			
		||||
    private readonly IRandom rng;
 | 
			
		||||
        
 | 
			
		||||
    public Uniform(IRandom rng)
 | 
			
		||||
    {
 | 
			
		||||
        private readonly IRandom rng;
 | 
			
		||||
        this.rng = rng ?? throw new ArgumentNullException(nameof(rng), "An IRandom implementation is needed.");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public async ValueTask<float> GetDistributedValue(CancellationToken token = default) => await this.rng.GetUniform(token);
 | 
			
		||||
        
 | 
			
		||||
        public Uniform(IRandom rng)
 | 
			
		||||
        {
 | 
			
		||||
            if (rng == null)
 | 
			
		||||
                throw new ArgumentNullException(nameof(rng), "An IRandom implementation is needed.");
 | 
			
		||||
            
 | 
			
		||||
            this.rng = rng;
 | 
			
		||||
        }
 | 
			
		||||
    public async ValueTask<uint> NextNumber(uint rangeStart, uint rangeEnd, CancellationToken cancel = default)
 | 
			
		||||
    {
 | 
			
		||||
        // Swap the values if the range start is greater than the range end:
 | 
			
		||||
        if (rangeStart > rangeEnd)
 | 
			
		||||
            (rangeStart, rangeEnd) = (rangeEnd, rangeStart);
 | 
			
		||||
 | 
			
		||||
        public async ValueTask<float> GetDistributedValue(CancellationToken token = default) => await this.rng.GetUniform(token);
 | 
			
		||||
        var range = rangeEnd - rangeStart;
 | 
			
		||||
        var distributedValue = await this.GetDistributedValue(cancel);
 | 
			
		||||
        return (uint) ((distributedValue * range) + rangeStart);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public async ValueTask<ulong> NextNumber(ulong rangeStart, ulong rangeEnd, CancellationToken cancel = default)
 | 
			
		||||
    {
 | 
			
		||||
        // Swap the values if the range start is greater than the range end:
 | 
			
		||||
        if (rangeStart > rangeEnd)
 | 
			
		||||
            (rangeStart, rangeEnd) = (rangeEnd, rangeStart);
 | 
			
		||||
 | 
			
		||||
        var range = rangeEnd - rangeStart;
 | 
			
		||||
        var distributedValue = await this.GetDistributedValue(cancel);
 | 
			
		||||
        return (ulong) ((distributedValue * range) + rangeStart);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public async ValueTask<float> NextNumber(float rangeStart, float rangeEnd, CancellationToken cancel = default)
 | 
			
		||||
    {
 | 
			
		||||
        // Swap the values if the range start is greater than the range end:
 | 
			
		||||
        if (rangeStart > rangeEnd)
 | 
			
		||||
            (rangeStart, rangeEnd) = (rangeEnd, rangeStart);
 | 
			
		||||
 | 
			
		||||
        var range = rangeEnd - rangeStart;
 | 
			
		||||
        var distributedValue = await this.GetDistributedValue(cancel);
 | 
			
		||||
        return (distributedValue * range) + rangeStart;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public async ValueTask<float> NextNumber(CancellationToken cancel = default) => await this.NextNumber(0.0f, 1.0f, cancel);
 | 
			
		||||
        
 | 
			
		||||
        public async ValueTask<uint> NextNumber(uint rangeStart, uint rangeEnd, CancellationToken cancel = default)
 | 
			
		||||
        {
 | 
			
		||||
            if (rangeStart > rangeEnd)
 | 
			
		||||
            {
 | 
			
		||||
                var tmp = rangeStart;
 | 
			
		||||
                rangeStart = rangeEnd;
 | 
			
		||||
                rangeEnd = tmp;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            var range = rangeEnd - rangeStart;
 | 
			
		||||
            var distributedValue = await this.GetDistributedValue(cancel);
 | 
			
		||||
            return (uint) ((distributedValue * range) + rangeStart);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public async ValueTask<ulong> NextNumber(ulong rangeStart, ulong rangeEnd, CancellationToken cancel = default(CancellationToken))
 | 
			
		||||
        {
 | 
			
		||||
            if (rangeStart > rangeEnd)
 | 
			
		||||
            {
 | 
			
		||||
                var tmp = rangeStart;
 | 
			
		||||
                rangeStart = rangeEnd;
 | 
			
		||||
                rangeEnd = tmp;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            var range = rangeEnd - rangeStart;
 | 
			
		||||
            var distributedValue = await this.GetDistributedValue(cancel);
 | 
			
		||||
            return (ulong) ((distributedValue * range) + rangeStart);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public async ValueTask<float> NextNumber(float rangeStart, float rangeEnd, CancellationToken cancel = default(CancellationToken))
 | 
			
		||||
        {
 | 
			
		||||
            if (rangeStart > rangeEnd)
 | 
			
		||||
            {
 | 
			
		||||
                var tmp = rangeStart;
 | 
			
		||||
                rangeStart = rangeEnd;
 | 
			
		||||
                rangeEnd = tmp;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            var range = rangeEnd - rangeStart;
 | 
			
		||||
            var distributedValue = await this.GetDistributedValue(cancel);
 | 
			
		||||
            return (distributedValue * range) + rangeStart;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public async ValueTask<float> NextNumber(CancellationToken cancel = default) => await this.NextNumber(0.0f, 1.0f, cancel);
 | 
			
		||||
        
 | 
			
		||||
        public async ValueTask<bool> HasDecisionBeenMade(float above, float below = 1, CancellationToken cancel = default)
 | 
			
		||||
        {
 | 
			
		||||
            var number = await this.NextNumber(cancel);
 | 
			
		||||
            return number > above && number < below;
 | 
			
		||||
        }
 | 
			
		||||
    public async ValueTask<bool> HasDecisionBeenMade(float above, float below = 1, CancellationToken cancel = default)
 | 
			
		||||
    {
 | 
			
		||||
        var number = await this.NextNumber(cancel);
 | 
			
		||||
        return number > above && number < below;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,17 +1,16 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace FastRng.Distributions
 | 
			
		||||
namespace FastRng.Distributions;
 | 
			
		||||
 | 
			
		||||
public sealed class WeibullK05La1 : Distribution
 | 
			
		||||
{
 | 
			
		||||
    public sealed class WeibullK05La1 : Distribution
 | 
			
		||||
    private const float K = 0.5f;
 | 
			
		||||
    private const float LAMBDA = 1.0f;
 | 
			
		||||
    private const float CONSTANT = 0.221034183615129f;
 | 
			
		||||
 | 
			
		||||
    public WeibullK05La1(IRandom rng) : base(rng)
 | 
			
		||||
    {
 | 
			
		||||
        private const float K = 0.5f;
 | 
			
		||||
        private const float LAMBDA = 1.0f;
 | 
			
		||||
        private const float CONSTANT = 0.221034183615129f;
 | 
			
		||||
 | 
			
		||||
        public WeibullK05La1(IRandom rng) : base(rng)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private protected override float ShapeFunction(float x) => CONSTANT * ( (K / LAMBDA) * MathF.Pow(x / LAMBDA, K - 1.0f) * MathF.Exp(-MathF.Pow(x/LAMBDA, K)));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private protected override float ShapeFunction(float x) => CONSTANT * ( (K / LAMBDA) * MathF.Pow(x / LAMBDA, K - 1.0f) * MathF.Exp(-MathF.Pow(x/LAMBDA, K)));
 | 
			
		||||
}
 | 
			
		||||
@ -2,22 +2,21 @@ using System;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace FastRng
 | 
			
		||||
namespace FastRng;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Interface for random number generators.
 | 
			
		||||
/// </summary>
 | 
			
		||||
public interface IRandom : IDisposable
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Interface for random number generators.
 | 
			
		||||
    /// Returns a uniform distributed pseudo-random number from the interval (0,1].
 | 
			
		||||
    /// This means, the result 0 is impossible, whereas 1 is possible.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public interface IRandom : IDisposable
 | 
			
		||||
    {
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Returns a uniform distributed pseudo-random number from the interval (0,1].
 | 
			
		||||
        /// This means, the result 0 is impossible, whereas 1 is possible.
 | 
			
		||||
        /// </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="cancel">An optional cancellation token.</param>
 | 
			
		||||
        public ValueTask<float> GetUniform(CancellationToken cancel = default);
 | 
			
		||||
    }
 | 
			
		||||
    /// <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="cancel">An optional cancellation token.</param>
 | 
			
		||||
    public ValueTask<float> GetUniform(CancellationToken cancel = default);
 | 
			
		||||
}
 | 
			
		||||
@ -1,83 +1,82 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace FastRng
 | 
			
		||||
namespace FastRng;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Provides some mathematical function, which are not available within in the .NET framework.
 | 
			
		||||
/// </summary>
 | 
			
		||||
public static class MathTools
 | 
			
		||||
{
 | 
			
		||||
    private static readonly float SQRT_2 = MathF.Sqrt(2.0f);
 | 
			
		||||
    private static readonly float SQRT_PI = MathF.Sqrt(MathF.PI);
 | 
			
		||||
        
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Provides some mathematical function, which are not available within in the .NET framework.
 | 
			
		||||
    /// The mathematical gamma function.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public static class MathTools
 | 
			
		||||
    /// <param name="z">The value for which you want calculate gamma.</param>
 | 
			
		||||
    public static float Gamma(float z)
 | 
			
		||||
    {
 | 
			
		||||
        private static readonly float SQRT_2 = MathF.Sqrt(2.0f);
 | 
			
		||||
        private static readonly float SQRT_PI = MathF.Sqrt(MathF.PI);
 | 
			
		||||
        
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// The mathematical gamma function.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="z">The value for which you want calculate gamma.</param>
 | 
			
		||||
        public static float Gamma(float z)
 | 
			
		||||
        {
 | 
			
		||||
            // Source: http://rosettacode.org/wiki/Gamma_function#Go
 | 
			
		||||
        // Source: http://rosettacode.org/wiki/Gamma_function#Go
 | 
			
		||||
            
 | 
			
		||||
            const float F1 = 6.5f;
 | 
			
		||||
            const float A1 = .99999999999980993f;
 | 
			
		||||
            const float A2 = 676.5203681218851f;
 | 
			
		||||
            const float A3 = 1259.1392167224028f;
 | 
			
		||||
            const float A4 = 771.32342877765313f;
 | 
			
		||||
            const float A5 = 176.61502916214059f;
 | 
			
		||||
            const float A6 = 12.507343278686905f;
 | 
			
		||||
            const float A7 = .13857109526572012f;
 | 
			
		||||
            const float A8 = 9.9843695780195716e-6f;
 | 
			
		||||
            const float A9 = 1.5056327351493116e-7f;
 | 
			
		||||
        const float F1 = 6.5f;
 | 
			
		||||
        const float A1 = .99999999999980993f;
 | 
			
		||||
        const float A2 = 676.5203681218851f;
 | 
			
		||||
        const float A3 = 1259.1392167224028f;
 | 
			
		||||
        const float A4 = 771.32342877765313f;
 | 
			
		||||
        const float A5 = 176.61502916214059f;
 | 
			
		||||
        const float A6 = 12.507343278686905f;
 | 
			
		||||
        const float A7 = .13857109526572012f;
 | 
			
		||||
        const float A8 = 9.9843695780195716e-6f;
 | 
			
		||||
        const float A9 = 1.5056327351493116e-7f;
 | 
			
		||||
 | 
			
		||||
            var t = z + F1;
 | 
			
		||||
            var x =  A1 +
 | 
			
		||||
                     A2 / z -
 | 
			
		||||
                     A3 / (z + 1) +
 | 
			
		||||
                     A4 / (z + 2) -
 | 
			
		||||
                     A5 / (z + 3) +
 | 
			
		||||
                     A6 / (z + 4) -
 | 
			
		||||
                     A7 / (z + 5) +
 | 
			
		||||
                     A8 / (z + 6) +
 | 
			
		||||
                     A9 / (z + 7);
 | 
			
		||||
        var t = z + F1;
 | 
			
		||||
        var x =  A1 +
 | 
			
		||||
                 A2 / z -
 | 
			
		||||
                 A3 / (z + 1) +
 | 
			
		||||
                 A4 / (z + 2) -
 | 
			
		||||
                 A5 / (z + 3) +
 | 
			
		||||
                 A6 / (z + 4) -
 | 
			
		||||
                 A7 / (z + 5) +
 | 
			
		||||
                 A8 / (z + 6) +
 | 
			
		||||
                 A9 / (z + 7);
 | 
			
		||||
 | 
			
		||||
            return MathTools.SQRT_2 * MathTools.SQRT_PI * MathF.Pow(t, z - 0.5f) * MathF.Exp(-t) * x;
 | 
			
		||||
        }
 | 
			
		||||
        return SQRT_2 * SQRT_PI * MathF.Pow(t, z - 0.5f) * MathF.Exp(-t) * x;
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// The mathematical factorial function for floating-point numbers.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="x">The value, for which you want to know the factorial.</param>
 | 
			
		||||
        public static float Factorial(float x) => MathTools.Gamma(x + 1.0f);
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// The mathematical factorial function for floating-point numbers.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="x">The value, for which you want to know the factorial.</param>
 | 
			
		||||
    public static float Factorial(float x) => Gamma(x + 1.0f);
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// The mathematical factorial function for integer numbers.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="x">The value, for which you want to know the factorial.</param>
 | 
			
		||||
        /// <exception cref="ArgumentOutOfRangeException">Throws, when x is greater than 20. Due to limitations of 64bit ulong type.</exception>
 | 
			
		||||
        public static ulong Factorial(uint x)
 | 
			
		||||
        {
 | 
			
		||||
            if (x > 20)
 | 
			
		||||
                throw new ArgumentOutOfRangeException(nameof(x), $"Cannot compute {x}!, since ulong.max is 18_446_744_073_709_551_615.");
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// The mathematical factorial function for integer numbers.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="x">The value, for which you want to know the factorial.</param>
 | 
			
		||||
    /// <exception cref="ArgumentOutOfRangeException">Throws, when x is greater than 20. Due to limitations of 64bit ulong type.</exception>
 | 
			
		||||
    public static ulong Factorial(uint x)
 | 
			
		||||
    {
 | 
			
		||||
        if (x > 20)
 | 
			
		||||
            throw new ArgumentOutOfRangeException(nameof(x), $"Cannot compute {x}!, since ulong.max is 18_446_744_073_709_551_615.");
 | 
			
		||||
            
 | 
			
		||||
            ulong accumulator = 1;
 | 
			
		||||
            for (uint factor = 1; factor <= x; factor++)
 | 
			
		||||
                accumulator *= factor;
 | 
			
		||||
        ulong accumulator = 1;
 | 
			
		||||
        for (uint factor = 1; factor <= x; factor++)
 | 
			
		||||
            accumulator *= factor;
 | 
			
		||||
 | 
			
		||||
            return accumulator;
 | 
			
		||||
        }
 | 
			
		||||
        return accumulator;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// The mathematical factorial function for integer numbers.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="x">The value, for which you want to know the factorial.</param>
 | 
			
		||||
        /// <exception cref="ArgumentOutOfRangeException">Throws, when x is greater than 20. Due to limitations
 | 
			
		||||
        /// of 64bit ulong type. Throws also, when x is less than 0.</exception>
 | 
			
		||||
        public static ulong Factorial(int x)
 | 
			
		||||
        {
 | 
			
		||||
            if(x < 0)
 | 
			
		||||
                throw new ArgumentOutOfRangeException(nameof(x), "Given value must be greater as zero.");
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// The mathematical factorial function for integer numbers.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="x">The value, for which you want to know the factorial.</param>
 | 
			
		||||
    /// <exception cref="ArgumentOutOfRangeException">Throws, when x is greater than 20. Due to limitations
 | 
			
		||||
    /// of 64bit ulong type. Throws also, when x is less than 0.</exception>
 | 
			
		||||
    public static ulong Factorial(int x)
 | 
			
		||||
    {
 | 
			
		||||
        if(x < 0)
 | 
			
		||||
            throw new ArgumentOutOfRangeException(nameof(x), "Given value must be greater as zero.");
 | 
			
		||||
 | 
			
		||||
            return MathTools.Factorial((uint) x);
 | 
			
		||||
        }
 | 
			
		||||
        return Factorial((uint) x);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -4,354 +4,353 @@ using System.Diagnostics.CodeAnalysis;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace FastRng
 | 
			
		||||
namespace FastRng;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// A fast multi-threaded pseudo random number generator.
 | 
			
		||||
/// </summary>
 | 
			
		||||
/// <remarks>
 | 
			
		||||
/// 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 and async. Consumers can await the next number without
 | 
			
		||||
/// blocking resources. Additionally, consumers can use a token to cancel e.g. timeout an operation as well.<br/><br/>
 | 
			
		||||
///
 | 
			
		||||
/// 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
 | 
			
		||||
/// 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.
 | 
			
		||||
/// Cook's (johndcook.com) implementation (https://www.codeproject.com/Articles/25172/Simple-Random-Number-Generation).
 | 
			
		||||
/// Thanks John for the inspiration.<br/><br/>
 | 
			
		||||
///
 | 
			
		||||
/// Please notice: When using the debug environment, MultiThreadedRng uses a smaller buffer size. Please ensure,
 | 
			
		||||
/// that the production environment uses a release build, though.
 | 
			
		||||
/// </remarks>
 | 
			
		||||
public sealed class MultiThreadedRng : IRandom, IDisposable
 | 
			
		||||
{
 | 
			
		||||
#if DEBUG
 | 
			
		||||
    private const int BUFFER_SIZE = 10_000;
 | 
			
		||||
#else
 | 
			
		||||
    private const int BUFFER_SIZE = 1_000_000;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    // The queue size means, how many buffer we store in a queue at the same time:
 | 
			
		||||
    private const int QUEUE_SIZE = 2;
 | 
			
		||||
        
 | 
			
		||||
    // Gets used to stop the producer threads:
 | 
			
		||||
    private readonly CancellationTokenSource producerTokenSource = new();
 | 
			
		||||
        
 | 
			
		||||
    // The time a thread waits e.g. to check if the queue needs a new buffer:
 | 
			
		||||
    private readonly TimeSpan waiter = TimeSpan.FromMilliseconds(10);
 | 
			
		||||
        
 | 
			
		||||
    // The first queue, where to store buffers of random uint numbers:
 | 
			
		||||
    private readonly ConcurrentQueue<uint[]> queueIntegers = new();
 | 
			
		||||
        
 | 
			
		||||
    // The second queue, where to store buffers of uniform random floating point numbers:
 | 
			
		||||
    private readonly ConcurrentQueue<float[]> queueFloats = new();
 | 
			
		||||
 | 
			
		||||
    // The uint producer thread:
 | 
			
		||||
    private Thread producerRandomUint;
 | 
			
		||||
        
 | 
			
		||||
    // The uniform float producer thread:
 | 
			
		||||
    private Thread producerRandomUniformDistributedFloat;
 | 
			
		||||
        
 | 
			
		||||
    // Variable w and z for the uint generator. Both get used
 | 
			
		||||
    // as seeding variable as well (cf. constructors)
 | 
			
		||||
    private uint mW;
 | 
			
		||||
    private uint mZ;
 | 
			
		||||
        
 | 
			
		||||
    // This is the current buffer for the consumer side i.e. the public interfaces:
 | 
			
		||||
    private float[] currentBuffer = Array.Empty<float>();
 | 
			
		||||
        
 | 
			
		||||
    // The current pointer to the next current buffer's address to read from:
 | 
			
		||||
    private int currentBufferPointer = BUFFER_SIZE;
 | 
			
		||||
 | 
			
		||||
    #region Constructors
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// A fast multi-threaded pseudo random number generator.
 | 
			
		||||
    /// Creates a multi-threaded random number generator.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <remarks>
 | 
			
		||||
    /// 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 and async. Consumers can await the next number without
 | 
			
		||||
    /// blocking resources. Additionally, consumers can use a token to cancel e.g. timeout an operation as well.<br/><br/>
 | 
			
		||||
    ///
 | 
			
		||||
    /// 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
 | 
			
		||||
    /// 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.
 | 
			
		||||
    /// Cook's (johndcook.com) implementation (https://www.codeproject.com/Articles/25172/Simple-Random-Number-Generation).
 | 
			
		||||
    /// Thanks John for the inspiration.<br/><br/>
 | 
			
		||||
    ///
 | 
			
		||||
    /// Please notice: When using the debug environment, MultiThreadedRng uses a smaller buffer size. Please ensure,
 | 
			
		||||
    /// that the production environment uses a release build, though.
 | 
			
		||||
    /// This constructor uses the user's current local time
 | 
			
		||||
    /// to derive necessary parameters for the generator.
 | 
			
		||||
    /// Thus, the results are depending on the time, where
 | 
			
		||||
    /// the generator was created.
 | 
			
		||||
    /// </remarks>
 | 
			
		||||
    public sealed class MultiThreadedRng : IRandom, IDisposable
 | 
			
		||||
    public MultiThreadedRng()
 | 
			
		||||
    {
 | 
			
		||||
        #if DEBUG
 | 
			
		||||
            private const int BUFFER_SIZE = 10_000;
 | 
			
		||||
        #else
 | 
			
		||||
            private const int BUFFER_SIZE = 1_000_000;
 | 
			
		||||
        #endif
 | 
			
		||||
 | 
			
		||||
        // The queue size means, how many buffer we store in a queue at the same time:
 | 
			
		||||
        private const int QUEUE_SIZE = 2;
 | 
			
		||||
        
 | 
			
		||||
        // Gets used to stop the producer threads:
 | 
			
		||||
        private readonly CancellationTokenSource producerTokenSource = new CancellationTokenSource();
 | 
			
		||||
        
 | 
			
		||||
        // The time a thread waits e.g. to check if the queue needs a new buffer:
 | 
			
		||||
        private readonly TimeSpan waiter = TimeSpan.FromMilliseconds(10);
 | 
			
		||||
        
 | 
			
		||||
        // The first queue, where to store buffers of random uint numbers:
 | 
			
		||||
        private readonly ConcurrentQueue<uint[]> queueIntegers = new ConcurrentQueue<uint[]>();
 | 
			
		||||
        
 | 
			
		||||
        // The second queue, where to store buffers of uniform random floating point numbers:
 | 
			
		||||
        private readonly ConcurrentQueue<float[]> queueFloats = new ConcurrentQueue<float[]>();
 | 
			
		||||
 | 
			
		||||
        // The uint producer thread:
 | 
			
		||||
        private Thread producerRandomUint;
 | 
			
		||||
        
 | 
			
		||||
        // The uniform float producer thread:
 | 
			
		||||
        private Thread producerRandomUniformDistributedFloat;
 | 
			
		||||
        
 | 
			
		||||
        // Variable w and z for the uint generator. Both get used
 | 
			
		||||
        // as seeding variable as well (cf. constructors)
 | 
			
		||||
        private uint mW;
 | 
			
		||||
        private uint mZ;
 | 
			
		||||
        
 | 
			
		||||
        // This is the current buffer for the consumer side i.e. the public interfaces:
 | 
			
		||||
        private float[] currentBuffer = Array.Empty<float>();
 | 
			
		||||
        
 | 
			
		||||
        // The current pointer to the next current buffer's address to read from:
 | 
			
		||||
        private int currentBufferPointer = BUFFER_SIZE;
 | 
			
		||||
 | 
			
		||||
        #region Constructors
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Creates a multi-threaded random number generator.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <remarks>
 | 
			
		||||
        /// This constructor uses the user's current local time
 | 
			
		||||
        /// to derive necessary parameters for the generator.
 | 
			
		||||
        /// Thus, the results are depending on the time, where
 | 
			
		||||
        /// the generator was created.
 | 
			
		||||
        /// </remarks>
 | 
			
		||||
        public MultiThreadedRng()
 | 
			
		||||
        {
 | 
			
		||||
            //
 | 
			
		||||
            // 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.StartProducerThreads();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <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">A seed value to generate a deterministic generator.</param>
 | 
			
		||||
        public MultiThreadedRng(uint seedU)
 | 
			
		||||
        {
 | 
			
		||||
            this.mW = seedU;
 | 
			
		||||
            this.mZ = 362_436_069;
 | 
			
		||||
            this.StartProducerThreads();
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        /// <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 MultiThreadedRng(uint seedU, uint seedV)
 | 
			
		||||
        {
 | 
			
		||||
            this.mW = seedU;
 | 
			
		||||
            this.mZ = seedV;
 | 
			
		||||
            this.StartProducerThreads();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void StartProducerThreads()
 | 
			
		||||
        {
 | 
			
		||||
            this.producerRandomUint = new Thread(() => this.RandomProducerUint(this.producerTokenSource.Token)) {IsBackground = true};
 | 
			
		||||
            this.producerRandomUint.Start();
 | 
			
		||||
            this.producerRandomUniformDistributedFloat = new Thread(() => this.RandomProducerUniformDistributedFloat(this.producerTokenSource.Token)) {IsBackground = true};
 | 
			
		||||
            this.producerRandomUniformDistributedFloat.Start();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        #endregion
 | 
			
		||||
 | 
			
		||||
        #region Producers
 | 
			
		||||
 | 
			
		||||
        [ExcludeFromCodeCoverage]
 | 
			
		||||
        private async void RandomProducerUint(CancellationToken cancellationToken)
 | 
			
		||||
        {
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                while (!cancellationToken.IsCancellationRequested)
 | 
			
		||||
                {
 | 
			
		||||
                    // A local next buffer, which gets filled next:
 | 
			
		||||
                    var nextBuffer = new uint[BUFFER_SIZE];
 | 
			
		||||
                    
 | 
			
		||||
                    // Produce the necessary number of random uints:
 | 
			
		||||
                    for (var n = 0; n < nextBuffer.Length && !cancellationToken.IsCancellationRequested; n++)
 | 
			
		||||
                    {
 | 
			
		||||
                        this.mZ = 36_969 * (this.mZ & 65_535) + (this.mZ >> 16);
 | 
			
		||||
                        this.mW = 18_000 * (this.mW & 65_535) + (this.mW >> 16);
 | 
			
		||||
                        nextBuffer[n] = (this.mZ << 16) + this.mW;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    // Inside this loop, we try to enqueue the produced buffer:
 | 
			
		||||
                    while (!cancellationToken.IsCancellationRequested)
 | 
			
		||||
                    {
 | 
			
		||||
                        try
 | 
			
		||||
                        {
 | 
			
		||||
                            // Ensure, that we do not produce more buffers, as configured: 
 | 
			
		||||
                            if (this.queueIntegers.Count < QUEUE_SIZE)
 | 
			
		||||
                            {
 | 
			
		||||
                                this.queueIntegers.Enqueue(nextBuffer);
 | 
			
		||||
                                break;
 | 
			
		||||
                            }
 | 
			
		||||
 | 
			
		||||
                            // The queue was full. Wait a moment and try it again:
 | 
			
		||||
                            await Task.Delay(this.waiter, cancellationToken);
 | 
			
		||||
                        }
 | 
			
		||||
                        catch (TaskCanceledException)
 | 
			
		||||
                        {
 | 
			
		||||
                            // The producers should be stopped:
 | 
			
		||||
                            return;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            catch (OperationCanceledException)
 | 
			
		||||
            {
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        [ExcludeFromCodeCoverage]
 | 
			
		||||
        private async void RandomProducerUniformDistributedFloat(CancellationToken cancellationToken)
 | 
			
		||||
        {
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                while (!cancellationToken.IsCancellationRequested)
 | 
			
		||||
                {
 | 
			
		||||
                    // A local source buffer of uints: 
 | 
			
		||||
                    uint[] bufferSource = null;
 | 
			
		||||
                    
 | 
			
		||||
                    // Try to get the next source buffer:
 | 
			
		||||
                    while (!this.queueIntegers.TryDequeue(out bufferSource) && !cancellationToken.IsCancellationRequested)
 | 
			
		||||
                        await Task.Delay(this.waiter, cancellationToken);
 | 
			
		||||
 | 
			
		||||
                    // Case: The producers should be stopped:
 | 
			
		||||
                    if(bufferSource == null)
 | 
			
		||||
                        return;
 | 
			
		||||
                    
 | 
			
		||||
                    // A local buffer to fill with uniform floats:
 | 
			
		||||
                    var nextBuffer = new float[BUFFER_SIZE];
 | 
			
		||||
                    
 | 
			
		||||
                    // Generate the necessary number of floats:
 | 
			
		||||
                    for (var n = 0; n < nextBuffer.Length && !cancellationToken.IsCancellationRequested; n++)
 | 
			
		||||
                        nextBuffer[n] = (bufferSource[n] + 1.0f) * 2.328306435454494e-10f;
 | 
			
		||||
 | 
			
		||||
                    // Inside this loop, we try to enqueue the generated buffer:
 | 
			
		||||
                    while (!cancellationToken.IsCancellationRequested)
 | 
			
		||||
                    {
 | 
			
		||||
                        try
 | 
			
		||||
                        {
 | 
			
		||||
                            // Ensure, that the queue contains only the configured number of buffers:
 | 
			
		||||
                            if (this.queueFloats.Count < QUEUE_SIZE)
 | 
			
		||||
                            {
 | 
			
		||||
                                this.queueFloats.Enqueue(nextBuffer);
 | 
			
		||||
                                break;
 | 
			
		||||
                            }
 | 
			
		||||
 | 
			
		||||
                            // The queue was full. Wait a moment and try it again:
 | 
			
		||||
                            await Task.Delay(this.waiter, cancellationToken);
 | 
			
		||||
                        }
 | 
			
		||||
                        catch (TaskCanceledException)
 | 
			
		||||
                        {
 | 
			
		||||
                            return;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            catch (OperationCanceledException)
 | 
			
		||||
            {
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        #endregion
 | 
			
		||||
 | 
			
		||||
        #region Implementing interface
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Returns a uniform distributed pseudo-random number from the interval (0,1].
 | 
			
		||||
        /// This means, the result 0 is impossible, whereas 1 is possible.
 | 
			
		||||
        /// </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="cancel">An optional cancellation token.</param>
 | 
			
		||||
        public async ValueTask<float> GetUniform(CancellationToken cancel = default)
 | 
			
		||||
        {
 | 
			
		||||
            while (!cancel.IsCancellationRequested)
 | 
			
		||||
            {
 | 
			
		||||
                // Check, if we need a new buffer to read from:
 | 
			
		||||
                if (this.currentBufferPointer >= BUFFER_SIZE)
 | 
			
		||||
                {
 | 
			
		||||
                    // Create a local copy of the current buffer's pointer:
 | 
			
		||||
                    var currentBufferReference = this.currentBuffer;
 | 
			
		||||
                    
 | 
			
		||||
                    // Here, we store the next buffer until we implement it:
 | 
			
		||||
                    var nextBuffer = Array.Empty<float>();
 | 
			
		||||
                    
 | 
			
		||||
                    // Try to get the next buffer from the queue:
 | 
			
		||||
                    while (this.currentBufferPointer >= BUFFER_SIZE && currentBufferReference == this.currentBuffer && !this.queueFloats.TryDequeue(out nextBuffer))
 | 
			
		||||
                    {
 | 
			
		||||
                        //
 | 
			
		||||
                        // Case: There is no next buffer available.
 | 
			
		||||
                        // Must wait for producer(s) to provide next.
 | 
			
		||||
                        //
 | 
			
		||||
                        try
 | 
			
		||||
                        {
 | 
			
		||||
                            await Task.Delay(this.waiter, cancel);
 | 
			
		||||
                        }
 | 
			
		||||
                        catch (TaskCanceledException)
 | 
			
		||||
                        {
 | 
			
		||||
                            //
 | 
			
		||||
                            // Case: The consumer cancelled the request.
 | 
			
		||||
                            //
 | 
			
		||||
                            return float.NaN;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                
 | 
			
		||||
                    //
 | 
			
		||||
                    // Note: In general, it does not matter if the following compare-exchange is successful.
 | 
			
		||||
                    // 1st case: It was successful -- everything is fine. But we are responsible to re-set the currentBufferPointer.
 | 
			
		||||
                    // 2nd case: It was not successful. This means, that another thread was successful, though.
 | 
			
		||||
                    //           That case is fine as well. But we would loose one buffer of work. Thus, we
 | 
			
		||||
                    //           check for this case and preserve the buffer full of work.
 | 
			
		||||
                    //
 | 
			
		||||
                    
 | 
			
		||||
                    // Try to implement the dequeued buffer without locking other threads:
 | 
			
		||||
                    if (Interlocked.CompareExchange(ref this.currentBuffer, nextBuffer, currentBufferReference) != currentBufferReference)
 | 
			
		||||
                    {
 | 
			
		||||
                        //
 | 
			
		||||
                        // Case: Another thread updated the buffer already.
 | 
			
		||||
                        // Thus, we enqueue our copy of the next buffer to preserve it.
 | 
			
		||||
                        //
 | 
			
		||||
                        this.queueFloats.Enqueue(nextBuffer);
 | 
			
		||||
                        
 | 
			
		||||
                        // Next? We can go ahead and yield a random number...
 | 
			
		||||
                    }
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
                        //
 | 
			
		||||
                        // Case: We updated the buffer.
 | 
			
		||||
                        //
 | 
			
		||||
                        this.currentBufferPointer = 0;
 | 
			
		||||
                        
 | 
			
		||||
                        // Next? We can go ahead and yield a random number...
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Made a local copy of the current pointer:
 | 
			
		||||
                var myPointer = this.currentBufferPointer;
 | 
			
		||||
                
 | 
			
		||||
                // Increment the pointer for the next thread or call:
 | 
			
		||||
                var nextPointer = myPointer + 1;
 | 
			
		||||
                
 | 
			
		||||
                // Try to update the pointer without locking other threads:
 | 
			
		||||
                if (Interlocked.CompareExchange(ref this.currentBufferPointer, nextPointer, myPointer) == myPointer)
 | 
			
		||||
                {
 | 
			
		||||
                    //
 | 
			
		||||
                    // Case: Success. We updated the pointer and, thus, can use the pointer to read a number.
 | 
			
		||||
                    //
 | 
			
		||||
                    return this.currentBuffer[myPointer];
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                //
 | 
			
		||||
                // Case: Another thread updated the pointer already. Must restart the process
 | 
			
		||||
                // to get a random number.
 | 
			
		||||
                //
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            //
 | 
			
		||||
            // Case: The consumer cancelled the request.
 | 
			
		||||
            //
 | 
			
		||||
            return float.NaN;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        private void StopProducer() => this.producerTokenSource.Cancel();
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Disposes this generator. It is important to dispose a generator,
 | 
			
		||||
        /// when it is no longer needed. Otherwise, the background threads
 | 
			
		||||
        /// are still running.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public void Dispose() => this.StopProducer();
 | 
			
		||||
 | 
			
		||||
        #endregion
 | 
			
		||||
        //
 | 
			
		||||
        // 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.StartProducerThreads();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <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">A seed value to generate a deterministic generator.</param>
 | 
			
		||||
    public MultiThreadedRng(uint seedU)
 | 
			
		||||
    {
 | 
			
		||||
        this.mW = seedU;
 | 
			
		||||
        this.mZ = 362_436_069;
 | 
			
		||||
        this.StartProducerThreads();
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    /// <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 MultiThreadedRng(uint seedU, uint seedV)
 | 
			
		||||
    {
 | 
			
		||||
        this.mW = seedU;
 | 
			
		||||
        this.mZ = seedV;
 | 
			
		||||
        this.StartProducerThreads();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void StartProducerThreads()
 | 
			
		||||
    {
 | 
			
		||||
        this.producerRandomUint = new Thread(() => this.RandomProducerUint(this.producerTokenSource.Token)) {IsBackground = true};
 | 
			
		||||
        this.producerRandomUint.Start();
 | 
			
		||||
        this.producerRandomUniformDistributedFloat = new Thread(() => this.RandomProducerUniformDistributedFloat(this.producerTokenSource.Token)) {IsBackground = true};
 | 
			
		||||
        this.producerRandomUniformDistributedFloat.Start();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #endregion
 | 
			
		||||
 | 
			
		||||
    #region Producers
 | 
			
		||||
 | 
			
		||||
    [ExcludeFromCodeCoverage]
 | 
			
		||||
    private async void RandomProducerUint(CancellationToken cancellationToken)
 | 
			
		||||
    {
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            while (!cancellationToken.IsCancellationRequested)
 | 
			
		||||
            {
 | 
			
		||||
                // A local next buffer, which gets filled next:
 | 
			
		||||
                var nextBuffer = new uint[BUFFER_SIZE];
 | 
			
		||||
                    
 | 
			
		||||
                // Produce the necessary number of random uints:
 | 
			
		||||
                for (var n = 0; n < nextBuffer.Length && !cancellationToken.IsCancellationRequested; n++)
 | 
			
		||||
                {
 | 
			
		||||
                    this.mZ = 36_969 * (this.mZ & 65_535) + (this.mZ >> 16);
 | 
			
		||||
                    this.mW = 18_000 * (this.mW & 65_535) + (this.mW >> 16);
 | 
			
		||||
                    nextBuffer[n] = (this.mZ << 16) + this.mW;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Inside this loop, we try to enqueue the produced buffer:
 | 
			
		||||
                while (!cancellationToken.IsCancellationRequested)
 | 
			
		||||
                {
 | 
			
		||||
                    try
 | 
			
		||||
                    {
 | 
			
		||||
                        // Ensure, that we do not produce more buffers, as configured: 
 | 
			
		||||
                        if (this.queueIntegers.Count < QUEUE_SIZE)
 | 
			
		||||
                        {
 | 
			
		||||
                            this.queueIntegers.Enqueue(nextBuffer);
 | 
			
		||||
                            break;
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        // The queue was full. Wait a moment and try it again:
 | 
			
		||||
                        await Task.Delay(this.waiter, cancellationToken);
 | 
			
		||||
                    }
 | 
			
		||||
                    catch (TaskCanceledException)
 | 
			
		||||
                    {
 | 
			
		||||
                        // The producers should be stopped:
 | 
			
		||||
                        return;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        catch (OperationCanceledException)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    [ExcludeFromCodeCoverage]
 | 
			
		||||
    private async void RandomProducerUniformDistributedFloat(CancellationToken cancellationToken)
 | 
			
		||||
    {
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            while (!cancellationToken.IsCancellationRequested)
 | 
			
		||||
            {
 | 
			
		||||
                // A local source buffer of uints: 
 | 
			
		||||
                uint[] bufferSource = null;
 | 
			
		||||
                    
 | 
			
		||||
                // Try to get the next source buffer:
 | 
			
		||||
                while (!this.queueIntegers.TryDequeue(out bufferSource) && !cancellationToken.IsCancellationRequested)
 | 
			
		||||
                    await Task.Delay(this.waiter, cancellationToken);
 | 
			
		||||
 | 
			
		||||
                // Case: The producers should be stopped:
 | 
			
		||||
                if(bufferSource == null)
 | 
			
		||||
                    return;
 | 
			
		||||
                    
 | 
			
		||||
                // A local buffer to fill with uniform floats:
 | 
			
		||||
                var nextBuffer = new float[BUFFER_SIZE];
 | 
			
		||||
                    
 | 
			
		||||
                // Generate the necessary number of floats:
 | 
			
		||||
                for (var n = 0; n < nextBuffer.Length && !cancellationToken.IsCancellationRequested; n++)
 | 
			
		||||
                    nextBuffer[n] = (bufferSource[n] + 1.0f) * 2.328306435454494e-10f;
 | 
			
		||||
 | 
			
		||||
                // Inside this loop, we try to enqueue the generated buffer:
 | 
			
		||||
                while (!cancellationToken.IsCancellationRequested)
 | 
			
		||||
                {
 | 
			
		||||
                    try
 | 
			
		||||
                    {
 | 
			
		||||
                        // Ensure, that the queue contains only the configured number of buffers:
 | 
			
		||||
                        if (this.queueFloats.Count < QUEUE_SIZE)
 | 
			
		||||
                        {
 | 
			
		||||
                            this.queueFloats.Enqueue(nextBuffer);
 | 
			
		||||
                            break;
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        // The queue was full. Wait a moment and try it again:
 | 
			
		||||
                        await Task.Delay(this.waiter, cancellationToken);
 | 
			
		||||
                    }
 | 
			
		||||
                    catch (TaskCanceledException)
 | 
			
		||||
                    {
 | 
			
		||||
                        return;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        catch (OperationCanceledException)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #endregion
 | 
			
		||||
 | 
			
		||||
    #region Implementing interface
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Returns a uniform distributed pseudo-random number from the interval (0,1].
 | 
			
		||||
    /// This means, the result 0 is impossible, whereas 1 is possible.
 | 
			
		||||
    /// </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="cancel">An optional cancellation token.</param>
 | 
			
		||||
    public async ValueTask<float> GetUniform(CancellationToken cancel = default)
 | 
			
		||||
    {
 | 
			
		||||
        while (!cancel.IsCancellationRequested)
 | 
			
		||||
        {
 | 
			
		||||
            // Check, if we need a new buffer to read from:
 | 
			
		||||
            if (this.currentBufferPointer >= BUFFER_SIZE)
 | 
			
		||||
            {
 | 
			
		||||
                // Create a local copy of the current buffer's pointer:
 | 
			
		||||
                var currentBufferReference = this.currentBuffer;
 | 
			
		||||
                    
 | 
			
		||||
                // Here, we store the next buffer until we implement it:
 | 
			
		||||
                var nextBuffer = Array.Empty<float>();
 | 
			
		||||
                    
 | 
			
		||||
                // Try to get the next buffer from the queue:
 | 
			
		||||
                while (this.currentBufferPointer >= BUFFER_SIZE && currentBufferReference == this.currentBuffer && !this.queueFloats.TryDequeue(out nextBuffer))
 | 
			
		||||
                {
 | 
			
		||||
                    //
 | 
			
		||||
                    // Case: There is no next buffer available.
 | 
			
		||||
                    // Must wait for producer(s) to provide next.
 | 
			
		||||
                    //
 | 
			
		||||
                    try
 | 
			
		||||
                    {
 | 
			
		||||
                        await Task.Delay(this.waiter, cancel);
 | 
			
		||||
                    }
 | 
			
		||||
                    catch (TaskCanceledException)
 | 
			
		||||
                    {
 | 
			
		||||
                        //
 | 
			
		||||
                        // Case: The consumer cancelled the request.
 | 
			
		||||
                        //
 | 
			
		||||
                        return float.NaN;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                //
 | 
			
		||||
                // Note: In general, it does not matter if the following compare-exchange is successful.
 | 
			
		||||
                // 1st case: It was successful -- everything is fine. But we are responsible to re-set the currentBufferPointer.
 | 
			
		||||
                // 2nd case: It was not successful. This means, that another thread was successful, though.
 | 
			
		||||
                //           That case is fine as well. But we would loose one buffer of work. Thus, we
 | 
			
		||||
                //           check for this case and preserve the buffer full of work.
 | 
			
		||||
                //
 | 
			
		||||
                    
 | 
			
		||||
                // Try to implement the dequeued buffer without locking other threads:
 | 
			
		||||
                if (Interlocked.CompareExchange(ref this.currentBuffer, nextBuffer, currentBufferReference) != currentBufferReference)
 | 
			
		||||
                {
 | 
			
		||||
                    //
 | 
			
		||||
                    // Case: Another thread updated the buffer already.
 | 
			
		||||
                    // Thus, we enqueue our copy of the next buffer to preserve it.
 | 
			
		||||
                    //
 | 
			
		||||
                    this.queueFloats.Enqueue(nextBuffer);
 | 
			
		||||
                        
 | 
			
		||||
                    // Next? We can go ahead and yield a random number...
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    //
 | 
			
		||||
                    // Case: We updated the buffer.
 | 
			
		||||
                    //
 | 
			
		||||
                    this.currentBufferPointer = 0;
 | 
			
		||||
                        
 | 
			
		||||
                    // Next? We can go ahead and yield a random number...
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Made a local copy of the current pointer:
 | 
			
		||||
            var myPointer = this.currentBufferPointer;
 | 
			
		||||
                
 | 
			
		||||
            // Increment the pointer for the next thread or call:
 | 
			
		||||
            var nextPointer = myPointer + 1;
 | 
			
		||||
                
 | 
			
		||||
            // Try to update the pointer without locking other threads:
 | 
			
		||||
            if (Interlocked.CompareExchange(ref this.currentBufferPointer, nextPointer, myPointer) == myPointer)
 | 
			
		||||
            {
 | 
			
		||||
                //
 | 
			
		||||
                // Case: Success. We updated the pointer and, thus, can use the pointer to read a number.
 | 
			
		||||
                //
 | 
			
		||||
                return this.currentBuffer[myPointer];
 | 
			
		||||
            }
 | 
			
		||||
                
 | 
			
		||||
            //
 | 
			
		||||
            // Case: Another thread updated the pointer already. Must restart the process
 | 
			
		||||
            // to get a random number.
 | 
			
		||||
            //
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //
 | 
			
		||||
        // Case: The consumer cancelled the request.
 | 
			
		||||
        //
 | 
			
		||||
        return float.NaN;
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    private void StopProducer() => this.producerTokenSource.Cancel();
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Disposes this generator. It is important to dispose a generator,
 | 
			
		||||
    /// when it is no longer needed. Otherwise, the background threads
 | 
			
		||||
    /// are still running.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public void Dispose() => this.StopProducer();
 | 
			
		||||
 | 
			
		||||
    #endregion
 | 
			
		||||
}
 | 
			
		||||
@ -3,76 +3,75 @@ using System.Threading;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using FastRng.Distributions;
 | 
			
		||||
 | 
			
		||||
namespace FastRng
 | 
			
		||||
namespace FastRng;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// ShapeFitter is a rejection sampler, cf. https://en.wikipedia.org/wiki/Rejection_sampling
 | 
			
		||||
/// </summary>
 | 
			
		||||
public sealed class ShapeFitter
 | 
			
		||||
{
 | 
			
		||||
    private readonly float[] probabilities;
 | 
			
		||||
    private readonly IRandom rng;
 | 
			
		||||
    private readonly float max;
 | 
			
		||||
    private readonly float sampleSize;
 | 
			
		||||
    private readonly IDistribution uniform;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// ShapeFitter is a rejection sampler, cf. https://en.wikipedia.org/wiki/Rejection_sampling
 | 
			
		||||
    /// Creates a shape fitter instance.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public sealed class ShapeFitter
 | 
			
		||||
    /// <param name="shapeFunction">The function which describes the desired shape.</param>
 | 
			
		||||
    /// <param name="rng">The random number generator instance to use.</param>
 | 
			
		||||
    /// <param name="sampleSize">The number of sampling steps to sample the given function.</param>
 | 
			
		||||
    public ShapeFitter(Func<float, float> shapeFunction, IRandom rng, ushort sampleSize = 50)
 | 
			
		||||
    {
 | 
			
		||||
        private readonly float[] probabilities;
 | 
			
		||||
        private readonly IRandom rng;
 | 
			
		||||
        private readonly float max;
 | 
			
		||||
        private readonly float sampleSize;
 | 
			
		||||
        private readonly IDistribution uniform;
 | 
			
		||||
        this.rng = rng;
 | 
			
		||||
        this.uniform = new Uniform(rng);
 | 
			
		||||
        this.sampleSize = sampleSize;
 | 
			
		||||
        this.probabilities = new float[sampleSize];
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Creates a shape fitter instance.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="shapeFunction">The function which describes the desired shape.</param>
 | 
			
		||||
        /// <param name="rng">The random number generator instance to use.</param>
 | 
			
		||||
        /// <param name="sampleSize">The number of sampling steps to sample the given function.</param>
 | 
			
		||||
        public ShapeFitter(Func<float, float> shapeFunction, IRandom rng, ushort sampleSize = 50)
 | 
			
		||||
        var sampleStepSize = 1.0f / sampleSize;
 | 
			
		||||
        var nextStep = 0.0f + sampleStepSize;
 | 
			
		||||
        var maxValue = 0.0f;
 | 
			
		||||
        for (var n = 0; n < sampleSize; n++)
 | 
			
		||||
        {
 | 
			
		||||
            this.rng = rng;
 | 
			
		||||
            this.uniform = new Uniform(rng);
 | 
			
		||||
            this.sampleSize = sampleSize;
 | 
			
		||||
            this.probabilities = new float[sampleSize];
 | 
			
		||||
 | 
			
		||||
            var sampleStepSize = 1.0f / sampleSize;
 | 
			
		||||
            var nextStep = 0.0f + sampleStepSize;
 | 
			
		||||
            var maxValue = 0.0f;
 | 
			
		||||
            for (var n = 0; n < sampleSize; n++)
 | 
			
		||||
            {
 | 
			
		||||
                this.probabilities[n] = shapeFunction(nextStep);
 | 
			
		||||
                if (this.probabilities[n] > maxValue)
 | 
			
		||||
                    maxValue = this.probabilities[n];
 | 
			
		||||
            this.probabilities[n] = shapeFunction(nextStep);
 | 
			
		||||
            if (this.probabilities[n] > maxValue)
 | 
			
		||||
                maxValue = this.probabilities[n];
 | 
			
		||||
                
 | 
			
		||||
                nextStep += sampleStepSize;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            this.max = maxValue;
 | 
			
		||||
            nextStep += sampleStepSize;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Returns a random number regarding the given shape.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="token">An optional cancellation token.</param>
 | 
			
		||||
        /// <returns>The next value regarding the given shape.</returns>
 | 
			
		||||
        public async ValueTask<float> NextNumber(CancellationToken token = default)
 | 
			
		||||
        {
 | 
			
		||||
            while (!token.IsCancellationRequested)
 | 
			
		||||
            {
 | 
			
		||||
                var x = await this.rng.GetUniform(token);
 | 
			
		||||
                if (float.IsNaN(x))
 | 
			
		||||
                    return x;
 | 
			
		||||
                
 | 
			
		||||
                var nextBucket = (int)MathF.Floor(x * this.sampleSize);
 | 
			
		||||
                if (nextBucket >= this.probabilities.Length)
 | 
			
		||||
                    nextBucket = this.probabilities.Length - 1;
 | 
			
		||||
                
 | 
			
		||||
                var threshold = this.probabilities[nextBucket];
 | 
			
		||||
                var y = await this.uniform.NextNumber(0.0f, this.max, token);
 | 
			
		||||
                if (float.IsNaN(y))
 | 
			
		||||
                    return y;
 | 
			
		||||
                
 | 
			
		||||
                if(y > threshold)
 | 
			
		||||
                    continue;
 | 
			
		||||
        this.max = maxValue;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Returns a random number regarding the given shape.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="token">An optional cancellation token.</param>
 | 
			
		||||
    /// <returns>The next value regarding the given shape.</returns>
 | 
			
		||||
    public async ValueTask<float> NextNumber(CancellationToken token = default)
 | 
			
		||||
    {
 | 
			
		||||
        while (!token.IsCancellationRequested)
 | 
			
		||||
        {
 | 
			
		||||
            var x = await this.rng.GetUniform(token);
 | 
			
		||||
            if (float.IsNaN(x))
 | 
			
		||||
                return x;
 | 
			
		||||
            }
 | 
			
		||||
                
 | 
			
		||||
            var nextBucket = (int)MathF.Floor(x * this.sampleSize);
 | 
			
		||||
            if (nextBucket >= this.probabilities.Length)
 | 
			
		||||
                nextBucket = this.probabilities.Length - 1;
 | 
			
		||||
                
 | 
			
		||||
            var threshold = this.probabilities[nextBucket];
 | 
			
		||||
            var y = await this.uniform.NextNumber(0.0f, this.max, token);
 | 
			
		||||
            if (float.IsNaN(y))
 | 
			
		||||
                return y;
 | 
			
		||||
                
 | 
			
		||||
            if(y > threshold)
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            return float.NaN;
 | 
			
		||||
            return x;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return float.NaN;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -6,57 +6,56 @@ using NUnit.Framework;
 | 
			
		||||
using Uniform = FastRng.Distributions.Uniform;
 | 
			
		||||
using WeibullK05La1 = FastRng.Distributions.WeibullK05La1;
 | 
			
		||||
 | 
			
		||||
namespace FastRngTests
 | 
			
		||||
namespace FastRngTests;
 | 
			
		||||
 | 
			
		||||
[ExcludeFromCodeCoverage]
 | 
			
		||||
public class DecisionTester
 | 
			
		||||
{
 | 
			
		||||
    [ExcludeFromCodeCoverage]
 | 
			
		||||
    public class DecisionTester
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task DecisionUniform01()
 | 
			
		||||
    {
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task DecisionUniform01()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new Uniform(rng);
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new Uniform(rng);
 | 
			
		||||
 | 
			
		||||
            var neededCoinTossesA = 0;
 | 
			
		||||
            var neededCoinTossesB = 0;
 | 
			
		||||
            var neededCoinTossesC = 0;
 | 
			
		||||
        var neededCoinTossesA = 0;
 | 
			
		||||
        var neededCoinTossesB = 0;
 | 
			
		||||
        var neededCoinTossesC = 0;
 | 
			
		||||
 | 
			
		||||
            for(var n = 0; n < 100; n++) while (!await dist.HasDecisionBeenMade(0.0f, 0.1f)) neededCoinTossesA++;
 | 
			
		||||
            for(var n = 0; n < 100; n++) while (!await dist.HasDecisionBeenMade(0.5f, 0.6f)) neededCoinTossesB++;
 | 
			
		||||
            for(var n = 0; n < 100; n++) while (!await dist.HasDecisionBeenMade(0.8f, 0.9f)) neededCoinTossesC++;
 | 
			
		||||
        for(var n = 0; n < 100; n++) while (!await dist.HasDecisionBeenMade(0.0f, 0.1f)) neededCoinTossesA++;
 | 
			
		||||
        for(var n = 0; n < 100; n++) while (!await dist.HasDecisionBeenMade(0.5f, 0.6f)) neededCoinTossesB++;
 | 
			
		||||
        for(var n = 0; n < 100; n++) while (!await dist.HasDecisionBeenMade(0.8f, 0.9f)) neededCoinTossesC++;
 | 
			
		||||
 | 
			
		||||
            var values = new[] {neededCoinTossesA, neededCoinTossesB, neededCoinTossesC};
 | 
			
		||||
            var max = values.Max();
 | 
			
		||||
            var min = values.Min();
 | 
			
		||||
        var values = new[] {neededCoinTossesA, neededCoinTossesB, neededCoinTossesC};
 | 
			
		||||
        var max = values.Max();
 | 
			
		||||
        var min = values.Min();
 | 
			
		||||
            
 | 
			
		||||
            TestContext.WriteLine($"Coin tosses: a={neededCoinTossesA}, b={neededCoinTossesB}, c={neededCoinTossesC}");
 | 
			
		||||
            Assert.That(max - min, Is.LessThanOrEqualTo(250));
 | 
			
		||||
        }
 | 
			
		||||
        TestContext.WriteLine($"Coin tosses: a={neededCoinTossesA}, b={neededCoinTossesB}, c={neededCoinTossesC}");
 | 
			
		||||
        Assert.That(max - min, Is.LessThanOrEqualTo(250));
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task DecisionWeibull01()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new WeibullK05La1(rng);
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task DecisionWeibull01()
 | 
			
		||||
    {
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new WeibullK05La1(rng);
 | 
			
		||||
 | 
			
		||||
            var neededCoinTossesA = 0;
 | 
			
		||||
            var neededCoinTossesB = 0;
 | 
			
		||||
            var neededCoinTossesC = 0;
 | 
			
		||||
        var neededCoinTossesA = 0;
 | 
			
		||||
        var neededCoinTossesB = 0;
 | 
			
		||||
        var neededCoinTossesC = 0;
 | 
			
		||||
 | 
			
		||||
            for(var n = 0; n < 100; n++) while (!await dist.HasDecisionBeenMade(0.0f, 0.1f)) neededCoinTossesA++;
 | 
			
		||||
            for(var n = 0; n < 100; n++) while (!await dist.HasDecisionBeenMade(0.5f, 0.6f)) neededCoinTossesB++;
 | 
			
		||||
            for(var n = 0; n < 100; n++) while (!await dist.HasDecisionBeenMade(0.8f, 0.9f)) neededCoinTossesC++;
 | 
			
		||||
        for(var n = 0; n < 100; n++) while (!await dist.HasDecisionBeenMade(0.0f, 0.1f)) neededCoinTossesA++;
 | 
			
		||||
        for(var n = 0; n < 100; n++) while (!await dist.HasDecisionBeenMade(0.5f, 0.6f)) neededCoinTossesB++;
 | 
			
		||||
        for(var n = 0; n < 100; n++) while (!await dist.HasDecisionBeenMade(0.8f, 0.9f)) neededCoinTossesC++;
 | 
			
		||||
 | 
			
		||||
            var values = new[] {neededCoinTossesA, neededCoinTossesB, neededCoinTossesC};
 | 
			
		||||
            var max = values.Max();
 | 
			
		||||
            var min = values.Min();
 | 
			
		||||
        var values = new[] {neededCoinTossesA, neededCoinTossesB, neededCoinTossesC};
 | 
			
		||||
        var max = values.Max();
 | 
			
		||||
        var min = values.Min();
 | 
			
		||||
            
 | 
			
		||||
            TestContext.WriteLine($"Coin tosses: a={neededCoinTossesA}, b={neededCoinTossesB}, c={neededCoinTossesC}");
 | 
			
		||||
            Assert.That(max - min, Is.LessThanOrEqualTo(2_800));
 | 
			
		||||
        }
 | 
			
		||||
        TestContext.WriteLine($"Coin tosses: a={neededCoinTossesA}, b={neededCoinTossesB}, c={neededCoinTossesC}");
 | 
			
		||||
        Assert.That(max - min, Is.LessThanOrEqualTo(2_800));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -5,80 +5,79 @@ using System.Threading.Tasks;
 | 
			
		||||
using FastRng;
 | 
			
		||||
using NUnit.Framework;
 | 
			
		||||
 | 
			
		||||
namespace FastRngTests.Distributions
 | 
			
		||||
namespace FastRngTests.Distributions;
 | 
			
		||||
 | 
			
		||||
[ExcludeFromCodeCoverage]
 | 
			
		||||
public class BetaA2B2
 | 
			
		||||
{
 | 
			
		||||
    [ExcludeFromCodeCoverage]
 | 
			
		||||
    public class BetaA2B2
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestBetaDistribution01()
 | 
			
		||||
    {
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestBetaDistribution01()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new FastRng.Distributions.BetaA2B2(rng);
 | 
			
		||||
            var fqa = new FrequencyAnalysis();
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new FastRng.Distributions.BetaA2B2(rng);
 | 
			
		||||
        var fqa = new FrequencyAnalysis();
 | 
			
		||||
 | 
			
		||||
            for (var n = 0; n < 100_000; n++)
 | 
			
		||||
                fqa.CountThis(await dist.NextNumber());
 | 
			
		||||
        for (var n = 0; n < 100_000; n++)
 | 
			
		||||
            fqa.CountThis(await dist.NextNumber());
 | 
			
		||||
            
 | 
			
		||||
            var result = fqa.NormalizeAndPlotEvents(TestContext.WriteLine);
 | 
			
		||||
        var result = fqa.NormalizeAndPlotEvents(TestContext.WriteLine);
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[0], Is.EqualTo(0.0396f).Within(0.3f));
 | 
			
		||||
            Assert.That(result[1], Is.EqualTo(0.0784f).Within(0.3f));
 | 
			
		||||
            Assert.That(result[2], Is.EqualTo(0.1164f).Within(0.3f));
 | 
			
		||||
        Assert.That(result[0], Is.EqualTo(0.0396f).Within(0.3f));
 | 
			
		||||
        Assert.That(result[1], Is.EqualTo(0.0784f).Within(0.3f));
 | 
			
		||||
        Assert.That(result[2], Is.EqualTo(0.1164f).Within(0.3f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[21], Is.EqualTo(0.6864f).Within(0.3f));
 | 
			
		||||
            Assert.That(result[22], Is.EqualTo(0.7084f).Within(0.3f));
 | 
			
		||||
            Assert.That(result[23], Is.EqualTo(0.7296f).Within(0.3f));
 | 
			
		||||
        Assert.That(result[21], Is.EqualTo(0.6864f).Within(0.3f));
 | 
			
		||||
        Assert.That(result[22], Is.EqualTo(0.7084f).Within(0.3f));
 | 
			
		||||
        Assert.That(result[23], Is.EqualTo(0.7296f).Within(0.3f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[50], Is.EqualTo(0.9996f).Within(0.3f));
 | 
			
		||||
        Assert.That(result[50], Is.EqualTo(0.9996f).Within(0.3f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[75], Is.EqualTo(0.7296f).Within(0.3f));
 | 
			
		||||
            Assert.That(result[85], Is.EqualTo(0.4816f).Within(0.3f));
 | 
			
		||||
            Assert.That(result[90], Is.EqualTo(0.3276f).Within(0.3f));
 | 
			
		||||
        Assert.That(result[75], Is.EqualTo(0.7296f).Within(0.3f));
 | 
			
		||||
        Assert.That(result[85], Is.EqualTo(0.4816f).Within(0.3f));
 | 
			
		||||
        Assert.That(result[90], Is.EqualTo(0.3276f).Within(0.3f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[97], Is.EqualTo(0.0784f).Within(0.3f));
 | 
			
		||||
            Assert.That(result[98], Is.EqualTo(0.0396f).Within(0.3f));
 | 
			
		||||
            Assert.That(result[99], Is.EqualTo(0.0000f).Within(0.3f));
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(result[97], Is.EqualTo(0.0784f).Within(0.3f));
 | 
			
		||||
        Assert.That(result[98], Is.EqualTo(0.0396f).Within(0.3f));
 | 
			
		||||
        Assert.That(result[99], Is.EqualTo(0.0000f).Within(0.3f));
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestBetaGeneratorWithRange01()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var samples = new float[1_000];
 | 
			
		||||
            var dist = new FastRng.Distributions.BetaA2B2(rng);
 | 
			
		||||
            for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
                samples[n] = await dist.NextNumber(-1.0f, 1.0f);
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestBetaGeneratorWithRange01()
 | 
			
		||||
    {
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var samples = new float[1_000];
 | 
			
		||||
        var dist = new FastRng.Distributions.BetaA2B2(rng);
 | 
			
		||||
        for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
            samples[n] = await dist.NextNumber(-1.0f, 1.0f);
 | 
			
		||||
 | 
			
		||||
            Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range");
 | 
			
		||||
            Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range");
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range");
 | 
			
		||||
        Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range");
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestBetaGeneratorWithRange02()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var samples = new float[1_000];
 | 
			
		||||
            var dist = new FastRng.Distributions.BetaA2B2(rng);
 | 
			
		||||
            for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
                samples[n] = await dist.NextNumber(0.0f, 1.0f);
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestBetaGeneratorWithRange02()
 | 
			
		||||
    {
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var samples = new float[1_000];
 | 
			
		||||
        var dist = new FastRng.Distributions.BetaA2B2(rng);
 | 
			
		||||
        for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
            samples[n] = await dist.NextNumber(0.0f, 1.0f);
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range");
 | 
			
		||||
            Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range");
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range");
 | 
			
		||||
        Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public void NoRandomNumberGenerator01()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.Throws<ArgumentNullException>(() => new FastRng.Distributions.BetaA2B2(null));
 | 
			
		||||
        }
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public void NoRandomNumberGenerator01()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.Throws<ArgumentNullException>(() => new FastRng.Distributions.BetaA2B2(null));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -5,80 +5,79 @@ using System.Threading.Tasks;
 | 
			
		||||
using FastRng;
 | 
			
		||||
using NUnit.Framework;
 | 
			
		||||
 | 
			
		||||
namespace FastRngTests.Distributions
 | 
			
		||||
namespace FastRngTests.Distributions;
 | 
			
		||||
 | 
			
		||||
[ExcludeFromCodeCoverage]
 | 
			
		||||
public class BetaA2B5
 | 
			
		||||
{
 | 
			
		||||
    [ExcludeFromCodeCoverage]
 | 
			
		||||
    public class BetaA2B5
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestBetaDistribution01()
 | 
			
		||||
    {
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestBetaDistribution01()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new FastRng.Distributions.BetaA2B5(rng);
 | 
			
		||||
            var fqa = new FrequencyAnalysis();
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new FastRng.Distributions.BetaA2B5(rng);
 | 
			
		||||
        var fqa = new FrequencyAnalysis();
 | 
			
		||||
 | 
			
		||||
            for (var n = 0; n < 100_000; n++)
 | 
			
		||||
                fqa.CountThis(await dist.NextNumber());
 | 
			
		||||
        for (var n = 0; n < 100_000; n++)
 | 
			
		||||
            fqa.CountThis(await dist.NextNumber());
 | 
			
		||||
            
 | 
			
		||||
            var result = fqa.NormalizeAndPlotEvents(TestContext.WriteLine);
 | 
			
		||||
        var result = fqa.NormalizeAndPlotEvents(TestContext.WriteLine);
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[0], Is.EqualTo(0.11719271f).Within(0.3f));
 | 
			
		||||
            Assert.That(result[1], Is.EqualTo(0.22505783f).Within(0.3f));
 | 
			
		||||
            Assert.That(result[2], Is.EqualTo(0.32401717f).Within(0.3f));
 | 
			
		||||
        Assert.That(result[0], Is.EqualTo(0.11719271f).Within(0.3f));
 | 
			
		||||
        Assert.That(result[1], Is.EqualTo(0.22505783f).Within(0.3f));
 | 
			
		||||
        Assert.That(result[2], Is.EqualTo(0.32401717f).Within(0.3f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[21], Is.EqualTo(0.99348410f).Within(0.3f));
 | 
			
		||||
            Assert.That(result[22], Is.EqualTo(0.98639433f).Within(0.3f));
 | 
			
		||||
            Assert.That(result[23], Is.EqualTo(0.97684451f).Within(0.3f));
 | 
			
		||||
        Assert.That(result[21], Is.EqualTo(0.99348410f).Within(0.3f));
 | 
			
		||||
        Assert.That(result[22], Is.EqualTo(0.98639433f).Within(0.3f));
 | 
			
		||||
        Assert.That(result[23], Is.EqualTo(0.97684451f).Within(0.3f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[50], Is.EqualTo(0.35868592f).Within(0.3f));
 | 
			
		||||
        Assert.That(result[50], Is.EqualTo(0.35868592f).Within(0.3f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[75], Is.EqualTo(0.03076227f).Within(0.03f));
 | 
			
		||||
            Assert.That(result[85], Is.EqualTo(0.00403061f).Within(0.03f));
 | 
			
		||||
            Assert.That(result[90], Is.EqualTo(0.00109800f).Within(0.01f));
 | 
			
		||||
        Assert.That(result[75], Is.EqualTo(0.03076227f).Within(0.03f));
 | 
			
		||||
        Assert.That(result[85], Is.EqualTo(0.00403061f).Within(0.03f));
 | 
			
		||||
        Assert.That(result[90], Is.EqualTo(0.00109800f).Within(0.01f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[97], Is.EqualTo(0.00000191f).Within(0.000003f));
 | 
			
		||||
            Assert.That(result[98], Is.EqualTo(0.00000012f).Within(0.0000003f));
 | 
			
		||||
            Assert.That(result[99], Is.EqualTo(0.00000000f).Within(0.0000003f));
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(result[97], Is.EqualTo(0.00000191f).Within(0.000003f));
 | 
			
		||||
        Assert.That(result[98], Is.EqualTo(0.00000012f).Within(0.0000003f));
 | 
			
		||||
        Assert.That(result[99], Is.EqualTo(0.00000000f).Within(0.0000003f));
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestBetaGeneratorWithRange01()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var samples = new float[1_000];
 | 
			
		||||
            var dist = new FastRng.Distributions.BetaA2B5(rng);
 | 
			
		||||
            for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
                samples[n] = await dist.NextNumber(-1.0f, 1.0f);
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestBetaGeneratorWithRange01()
 | 
			
		||||
    {
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var samples = new float[1_000];
 | 
			
		||||
        var dist = new FastRng.Distributions.BetaA2B5(rng);
 | 
			
		||||
        for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
            samples[n] = await dist.NextNumber(-1.0f, 1.0f);
 | 
			
		||||
 | 
			
		||||
            Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range");
 | 
			
		||||
            Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range");
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range");
 | 
			
		||||
        Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range");
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestBetaGeneratorWithRange02()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var samples = new float[1_000];
 | 
			
		||||
            var dist = new FastRng.Distributions.BetaA2B5(rng);
 | 
			
		||||
            for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
                samples[n] = await dist.NextNumber(0.0f, 1.0f);
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestBetaGeneratorWithRange02()
 | 
			
		||||
    {
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var samples = new float[1_000];
 | 
			
		||||
        var dist = new FastRng.Distributions.BetaA2B5(rng);
 | 
			
		||||
        for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
            samples[n] = await dist.NextNumber(0.0f, 1.0f);
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range");
 | 
			
		||||
            Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range");
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range");
 | 
			
		||||
        Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public void NoRandomNumberGenerator01()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.Throws<ArgumentNullException>(() => new FastRng.Distributions.BetaA2B5(null));
 | 
			
		||||
        }
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public void NoRandomNumberGenerator01()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.Throws<ArgumentNullException>(() => new FastRng.Distributions.BetaA2B5(null));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -5,80 +5,79 @@ using System.Threading.Tasks;
 | 
			
		||||
using FastRng;
 | 
			
		||||
using NUnit.Framework;
 | 
			
		||||
 | 
			
		||||
namespace FastRngTests.Distributions
 | 
			
		||||
namespace FastRngTests.Distributions;
 | 
			
		||||
 | 
			
		||||
[ExcludeFromCodeCoverage]
 | 
			
		||||
public class BetaA5B2
 | 
			
		||||
{
 | 
			
		||||
    [ExcludeFromCodeCoverage]
 | 
			
		||||
    public class BetaA5B2
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestBetaDistribution01()
 | 
			
		||||
    {
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestBetaDistribution01()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new FastRng.Distributions.BetaA5B2(rng);
 | 
			
		||||
            var fqa = new FrequencyAnalysis();
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new FastRng.Distributions.BetaA5B2(rng);
 | 
			
		||||
        var fqa = new FrequencyAnalysis();
 | 
			
		||||
 | 
			
		||||
            for (var n = 0; n < 100_000; n++)
 | 
			
		||||
                fqa.CountThis(await dist.NextNumber());
 | 
			
		||||
        for (var n = 0; n < 100_000; n++)
 | 
			
		||||
            fqa.CountThis(await dist.NextNumber());
 | 
			
		||||
            
 | 
			
		||||
            var result = fqa.NormalizeAndPlotEvents(TestContext.WriteLine);
 | 
			
		||||
        var result = fqa.NormalizeAndPlotEvents(TestContext.WriteLine);
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[0], Is.EqualTo(0.0000001f).Within(0.0000003f));
 | 
			
		||||
            Assert.That(result[1], Is.EqualTo(0.0000019f).Within(0.00001f));
 | 
			
		||||
            Assert.That(result[2], Is.EqualTo(0.0000096f).Within(0.0004f));
 | 
			
		||||
        Assert.That(result[0], Is.EqualTo(0.0000001f).Within(0.0000003f));
 | 
			
		||||
        Assert.That(result[1], Is.EqualTo(0.0000019f).Within(0.00001f));
 | 
			
		||||
        Assert.That(result[2], Is.EqualTo(0.0000096f).Within(0.0004f));
 | 
			
		||||
 | 
			
		||||
            Assert.That(result[21], Is.EqualTo(0.0222918f).Within(0.03f));
 | 
			
		||||
            Assert.That(result[22], Is.EqualTo(0.0262883f).Within(0.03f));
 | 
			
		||||
            Assert.That(result[23], Is.EqualTo(0.0307623f).Within(0.03f));
 | 
			
		||||
        Assert.That(result[21], Is.EqualTo(0.0222918f).Within(0.03f));
 | 
			
		||||
        Assert.That(result[22], Is.EqualTo(0.0262883f).Within(0.03f));
 | 
			
		||||
        Assert.That(result[23], Is.EqualTo(0.0307623f).Within(0.03f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[50], Is.EqualTo(0.4044237f).Within(0.2f));
 | 
			
		||||
        Assert.That(result[50], Is.EqualTo(0.4044237f).Within(0.2f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[75], Is.EqualTo(0.9768445f).Within(0.15f));
 | 
			
		||||
            Assert.That(result[85], Is.EqualTo(0.9552714f).Within(0.15f));
 | 
			
		||||
            Assert.That(result[90], Is.EqualTo(0.8004420f).Within(0.35f));
 | 
			
		||||
        Assert.That(result[75], Is.EqualTo(0.9768445f).Within(0.15f));
 | 
			
		||||
        Assert.That(result[85], Is.EqualTo(0.9552714f).Within(0.15f));
 | 
			
		||||
        Assert.That(result[90], Is.EqualTo(0.8004420f).Within(0.35f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[97], Is.EqualTo(0.2250578f).Within(0.03f));
 | 
			
		||||
            Assert.That(result[98], Is.EqualTo(0.1171927f).Within(0.03f));
 | 
			
		||||
            Assert.That(result[99], Is.EqualTo(0f).Within(0.0004f));
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(result[97], Is.EqualTo(0.2250578f).Within(0.03f));
 | 
			
		||||
        Assert.That(result[98], Is.EqualTo(0.1171927f).Within(0.03f));
 | 
			
		||||
        Assert.That(result[99], Is.EqualTo(0f).Within(0.0004f));
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestBetaGeneratorWithRange01()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var samples = new float[1_000];
 | 
			
		||||
            var dist = new FastRng.Distributions.BetaA5B2(rng);
 | 
			
		||||
            for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
                samples[n] = await dist.NextNumber(-1.0f, 1.0f);
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestBetaGeneratorWithRange01()
 | 
			
		||||
    {
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var samples = new float[1_000];
 | 
			
		||||
        var dist = new FastRng.Distributions.BetaA5B2(rng);
 | 
			
		||||
        for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
            samples[n] = await dist.NextNumber(-1.0f, 1.0f);
 | 
			
		||||
 | 
			
		||||
            Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range");
 | 
			
		||||
            Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range");
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range");
 | 
			
		||||
        Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range");
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestBetaGeneratorWithRange02()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var samples = new float[1_000];
 | 
			
		||||
            var dist = new FastRng.Distributions.BetaA5B2(rng);
 | 
			
		||||
            for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
                samples[n] = await dist.NextNumber(0.0f, 1.0f);
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestBetaGeneratorWithRange02()
 | 
			
		||||
    {
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var samples = new float[1_000];
 | 
			
		||||
        var dist = new FastRng.Distributions.BetaA5B2(rng);
 | 
			
		||||
        for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
            samples[n] = await dist.NextNumber(0.0f, 1.0f);
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range");
 | 
			
		||||
            Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range");
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range");
 | 
			
		||||
        Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public void NoRandomNumberGenerator01()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.Throws<ArgumentNullException>(() => new FastRng.Distributions.BetaA5B2(null));
 | 
			
		||||
        }
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public void NoRandomNumberGenerator01()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.Throws<ArgumentNullException>(() => new FastRng.Distributions.BetaA5B2(null));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -5,83 +5,82 @@ using System.Threading.Tasks;
 | 
			
		||||
using FastRng;
 | 
			
		||||
using NUnit.Framework;
 | 
			
		||||
 | 
			
		||||
namespace FastRngTests.Distributions
 | 
			
		||||
namespace FastRngTests.Distributions;
 | 
			
		||||
 | 
			
		||||
[ExcludeFromCodeCoverage]
 | 
			
		||||
public class CauchyLorentzX0
 | 
			
		||||
{
 | 
			
		||||
    [ExcludeFromCodeCoverage]
 | 
			
		||||
    public class CauchyLorentzX0
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestCauchyDistribution01()
 | 
			
		||||
    {
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestCauchyDistribution01()
 | 
			
		||||
        {
 | 
			
		||||
            // The properties of the cauchy distribution cannot be tested by mean, media or variance,  
 | 
			
		||||
            // cf. https://en.wikipedia.org/wiki/Cauchy_distribution#Explanation_of_undefined_moments
 | 
			
		||||
        // The properties of the cauchy distribution cannot be tested by mean, media or variance,  
 | 
			
		||||
        // cf. https://en.wikipedia.org/wiki/Cauchy_distribution#Explanation_of_undefined_moments
 | 
			
		||||
            
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new FastRng.Distributions.CauchyLorentzX0(rng);
 | 
			
		||||
            var fqa = new FrequencyAnalysis();
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new FastRng.Distributions.CauchyLorentzX0(rng);
 | 
			
		||||
        var fqa = new FrequencyAnalysis();
 | 
			
		||||
 | 
			
		||||
            for (var n = 0; n < 100_000; n++)
 | 
			
		||||
                fqa.CountThis(await dist.NextNumber());
 | 
			
		||||
        for (var n = 0; n < 100_000; n++)
 | 
			
		||||
            fqa.CountThis(await dist.NextNumber());
 | 
			
		||||
            
 | 
			
		||||
            var result = fqa.NormalizeAndPlotEvents(TestContext.WriteLine);
 | 
			
		||||
        var result = fqa.NormalizeAndPlotEvents(TestContext.WriteLine);
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[0], Is.EqualTo(0.976990739772031f).Within(0.06f));
 | 
			
		||||
            Assert.That(result[1], Is.EqualTo(0.948808314586299f).Within(0.06f));
 | 
			
		||||
            Assert.That(result[2], Is.EqualTo(0.905284997403441f).Within(0.06f));
 | 
			
		||||
        Assert.That(result[0], Is.EqualTo(0.976990739772031f).Within(0.06f));
 | 
			
		||||
        Assert.That(result[1], Is.EqualTo(0.948808314586299f).Within(0.06f));
 | 
			
		||||
        Assert.That(result[2], Is.EqualTo(0.905284997403441f).Within(0.06f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[21], Is.EqualTo(0.168965864241396f).Within(0.04f));
 | 
			
		||||
            Assert.That(result[22], Is.EqualTo(0.156877686354491f).Within(0.04f));
 | 
			
		||||
            Assert.That(result[23], Is.EqualTo(0.145970509936354f).Within(0.04f));
 | 
			
		||||
        Assert.That(result[21], Is.EqualTo(0.168965864241396f).Within(0.04f));
 | 
			
		||||
        Assert.That(result[22], Is.EqualTo(0.156877686354491f).Within(0.04f));
 | 
			
		||||
        Assert.That(result[23], Is.EqualTo(0.145970509936354f).Within(0.04f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[50], Is.EqualTo(0.036533159835978f).Within(0.01f));
 | 
			
		||||
        Assert.That(result[50], Is.EqualTo(0.036533159835978f).Within(0.01f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[75], Is.EqualTo(0.016793067514802f).Within(0.01f));
 | 
			
		||||
            Assert.That(result[85], Is.EqualTo(0.01316382933791f).Within(0.005f));
 | 
			
		||||
            Assert.That(result[90], Is.EqualTo(0.011773781734516f).Within(0.005f));
 | 
			
		||||
        Assert.That(result[75], Is.EqualTo(0.016793067514802f).Within(0.01f));
 | 
			
		||||
        Assert.That(result[85], Is.EqualTo(0.01316382933791f).Within(0.005f));
 | 
			
		||||
        Assert.That(result[90], Is.EqualTo(0.011773781734516f).Within(0.005f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[97], Is.EqualTo(0.010168596941156f).Within(0.005f));
 | 
			
		||||
            Assert.That(result[98], Is.EqualTo(0.009966272570142f).Within(0.005f));
 | 
			
		||||
            Assert.That(result[99], Is.EqualTo(0.00976990739772f).Within(0.005f));
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(result[97], Is.EqualTo(0.010168596941156f).Within(0.005f));
 | 
			
		||||
        Assert.That(result[98], Is.EqualTo(0.009966272570142f).Within(0.005f));
 | 
			
		||||
        Assert.That(result[99], Is.EqualTo(0.00976990739772f).Within(0.005f));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestCauchyGeneratorWithRange01()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new FastRng.Distributions.CauchyLorentzX0(rng);
 | 
			
		||||
            var samples = new float[1_000];
 | 
			
		||||
            for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
                samples[n] = await dist.NextNumber(-1.0f, 1.0f);
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestCauchyGeneratorWithRange01()
 | 
			
		||||
    {
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new FastRng.Distributions.CauchyLorentzX0(rng);
 | 
			
		||||
        var samples = new float[1_000];
 | 
			
		||||
        for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
            samples[n] = await dist.NextNumber(-1.0f, 1.0f);
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min is out of range");
 | 
			
		||||
            Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range");
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min is out of range");
 | 
			
		||||
        Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range");
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestCauchyGeneratorWithRange02()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new FastRng.Distributions.CauchyLorentzX0(rng);
 | 
			
		||||
            var samples = new float[1_000];
 | 
			
		||||
            for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
                samples[n] = await dist.NextNumber(0.0f, 1.0f);
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestCauchyGeneratorWithRange02()
 | 
			
		||||
    {
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new FastRng.Distributions.CauchyLorentzX0(rng);
 | 
			
		||||
        var samples = new float[1_000];
 | 
			
		||||
        for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
            samples[n] = await dist.NextNumber(0.0f, 1.0f);
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range");
 | 
			
		||||
            Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range");
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range");
 | 
			
		||||
        Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public void NoRandomNumberGenerator01()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.Throws<ArgumentNullException>(() => new FastRng.Distributions.CauchyLorentzX0(null));
 | 
			
		||||
        }
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public void NoRandomNumberGenerator01()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.Throws<ArgumentNullException>(() => new FastRng.Distributions.CauchyLorentzX0(null));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -5,83 +5,82 @@ using System.Threading.Tasks;
 | 
			
		||||
using FastRng;
 | 
			
		||||
using NUnit.Framework;
 | 
			
		||||
 | 
			
		||||
namespace FastRngTests.Distributions
 | 
			
		||||
namespace FastRngTests.Distributions;
 | 
			
		||||
 | 
			
		||||
[ExcludeFromCodeCoverage]
 | 
			
		||||
public class CauchyLorentzX1
 | 
			
		||||
{
 | 
			
		||||
    [ExcludeFromCodeCoverage]
 | 
			
		||||
    public class CauchyLorentzX1
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestCauchyDistribution01()
 | 
			
		||||
    {
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestCauchyDistribution01()
 | 
			
		||||
        {
 | 
			
		||||
            // The properties of the cauchy distribution cannot be tested by mean, media or variance,  
 | 
			
		||||
            // cf. https://en.wikipedia.org/wiki/Cauchy_distribution#Explanation_of_undefined_moments
 | 
			
		||||
        // The properties of the cauchy distribution cannot be tested by mean, media or variance,  
 | 
			
		||||
        // cf. https://en.wikipedia.org/wiki/Cauchy_distribution#Explanation_of_undefined_moments
 | 
			
		||||
            
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new FastRng.Distributions.CauchyLorentzX1(rng);
 | 
			
		||||
            var fqa = new FrequencyAnalysis();
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new FastRng.Distributions.CauchyLorentzX1(rng);
 | 
			
		||||
        var fqa = new FrequencyAnalysis();
 | 
			
		||||
 | 
			
		||||
            for (var n = 0; n < 100_000; n++)
 | 
			
		||||
                fqa.CountThis(await dist.NextNumber());
 | 
			
		||||
        for (var n = 0; n < 100_000; n++)
 | 
			
		||||
            fqa.CountThis(await dist.NextNumber());
 | 
			
		||||
            
 | 
			
		||||
            var result = fqa.NormalizeAndPlotEvents(TestContext.WriteLine);
 | 
			
		||||
        var result = fqa.NormalizeAndPlotEvents(TestContext.WriteLine);
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[0], Is.EqualTo(0.009966272570142f).Within(0.003f));
 | 
			
		||||
            Assert.That(result[1], Is.EqualTo(0.010168596941156f).Within(0.004f));
 | 
			
		||||
            Assert.That(result[2], Is.EqualTo(0.010377123221893f).Within(0.005f));
 | 
			
		||||
        Assert.That(result[0], Is.EqualTo(0.009966272570142f).Within(0.003f));
 | 
			
		||||
        Assert.That(result[1], Is.EqualTo(0.010168596941156f).Within(0.004f));
 | 
			
		||||
        Assert.That(result[2], Is.EqualTo(0.010377123221893f).Within(0.005f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[21], Is.EqualTo(0.015956672819692f).Within(0.005f));
 | 
			
		||||
            Assert.That(result[22], Is.EqualTo(0.016366904083094f).Within(0.005f));
 | 
			
		||||
            Assert.That(result[23], Is.EqualTo(0.016793067514802f).Within(0.005f));
 | 
			
		||||
        Assert.That(result[21], Is.EqualTo(0.015956672819692f).Within(0.005f));
 | 
			
		||||
        Assert.That(result[22], Is.EqualTo(0.016366904083094f).Within(0.005f));
 | 
			
		||||
        Assert.That(result[23], Is.EqualTo(0.016793067514802f).Within(0.005f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[50], Is.EqualTo(0.039454644029179f).Within(0.015f));
 | 
			
		||||
        Assert.That(result[50], Is.EqualTo(0.039454644029179f).Within(0.015f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[75], Is.EqualTo(0.145970509936354f).Within(0.03f));
 | 
			
		||||
            Assert.That(result[85], Is.EqualTo(0.333365083503296f).Within(0.1f));
 | 
			
		||||
            Assert.That(result[90], Is.EqualTo(0.545171628270584f).Within(0.1f));
 | 
			
		||||
        Assert.That(result[75], Is.EqualTo(0.145970509936354f).Within(0.03f));
 | 
			
		||||
        Assert.That(result[85], Is.EqualTo(0.333365083503296f).Within(0.1f));
 | 
			
		||||
        Assert.That(result[90], Is.EqualTo(0.545171628270584f).Within(0.1f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[97], Is.EqualTo(0.948808314586302f).Within(0.06f));
 | 
			
		||||
            Assert.That(result[98], Is.EqualTo(0.976990739772032f).Within(0.03f));
 | 
			
		||||
            Assert.That(result[99], Is.EqualTo(0.986760647169751f).Within(0.02f));
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(result[97], Is.EqualTo(0.948808314586302f).Within(0.06f));
 | 
			
		||||
        Assert.That(result[98], Is.EqualTo(0.976990739772032f).Within(0.03f));
 | 
			
		||||
        Assert.That(result[99], Is.EqualTo(0.986760647169751f).Within(0.02f));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestCauchyGeneratorWithRange01()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new FastRng.Distributions.CauchyLorentzX0(rng);
 | 
			
		||||
            var samples = new float[1_000];
 | 
			
		||||
            for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
                samples[n] = await dist.NextNumber(-1.0f, 1.0f);
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestCauchyGeneratorWithRange01()
 | 
			
		||||
    {
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new FastRng.Distributions.CauchyLorentzX0(rng);
 | 
			
		||||
        var samples = new float[1_000];
 | 
			
		||||
        for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
            samples[n] = await dist.NextNumber(-1.0f, 1.0f);
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min is out of range");
 | 
			
		||||
            Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range");
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min is out of range");
 | 
			
		||||
        Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range");
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestCauchyGeneratorWithRange02()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new FastRng.Distributions.CauchyLorentzX0(rng);
 | 
			
		||||
            var samples = new float[1_000];
 | 
			
		||||
            for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
                samples[n] = await dist.NextNumber(0.0f, 1.0f);
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestCauchyGeneratorWithRange02()
 | 
			
		||||
    {
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new FastRng.Distributions.CauchyLorentzX0(rng);
 | 
			
		||||
        var samples = new float[1_000];
 | 
			
		||||
        for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
            samples[n] = await dist.NextNumber(0.0f, 1.0f);
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range");
 | 
			
		||||
            Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range");
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range");
 | 
			
		||||
        Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public void NoRandomNumberGenerator01()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.Throws<ArgumentNullException>(() => new FastRng.Distributions.CauchyLorentzX1(null));
 | 
			
		||||
        }
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public void NoRandomNumberGenerator01()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.Throws<ArgumentNullException>(() => new FastRng.Distributions.CauchyLorentzX1(null));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -5,83 +5,82 @@ using System.Threading.Tasks;
 | 
			
		||||
using FastRng;
 | 
			
		||||
using NUnit.Framework;
 | 
			
		||||
 | 
			
		||||
namespace FastRngTests.Distributions
 | 
			
		||||
namespace FastRngTests.Distributions;
 | 
			
		||||
 | 
			
		||||
[ExcludeFromCodeCoverage]
 | 
			
		||||
public class ChiSquareK1
 | 
			
		||||
{
 | 
			
		||||
    [ExcludeFromCodeCoverage]
 | 
			
		||||
    public class ChiSquareK1
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestChiSquareDistribution01()
 | 
			
		||||
    {
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestChiSquareDistribution01()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new FastRng.Distributions.ChiSquareK1(rng);
 | 
			
		||||
            var fqa = new FrequencyAnalysis();
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new FastRng.Distributions.ChiSquareK1(rng);
 | 
			
		||||
        var fqa = new FrequencyAnalysis();
 | 
			
		||||
 | 
			
		||||
            for (var n = 0; n < 100_000; n++)
 | 
			
		||||
            {
 | 
			
		||||
                var value = await dist.NextNumber();
 | 
			
		||||
                fqa.CountThis(value);
 | 
			
		||||
            }
 | 
			
		||||
        for (var n = 0; n < 100_000; n++)
 | 
			
		||||
        {
 | 
			
		||||
            var value = await dist.NextNumber();
 | 
			
		||||
            fqa.CountThis(value);
 | 
			
		||||
        }
 | 
			
		||||
            
 | 
			
		||||
            var result = fqa.NormalizeAndPlotEvents(TestContext.WriteLine);
 | 
			
		||||
        var result = fqa.NormalizeAndPlotEvents(TestContext.WriteLine);
 | 
			
		||||
 | 
			
		||||
            Assert.That(result[0], Is.EqualTo(1.00032041964207f).Within(0.004f));
 | 
			
		||||
            Assert.That(result[1], Is.EqualTo(0.70380551227703f).Within(0.05f));
 | 
			
		||||
            Assert.That(result[2], Is.EqualTo(0.571788691668126f).Within(0.05f));
 | 
			
		||||
        Assert.That(result[0], Is.EqualTo(1.00032041964207f).Within(0.004f));
 | 
			
		||||
        Assert.That(result[1], Is.EqualTo(0.70380551227703f).Within(0.05f));
 | 
			
		||||
        Assert.That(result[2], Is.EqualTo(0.571788691668126f).Within(0.05f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[21], Is.EqualTo(0.192011337664754f).Within(0.07f));
 | 
			
		||||
            Assert.That(result[22], Is.EqualTo(0.186854182385981f).Within(0.07f));
 | 
			
		||||
            Assert.That(result[23], Is.EqualTo(0.182007652359976f).Within(0.07f));
 | 
			
		||||
        Assert.That(result[21], Is.EqualTo(0.192011337664754f).Within(0.07f));
 | 
			
		||||
        Assert.That(result[22], Is.EqualTo(0.186854182385981f).Within(0.07f));
 | 
			
		||||
        Assert.That(result[23], Is.EqualTo(0.182007652359976f).Within(0.07f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[50], Is.EqualTo(0.109088865614875f).Within(0.06f));
 | 
			
		||||
        Assert.That(result[50], Is.EqualTo(0.109088865614875f).Within(0.06f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[75], Is.EqualTo(0.07886274821701f).Within(0.02f));
 | 
			
		||||
            Assert.That(result[85], Is.EqualTo(0.070520397849883f).Within(0.02f));
 | 
			
		||||
            Assert.That(result[90], Is.EqualTo(0.066863009640287f).Within(0.02f));
 | 
			
		||||
        Assert.That(result[75], Is.EqualTo(0.07886274821701f).Within(0.02f));
 | 
			
		||||
        Assert.That(result[85], Is.EqualTo(0.070520397849883f).Within(0.02f));
 | 
			
		||||
        Assert.That(result[90], Is.EqualTo(0.066863009640287f).Within(0.02f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[97], Is.EqualTo(0.062214737436948f).Within(0.02f));
 | 
			
		||||
            Assert.That(result[98], Is.EqualTo(0.061590997922187f).Within(0.02f));
 | 
			
		||||
            Assert.That(result[99], Is.EqualTo(0.060976622578824f).Within(0.02f));
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(result[97], Is.EqualTo(0.062214737436948f).Within(0.02f));
 | 
			
		||||
        Assert.That(result[98], Is.EqualTo(0.061590997922187f).Within(0.02f));
 | 
			
		||||
        Assert.That(result[99], Is.EqualTo(0.060976622578824f).Within(0.02f));
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestChiSquareGeneratorWithRange01()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new FastRng.Distributions.ChiSquareK1(rng);
 | 
			
		||||
            var samples = new float[1_000];
 | 
			
		||||
            for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
                samples[n] = await dist.NextNumber(-1.0f, 1.0f);
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestChiSquareGeneratorWithRange01()
 | 
			
		||||
    {
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new FastRng.Distributions.ChiSquareK1(rng);
 | 
			
		||||
        var samples = new float[1_000];
 | 
			
		||||
        for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
            samples[n] = await dist.NextNumber(-1.0f, 1.0f);
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range");
 | 
			
		||||
            Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range");
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range");
 | 
			
		||||
        Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range");
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestChiSquareGeneratorWithRange02()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new FastRng.Distributions.ChiSquareK1(rng);
 | 
			
		||||
            var samples = new float[1_000];
 | 
			
		||||
            for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
                samples[n] = await dist.NextNumber(0.0f, 1.0f);
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestChiSquareGeneratorWithRange02()
 | 
			
		||||
    {
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new FastRng.Distributions.ChiSquareK1(rng);
 | 
			
		||||
        var samples = new float[1_000];
 | 
			
		||||
        for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
            samples[n] = await dist.NextNumber(0.0f, 1.0f);
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range");
 | 
			
		||||
            Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range");
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range");
 | 
			
		||||
        Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range");
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public void NoRandomNumberGenerator01()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.Throws<ArgumentNullException>(() => new FastRng.Distributions.ChiSquareK1(null));
 | 
			
		||||
        }
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public void NoRandomNumberGenerator01()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.Throws<ArgumentNullException>(() => new FastRng.Distributions.ChiSquareK1(null));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -5,83 +5,82 @@ using System.Threading.Tasks;
 | 
			
		||||
using FastRng;
 | 
			
		||||
using NUnit.Framework;
 | 
			
		||||
 | 
			
		||||
namespace FastRngTests.Distributions
 | 
			
		||||
namespace FastRngTests.Distributions;
 | 
			
		||||
 | 
			
		||||
[ExcludeFromCodeCoverage]
 | 
			
		||||
public class ChiSquareK10
 | 
			
		||||
{
 | 
			
		||||
    [ExcludeFromCodeCoverage]
 | 
			
		||||
    public class ChiSquareK10
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestChiSquareDistribution01()
 | 
			
		||||
    {
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestChiSquareDistribution01()
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new FastRng.Distributions.ChiSquareK10(rng);
 | 
			
		||||
        var fqa = new FrequencyAnalysis();
 | 
			
		||||
 | 
			
		||||
        for (var n = 0; n < 100_000; n++)
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new FastRng.Distributions.ChiSquareK10(rng);
 | 
			
		||||
            var fqa = new FrequencyAnalysis();
 | 
			
		||||
 | 
			
		||||
            for (var n = 0; n < 100_000; n++)
 | 
			
		||||
            {
 | 
			
		||||
                var value = await dist.NextNumber();
 | 
			
		||||
                fqa.CountThis(value);
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            var result = fqa.NormalizeAndPlotEvents(TestContext.WriteLine);
 | 
			
		||||
 | 
			
		||||
            Assert.That(result[0], Is.EqualTo(0.0000000164021588f).Within(0.0000002f));
 | 
			
		||||
            Assert.That(result[1], Is.EqualTo(0.0000002611256437f).Within(0.000003f));
 | 
			
		||||
            Assert.That(result[2], Is.EqualTo(0.0000013153553250f).Within(0.00002f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[21], Is.EqualTo(0.003459320622874f).Within(0.005f));
 | 
			
		||||
            Assert.That(result[22], Is.EqualTo(0.004111875573379f).Within(0.005f));
 | 
			
		||||
            Assert.That(result[23], Is.EqualTo(0.004850674298859f).Within(0.005f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[50], Is.EqualTo(0.086418773275056f).Within(0.05f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[75], Is.EqualTo(0.376092741436046f).Within(0.08f));
 | 
			
		||||
            Assert.That(result[85], Is.EqualTo(0.586569751611096f).Within(0.08f));
 | 
			
		||||
            Assert.That(result[90], Is.EqualTo(0.717189736168766f).Within(0.08f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[97], Is.EqualTo(0.931477764640217f).Within(0.08f));
 | 
			
		||||
            Assert.That(result[98], Is.EqualTo(0.965244855212136f).Within(0.08f));
 | 
			
		||||
            Assert.That(result[99], Is.EqualTo(0.999827884370044f).Within(0.08f));
 | 
			
		||||
            var value = await dist.NextNumber();
 | 
			
		||||
            fqa.CountThis(value);
 | 
			
		||||
        }
 | 
			
		||||
            
 | 
			
		||||
        var result = fqa.NormalizeAndPlotEvents(TestContext.WriteLine);
 | 
			
		||||
 | 
			
		||||
        Assert.That(result[0], Is.EqualTo(0.0000000164021588f).Within(0.0000002f));
 | 
			
		||||
        Assert.That(result[1], Is.EqualTo(0.0000002611256437f).Within(0.000003f));
 | 
			
		||||
        Assert.That(result[2], Is.EqualTo(0.0000013153553250f).Within(0.00002f));
 | 
			
		||||
            
 | 
			
		||||
        Assert.That(result[21], Is.EqualTo(0.003459320622874f).Within(0.005f));
 | 
			
		||||
        Assert.That(result[22], Is.EqualTo(0.004111875573379f).Within(0.005f));
 | 
			
		||||
        Assert.That(result[23], Is.EqualTo(0.004850674298859f).Within(0.005f));
 | 
			
		||||
            
 | 
			
		||||
        Assert.That(result[50], Is.EqualTo(0.086418773275056f).Within(0.05f));
 | 
			
		||||
            
 | 
			
		||||
        Assert.That(result[75], Is.EqualTo(0.376092741436046f).Within(0.08f));
 | 
			
		||||
        Assert.That(result[85], Is.EqualTo(0.586569751611096f).Within(0.08f));
 | 
			
		||||
        Assert.That(result[90], Is.EqualTo(0.717189736168766f).Within(0.08f));
 | 
			
		||||
            
 | 
			
		||||
        Assert.That(result[97], Is.EqualTo(0.931477764640217f).Within(0.08f));
 | 
			
		||||
        Assert.That(result[98], Is.EqualTo(0.965244855212136f).Within(0.08f));
 | 
			
		||||
        Assert.That(result[99], Is.EqualTo(0.999827884370044f).Within(0.08f));
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestChiSquareGeneratorWithRange01()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new FastRng.Distributions.ChiSquareK10(rng);
 | 
			
		||||
            var samples = new float[1_000];
 | 
			
		||||
            for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
                samples[n] = await dist.NextNumber(-1.0f, 1.0f);
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestChiSquareGeneratorWithRange01()
 | 
			
		||||
    {
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new FastRng.Distributions.ChiSquareK10(rng);
 | 
			
		||||
        var samples = new float[1_000];
 | 
			
		||||
        for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
            samples[n] = await dist.NextNumber(-1.0f, 1.0f);
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range");
 | 
			
		||||
            Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range");
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range");
 | 
			
		||||
        Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range");
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestChiSquareGeneratorWithRange02()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new FastRng.Distributions.ChiSquareK10(rng);
 | 
			
		||||
            var samples = new float[1_000];
 | 
			
		||||
            for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
                samples[n] = await dist.NextNumber(0.0f, 1.0f);
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestChiSquareGeneratorWithRange02()
 | 
			
		||||
    {
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new FastRng.Distributions.ChiSquareK10(rng);
 | 
			
		||||
        var samples = new float[1_000];
 | 
			
		||||
        for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
            samples[n] = await dist.NextNumber(0.0f, 1.0f);
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range");
 | 
			
		||||
            Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range");
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range");
 | 
			
		||||
        Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public void NoRandomNumberGenerator01()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.Throws<ArgumentNullException>(() => new FastRng.Distributions.ChiSquareK10(null));
 | 
			
		||||
        }
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public void NoRandomNumberGenerator01()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.Throws<ArgumentNullException>(() => new FastRng.Distributions.ChiSquareK10(null));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -5,80 +5,79 @@ using System.Threading.Tasks;
 | 
			
		||||
using FastRng;
 | 
			
		||||
using NUnit.Framework;
 | 
			
		||||
 | 
			
		||||
namespace FastRngTests.Distributions
 | 
			
		||||
namespace FastRngTests.Distributions;
 | 
			
		||||
 | 
			
		||||
[ExcludeFromCodeCoverage]
 | 
			
		||||
public class ChiSquareK4
 | 
			
		||||
{
 | 
			
		||||
    [ExcludeFromCodeCoverage]
 | 
			
		||||
    public class ChiSquareK4
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestChiSquareDistribution01()
 | 
			
		||||
    {
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestChiSquareDistribution01()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new FastRng.Distributions.ChiSquareK4(rng);
 | 
			
		||||
            var fqa = new FrequencyAnalysis();
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new FastRng.Distributions.ChiSquareK4(rng);
 | 
			
		||||
        var fqa = new FrequencyAnalysis();
 | 
			
		||||
 | 
			
		||||
            for (var n = 0; n < 100_000; n++)
 | 
			
		||||
                fqa.CountThis(await dist.NextNumber());
 | 
			
		||||
        for (var n = 0; n < 100_000; n++)
 | 
			
		||||
            fqa.CountThis(await dist.NextNumber());
 | 
			
		||||
 | 
			
		||||
            var result = fqa.NormalizeAndPlotEvents(TestContext.WriteLine);
 | 
			
		||||
        var result = fqa.NormalizeAndPlotEvents(TestContext.WriteLine);
 | 
			
		||||
 | 
			
		||||
            Assert.That(result[0], Is.EqualTo(0.016417705906679f).Within(0.02f));
 | 
			
		||||
            Assert.That(result[1], Is.EqualTo(0.032671644513723f).Within(0.02f));
 | 
			
		||||
            Assert.That(result[2], Is.EqualTo(0.048763041010352f).Within(0.02f));
 | 
			
		||||
        Assert.That(result[0], Is.EqualTo(0.016417705906679f).Within(0.02f));
 | 
			
		||||
        Assert.That(result[1], Is.EqualTo(0.032671644513723f).Within(0.02f));
 | 
			
		||||
        Assert.That(result[2], Is.EqualTo(0.048763041010352f).Within(0.02f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[21], Is.EqualTo(0.32518779111264f).Within(0.05f));
 | 
			
		||||
            Assert.That(result[22], Is.EqualTo(0.338273451612642f).Within(0.05f));
 | 
			
		||||
            Assert.That(result[23], Is.EqualTo(0.351220492939994f).Within(0.05f));
 | 
			
		||||
        Assert.That(result[21], Is.EqualTo(0.32518779111264f).Within(0.05f));
 | 
			
		||||
        Assert.That(result[22], Is.EqualTo(0.338273451612642f).Within(0.05f));
 | 
			
		||||
        Assert.That(result[23], Is.EqualTo(0.351220492939994f).Within(0.05f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[50], Is.EqualTo(0.65209223303425f).Within(0.08f));
 | 
			
		||||
        Assert.That(result[50], Is.EqualTo(0.65209223303425f).Within(0.08f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[75], Is.EqualTo(0.857562207152294f).Within(0.099f));
 | 
			
		||||
            Assert.That(result[85], Is.EqualTo(0.923072405412387f).Within(0.099f));
 | 
			
		||||
            Assert.That(result[90], Is.EqualTo(0.952623623874265f).Within(0.099f));
 | 
			
		||||
        Assert.That(result[75], Is.EqualTo(0.857562207152294f).Within(0.099f));
 | 
			
		||||
        Assert.That(result[85], Is.EqualTo(0.923072405412387f).Within(0.099f));
 | 
			
		||||
        Assert.That(result[90], Is.EqualTo(0.952623623874265f).Within(0.099f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[97], Is.EqualTo(0.990616879396201f).Within(0.099f));
 | 
			
		||||
            Assert.That(result[98], Is.EqualTo(0.995734077068522f).Within(0.099f));
 | 
			
		||||
            Assert.That(result[99], Is.EqualTo(1.00077558852585f).Within(0.1f));
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(result[97], Is.EqualTo(0.990616879396201f).Within(0.099f));
 | 
			
		||||
        Assert.That(result[98], Is.EqualTo(0.995734077068522f).Within(0.099f));
 | 
			
		||||
        Assert.That(result[99], Is.EqualTo(1.00077558852585f).Within(0.1f));
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestChiSquareGeneratorWithRange01()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new FastRng.Distributions.ChiSquareK4(rng);
 | 
			
		||||
            var samples = new float[1_000];
 | 
			
		||||
            for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
                samples[n] = await dist.NextNumber(-1.0f, 1.0f);
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestChiSquareGeneratorWithRange01()
 | 
			
		||||
    {
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new FastRng.Distributions.ChiSquareK4(rng);
 | 
			
		||||
        var samples = new float[1_000];
 | 
			
		||||
        for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
            samples[n] = await dist.NextNumber(-1.0f, 1.0f);
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range");
 | 
			
		||||
            Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range");
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range");
 | 
			
		||||
        Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range");
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestChiSquareGeneratorWithRange02()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new FastRng.Distributions.ChiSquareK4(rng);
 | 
			
		||||
            var samples = new float[1_000];
 | 
			
		||||
            for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
                samples[n] = await dist.NextNumber(0.0f, 1.0f);
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestChiSquareGeneratorWithRange02()
 | 
			
		||||
    {
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new FastRng.Distributions.ChiSquareK4(rng);
 | 
			
		||||
        var samples = new float[1_000];
 | 
			
		||||
        for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
            samples[n] = await dist.NextNumber(0.0f, 1.0f);
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range");
 | 
			
		||||
            Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range");
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range");
 | 
			
		||||
        Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public void NoRandomNumberGenerator01()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.Throws<ArgumentNullException>(() => new FastRng.Distributions.ChiSquareK4(null));
 | 
			
		||||
        }
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public void NoRandomNumberGenerator01()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.Throws<ArgumentNullException>(() => new FastRng.Distributions.ChiSquareK4(null));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -5,80 +5,79 @@ using System.Threading.Tasks;
 | 
			
		||||
using FastRng;
 | 
			
		||||
using NUnit.Framework;
 | 
			
		||||
 | 
			
		||||
namespace FastRngTests.Distributions
 | 
			
		||||
namespace FastRngTests.Distributions;
 | 
			
		||||
 | 
			
		||||
[ExcludeFromCodeCoverage]
 | 
			
		||||
public class ExponentialLa10
 | 
			
		||||
{
 | 
			
		||||
    [ExcludeFromCodeCoverage]
 | 
			
		||||
    public class ExponentialLa10
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestExponentialDistribution01()
 | 
			
		||||
    {
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestExponentialDistribution01()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new FastRng.Distributions.ExponentialLa10(rng);
 | 
			
		||||
            var fqa = new FrequencyAnalysis();
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new FastRng.Distributions.ExponentialLa10(rng);
 | 
			
		||||
        var fqa = new FrequencyAnalysis();
 | 
			
		||||
            
 | 
			
		||||
            for (var n = 0; n < 100_000; n++)
 | 
			
		||||
                fqa.CountThis(await dist.NextNumber());
 | 
			
		||||
        for (var n = 0; n < 100_000; n++)
 | 
			
		||||
            fqa.CountThis(await dist.NextNumber());
 | 
			
		||||
            
 | 
			
		||||
            var result = fqa.NormalizeAndPlotEvents(TestContext.WriteLine);
 | 
			
		||||
        var result = fqa.NormalizeAndPlotEvents(TestContext.WriteLine);
 | 
			
		||||
 | 
			
		||||
            Assert.That(result[0], Is.EqualTo(1.00075018434777f).Within(0.05f));
 | 
			
		||||
            Assert.That(result[1], Is.EqualTo(0.905516212904248f).Within(0.05f));
 | 
			
		||||
            Assert.That(result[2], Is.EqualTo(0.81934495207398f).Within(0.05f));
 | 
			
		||||
        Assert.That(result[0], Is.EqualTo(1.00075018434777f).Within(0.05f));
 | 
			
		||||
        Assert.That(result[1], Is.EqualTo(0.905516212904248f).Within(0.05f));
 | 
			
		||||
        Assert.That(result[2], Is.EqualTo(0.81934495207398f).Within(0.05f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[21], Is.EqualTo(0.122548293148741f).Within(0.12f));
 | 
			
		||||
            Assert.That(result[22], Is.EqualTo(0.110886281157421f).Within(0.12f));
 | 
			
		||||
            Assert.That(result[23], Is.EqualTo(0.10033405633809f).Within(0.12f));
 | 
			
		||||
        Assert.That(result[21], Is.EqualTo(0.122548293148741f).Within(0.12f));
 | 
			
		||||
        Assert.That(result[22], Is.EqualTo(0.110886281157421f).Within(0.12f));
 | 
			
		||||
        Assert.That(result[23], Is.EqualTo(0.10033405633809f).Within(0.12f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[50], Is.EqualTo(0.00674300170146f).Within(0.005f));
 | 
			
		||||
        Assert.That(result[50], Is.EqualTo(0.00674300170146f).Within(0.005f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[75], Is.EqualTo(0.000553499285385f).Within(0.001f));
 | 
			
		||||
            Assert.That(result[85], Is.EqualTo(0.000203621007796f).Within(0.001f));
 | 
			
		||||
            Assert.That(result[90], Is.EqualTo(0.00012350238419f).Within(0.001f));
 | 
			
		||||
        Assert.That(result[75], Is.EqualTo(0.000553499285385f).Within(0.001f));
 | 
			
		||||
        Assert.That(result[85], Is.EqualTo(0.000203621007796f).Within(0.001f));
 | 
			
		||||
        Assert.That(result[90], Is.EqualTo(0.00012350238419f).Within(0.001f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[97], Is.EqualTo(0.0000613294689720f).Within(0.0008f));
 | 
			
		||||
            Assert.That(result[98], Is.EqualTo(0.0000554931983541f).Within(0.0008f));
 | 
			
		||||
            Assert.That(result[99], Is.EqualTo(0.0000502123223173f).Within(0.0008f));
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(result[97], Is.EqualTo(0.0000613294689720f).Within(0.0008f));
 | 
			
		||||
        Assert.That(result[98], Is.EqualTo(0.0000554931983541f).Within(0.0008f));
 | 
			
		||||
        Assert.That(result[99], Is.EqualTo(0.0000502123223173f).Within(0.0008f));
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestExponentialGeneratorWithRange01()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new FastRng.Distributions.ExponentialLa10(rng);
 | 
			
		||||
            var samples = new float[1_000];
 | 
			
		||||
            for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
                samples[n] = await dist.NextNumber(-1.0f, 1.0f);
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestExponentialGeneratorWithRange01()
 | 
			
		||||
    {
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new FastRng.Distributions.ExponentialLa10(rng);
 | 
			
		||||
        var samples = new float[1_000];
 | 
			
		||||
        for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
            samples[n] = await dist.NextNumber(-1.0f, 1.0f);
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range");
 | 
			
		||||
            Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range");
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range");
 | 
			
		||||
        Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range");
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestExponentialGeneratorWithRange02()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new FastRng.Distributions.ExponentialLa10(rng);
 | 
			
		||||
            var samples = new float[1_000];
 | 
			
		||||
            for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
                samples[n] = await dist.NextNumber(0.0f, 1.0f);
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestExponentialGeneratorWithRange02()
 | 
			
		||||
    {
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new FastRng.Distributions.ExponentialLa10(rng);
 | 
			
		||||
        var samples = new float[1_000];
 | 
			
		||||
        for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
            samples[n] = await dist.NextNumber(0.0f, 1.0f);
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range");
 | 
			
		||||
            Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range");
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range");
 | 
			
		||||
        Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public void NoRandomNumberGenerator01()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.Throws<ArgumentNullException>(() => new FastRng.Distributions.ExponentialLa10(null));
 | 
			
		||||
        }
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public void NoRandomNumberGenerator01()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.Throws<ArgumentNullException>(() => new FastRng.Distributions.ExponentialLa10(null));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -5,80 +5,79 @@ using System.Threading.Tasks;
 | 
			
		||||
using FastRng;
 | 
			
		||||
using NUnit.Framework;
 | 
			
		||||
 | 
			
		||||
namespace FastRngTests.Distributions
 | 
			
		||||
namespace FastRngTests.Distributions;
 | 
			
		||||
 | 
			
		||||
[ExcludeFromCodeCoverage]
 | 
			
		||||
public class ExponentialLa5
 | 
			
		||||
{
 | 
			
		||||
    [ExcludeFromCodeCoverage]
 | 
			
		||||
    public class ExponentialLa5
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestExponentialDistribution01()
 | 
			
		||||
    {
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestExponentialDistribution01()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new FastRng.Distributions.ExponentialLa5(rng);
 | 
			
		||||
            var fqa = new FrequencyAnalysis();
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new FastRng.Distributions.ExponentialLa5(rng);
 | 
			
		||||
        var fqa = new FrequencyAnalysis();
 | 
			
		||||
 | 
			
		||||
            for (var n = 0; n < 100_000; n++)
 | 
			
		||||
                fqa.CountThis(await dist.NextNumber());
 | 
			
		||||
        for (var n = 0; n < 100_000; n++)
 | 
			
		||||
            fqa.CountThis(await dist.NextNumber());
 | 
			
		||||
            
 | 
			
		||||
            var result = fqa.NormalizeAndPlotEvents(TestContext.WriteLine);
 | 
			
		||||
        var result = fqa.NormalizeAndPlotEvents(TestContext.WriteLine);
 | 
			
		||||
 | 
			
		||||
            Assert.That(result[0], Is.EqualTo(1.0002177398625f).Within(0.05f));
 | 
			
		||||
            Assert.That(result[1], Is.EqualTo(0.951436545064811f).Within(0.05f));
 | 
			
		||||
            Assert.That(result[2], Is.EqualTo(0.905034437210948f).Within(0.05f));
 | 
			
		||||
        Assert.That(result[0], Is.EqualTo(1.0002177398625f).Within(0.05f));
 | 
			
		||||
        Assert.That(result[1], Is.EqualTo(0.951436545064811f).Within(0.05f));
 | 
			
		||||
        Assert.That(result[2], Is.EqualTo(0.905034437210948f).Within(0.05f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[21], Is.EqualTo(0.35001394450853f).Within(0.05f));
 | 
			
		||||
            Assert.That(result[22], Is.EqualTo(0.332943563002074f).Within(0.05f));
 | 
			
		||||
            Assert.That(result[23], Is.EqualTo(0.31670571382568f).Within(0.05f));
 | 
			
		||||
        Assert.That(result[21], Is.EqualTo(0.35001394450853f).Within(0.05f));
 | 
			
		||||
        Assert.That(result[22], Is.EqualTo(0.332943563002074f).Within(0.05f));
 | 
			
		||||
        Assert.That(result[23], Is.EqualTo(0.31670571382568f).Within(0.05f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[50], Is.EqualTo(0.082102871800213f).Within(0.01f));
 | 
			
		||||
        Assert.That(result[50], Is.EqualTo(0.082102871800213f).Within(0.01f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[75], Is.EqualTo(0.023522866606758f).Within(0.01f));
 | 
			
		||||
            Assert.That(result[85], Is.EqualTo(0.014267339801329f).Within(0.01f));
 | 
			
		||||
            Assert.That(result[90], Is.EqualTo(0.011111415409621f).Within(0.01f));
 | 
			
		||||
        Assert.That(result[75], Is.EqualTo(0.023522866606758f).Within(0.01f));
 | 
			
		||||
        Assert.That(result[85], Is.EqualTo(0.014267339801329f).Within(0.01f));
 | 
			
		||||
        Assert.That(result[90], Is.EqualTo(0.011111415409621f).Within(0.01f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[97], Is.EqualTo(0.007830082099077f).Within(0.008f));
 | 
			
		||||
            Assert.That(result[98], Is.EqualTo(0.007448204488898f).Within(0.008f));
 | 
			
		||||
            Assert.That(result[99], Is.EqualTo(0.007084951269538f).Within(0.008f));
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(result[97], Is.EqualTo(0.007830082099077f).Within(0.008f));
 | 
			
		||||
        Assert.That(result[98], Is.EqualTo(0.007448204488898f).Within(0.008f));
 | 
			
		||||
        Assert.That(result[99], Is.EqualTo(0.007084951269538f).Within(0.008f));
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestExponentialGeneratorWithRange01()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new FastRng.Distributions.ExponentialLa5(rng);
 | 
			
		||||
            var samples = new float[1_000];
 | 
			
		||||
            for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
                samples[n] = await dist.NextNumber(-1.0f, 1.0f);
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestExponentialGeneratorWithRange01()
 | 
			
		||||
    {
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new FastRng.Distributions.ExponentialLa5(rng);
 | 
			
		||||
        var samples = new float[1_000];
 | 
			
		||||
        for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
            samples[n] = await dist.NextNumber(-1.0f, 1.0f);
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range");
 | 
			
		||||
            Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range");
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range");
 | 
			
		||||
        Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range");
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestExponentialGeneratorWithRange02()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new FastRng.Distributions.ExponentialLa5(rng);
 | 
			
		||||
            var samples = new float[1_000];
 | 
			
		||||
            for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
                samples[n] = await dist.NextNumber(0.0f, 1.0f);
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestExponentialGeneratorWithRange02()
 | 
			
		||||
    {
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new FastRng.Distributions.ExponentialLa5(rng);
 | 
			
		||||
        var samples = new float[1_000];
 | 
			
		||||
        for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
            samples[n] = await dist.NextNumber(0.0f, 1.0f);
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range");
 | 
			
		||||
            Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range");
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range");
 | 
			
		||||
        Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public void NoRandomNumberGenerator01()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.Throws<ArgumentNullException>(() => new FastRng.Distributions.ExponentialLa5(null));
 | 
			
		||||
        }
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public void NoRandomNumberGenerator01()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.Throws<ArgumentNullException>(() => new FastRng.Distributions.ExponentialLa5(null));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -5,80 +5,79 @@ using System.Threading.Tasks;
 | 
			
		||||
using FastRng;
 | 
			
		||||
using NUnit.Framework;
 | 
			
		||||
 | 
			
		||||
namespace FastRngTests.Distributions
 | 
			
		||||
namespace FastRngTests.Distributions;
 | 
			
		||||
 | 
			
		||||
[ExcludeFromCodeCoverage]
 | 
			
		||||
public class GammaA5B15
 | 
			
		||||
{
 | 
			
		||||
    [ExcludeFromCodeCoverage]
 | 
			
		||||
    public class GammaA5B15
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestGammaDistribution01()
 | 
			
		||||
    {
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestGammaDistribution01()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new FastRng.Distributions.GammaA5B15(rng);
 | 
			
		||||
            var fra = new FrequencyAnalysis();
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new FastRng.Distributions.GammaA5B15(rng);
 | 
			
		||||
        var fra = new FrequencyAnalysis();
 | 
			
		||||
            
 | 
			
		||||
            for (var n = 0; n < 100_000; n++)
 | 
			
		||||
                fra.CountThis(await dist.NextNumber());
 | 
			
		||||
        for (var n = 0; n < 100_000; n++)
 | 
			
		||||
            fra.CountThis(await dist.NextNumber());
 | 
			
		||||
            
 | 
			
		||||
            var result = fra.NormalizeAndPlotEvents(TestContext.WriteLine);
 | 
			
		||||
        var result = fra.NormalizeAndPlotEvents(TestContext.WriteLine);
 | 
			
		||||
 | 
			
		||||
            Assert.That(result[0], Is.EqualTo(0.0000929594237282f).Within(0.0008f));
 | 
			
		||||
            Assert.That(result[1], Is.EqualTo(0.0012801746797876f).Within(0.002f));
 | 
			
		||||
            Assert.That(result[2], Is.EqualTo(0.0055781488254349f).Within(0.004f));
 | 
			
		||||
        Assert.That(result[0], Is.EqualTo(0.0000929594237282f).Within(0.0008f));
 | 
			
		||||
        Assert.That(result[1], Is.EqualTo(0.0012801746797876f).Within(0.002f));
 | 
			
		||||
        Assert.That(result[2], Is.EqualTo(0.0055781488254349f).Within(0.004f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[21], Is.EqualTo(0.9331608887752720f).Within(0.09f));
 | 
			
		||||
            Assert.That(result[22], Is.EqualTo(0.9594734828891280f).Within(0.09f));
 | 
			
		||||
            Assert.That(result[23], Is.EqualTo(0.9790895765535350f).Within(0.09f));
 | 
			
		||||
        Assert.That(result[21], Is.EqualTo(0.9331608887752720f).Within(0.09f));
 | 
			
		||||
        Assert.That(result[22], Is.EqualTo(0.9594734828891280f).Within(0.09f));
 | 
			
		||||
        Assert.That(result[23], Is.EqualTo(0.9790895765535350f).Within(0.09f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[50], Is.EqualTo(0.3478287795336570f).Within(0.06f));
 | 
			
		||||
        Assert.That(result[50], Is.EqualTo(0.3478287795336570f).Within(0.06f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[75], Is.EqualTo(0.0403399049422936f).Within(0.009f));
 | 
			
		||||
            Assert.That(result[85], Is.EqualTo(0.0163628388658126f).Within(0.009f));
 | 
			
		||||
            Assert.That(result[90], Is.EqualTo(0.0097147611446660f).Within(0.005f));
 | 
			
		||||
        Assert.That(result[75], Is.EqualTo(0.0403399049422936f).Within(0.009f));
 | 
			
		||||
        Assert.That(result[85], Is.EqualTo(0.0163628388658126f).Within(0.009f));
 | 
			
		||||
        Assert.That(result[90], Is.EqualTo(0.0097147611446660f).Within(0.005f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[97], Is.EqualTo(0.0041135143233153f).Within(0.008f));
 | 
			
		||||
            Assert.That(result[98], Is.EqualTo(0.0036872732029996f).Within(0.008f));
 | 
			
		||||
            Assert.That(result[99], Is.EqualTo(0.0033038503429554f).Within(0.008f));
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(result[97], Is.EqualTo(0.0041135143233153f).Within(0.008f));
 | 
			
		||||
        Assert.That(result[98], Is.EqualTo(0.0036872732029996f).Within(0.008f));
 | 
			
		||||
        Assert.That(result[99], Is.EqualTo(0.0033038503429554f).Within(0.008f));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestGammaGeneratorWithRange01()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new FastRng.Distributions.GammaA5B15(rng);
 | 
			
		||||
            var samples = new float[1_000];
 | 
			
		||||
            for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
                samples[n] = await dist.NextNumber(-1.0f, 1.0f);
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestGammaGeneratorWithRange01()
 | 
			
		||||
    {
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new FastRng.Distributions.GammaA5B15(rng);
 | 
			
		||||
        var samples = new float[1_000];
 | 
			
		||||
        for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
            samples[n] = await dist.NextNumber(-1.0f, 1.0f);
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min is out of range");
 | 
			
		||||
            Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range");
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min is out of range");
 | 
			
		||||
        Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range");
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestGammaGeneratorWithRange02()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new FastRng.Distributions.GammaA5B15(rng);
 | 
			
		||||
            var samples = new float[1_000];
 | 
			
		||||
            for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
                samples[n] = await dist.NextNumber(0.0f, 1.0f);
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestGammaGeneratorWithRange02()
 | 
			
		||||
    {
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new FastRng.Distributions.GammaA5B15(rng);
 | 
			
		||||
        var samples = new float[1_000];
 | 
			
		||||
        for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
            samples[n] = await dist.NextNumber(0.0f, 1.0f);
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range");
 | 
			
		||||
            Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range");
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range");
 | 
			
		||||
        Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public void NoRandomNumberGenerator01()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.Throws<ArgumentNullException>(() => new FastRng.Distributions.GammaA5B15(null));
 | 
			
		||||
        }
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public void NoRandomNumberGenerator01()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.Throws<ArgumentNullException>(() => new FastRng.Distributions.GammaA5B15(null));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -5,80 +5,79 @@ using System.Threading.Tasks;
 | 
			
		||||
using FastRng;
 | 
			
		||||
using NUnit.Framework;
 | 
			
		||||
 | 
			
		||||
namespace FastRngTests.Distributions
 | 
			
		||||
namespace FastRngTests.Distributions;
 | 
			
		||||
 | 
			
		||||
[ExcludeFromCodeCoverage]
 | 
			
		||||
public class InverseExponentialLa10
 | 
			
		||||
{
 | 
			
		||||
    [ExcludeFromCodeCoverage]
 | 
			
		||||
    public class InverseExponentialLa10
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestExponentialDistribution01()
 | 
			
		||||
    {
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestExponentialDistribution01()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new FastRng.Distributions.InverseExponentialLa10(rng);
 | 
			
		||||
            var fqa = new FrequencyAnalysis();
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new FastRng.Distributions.InverseExponentialLa10(rng);
 | 
			
		||||
        var fqa = new FrequencyAnalysis();
 | 
			
		||||
            
 | 
			
		||||
            for (var n = 0; n < 100_000; n++)
 | 
			
		||||
                fqa.CountThis(await dist.NextNumber());
 | 
			
		||||
        for (var n = 0; n < 100_000; n++)
 | 
			
		||||
            fqa.CountThis(await dist.NextNumber());
 | 
			
		||||
            
 | 
			
		||||
            var result = fqa.NormalizeAndPlotEvents(TestContext.WriteLine);
 | 
			
		||||
        var result = fqa.NormalizeAndPlotEvents(TestContext.WriteLine);
 | 
			
		||||
 | 
			
		||||
            Assert.That(result[0], Is.EqualTo(0.0000501746820562f).Within(0.0003f));
 | 
			
		||||
            Assert.That(result[1], Is.EqualTo(0.0000554515994322f).Within(0.0003f));
 | 
			
		||||
            Assert.That(result[2], Is.EqualTo(0.0000612834950532f).Within(0.0003f));
 | 
			
		||||
        Assert.That(result[0], Is.EqualTo(0.0000501746820562f).Within(0.0003f));
 | 
			
		||||
        Assert.That(result[1], Is.EqualTo(0.0000554515994322f).Within(0.0003f));
 | 
			
		||||
        Assert.That(result[2], Is.EqualTo(0.0000612834950532f).Within(0.0003f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[21], Is.EqualTo(0.00040973497898f).Within(0.00045f));
 | 
			
		||||
            Assert.That(result[22], Is.EqualTo(0.000452827182887f).Within(0.00050f));
 | 
			
		||||
            Assert.That(result[23], Is.EqualTo(0.000500451433441f).Within(0.0006f));
 | 
			
		||||
        Assert.That(result[21], Is.EqualTo(0.00040973497898f).Within(0.00045f));
 | 
			
		||||
        Assert.That(result[22], Is.EqualTo(0.000452827182887f).Within(0.00050f));
 | 
			
		||||
        Assert.That(result[23], Is.EqualTo(0.000500451433441f).Within(0.0006f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[50], Is.EqualTo(0.007446583070924f).Within(0.003f));
 | 
			
		||||
        Assert.That(result[50], Is.EqualTo(0.007446583070924f).Within(0.003f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[75], Is.EqualTo(0.090717953289412f).Within(0.02f));
 | 
			
		||||
            Assert.That(result[85], Is.EqualTo(0.246596963941606f).Within(0.05f));
 | 
			
		||||
            Assert.That(result[90], Is.EqualTo(0.406569659740598f).Within(0.08f));
 | 
			
		||||
        Assert.That(result[75], Is.EqualTo(0.090717953289412f).Within(0.02f));
 | 
			
		||||
        Assert.That(result[85], Is.EqualTo(0.246596963941606f).Within(0.05f));
 | 
			
		||||
        Assert.That(result[90], Is.EqualTo(0.406569659740598f).Within(0.08f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[97], Is.EqualTo(0.81873075307798f).Within(0.08f));
 | 
			
		||||
            Assert.That(result[98], Is.EqualTo(0.904837418035957f).Within(0.08f));
 | 
			
		||||
            Assert.That(result[99], Is.EqualTo(0.999999999999999f).Within(0.08f));
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(result[97], Is.EqualTo(0.81873075307798f).Within(0.08f));
 | 
			
		||||
        Assert.That(result[98], Is.EqualTo(0.904837418035957f).Within(0.08f));
 | 
			
		||||
        Assert.That(result[99], Is.EqualTo(0.999999999999999f).Within(0.08f));
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestExponentialGeneratorWithRange01()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new FastRng.Distributions.InverseExponentialLa10(rng);
 | 
			
		||||
            var samples = new float[1_000];
 | 
			
		||||
            for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
                samples[n] = await dist.NextNumber(-1.0f, 1.0f);
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestExponentialGeneratorWithRange01()
 | 
			
		||||
    {
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new FastRng.Distributions.InverseExponentialLa10(rng);
 | 
			
		||||
        var samples = new float[1_000];
 | 
			
		||||
        for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
            samples[n] = await dist.NextNumber(-1.0f, 1.0f);
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range");
 | 
			
		||||
            Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range");
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range");
 | 
			
		||||
        Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range");
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestExponentialGeneratorWithRange02()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new FastRng.Distributions.InverseExponentialLa10(rng);
 | 
			
		||||
            var samples = new float[1_000];
 | 
			
		||||
            for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
                samples[n] = await dist.NextNumber(0.0f, 1.0f);
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestExponentialGeneratorWithRange02()
 | 
			
		||||
    {
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new FastRng.Distributions.InverseExponentialLa10(rng);
 | 
			
		||||
        var samples = new float[1_000];
 | 
			
		||||
        for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
            samples[n] = await dist.NextNumber(0.0f, 1.0f);
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range");
 | 
			
		||||
            Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range");
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range");
 | 
			
		||||
        Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public void NoRandomNumberGenerator01()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.Throws<ArgumentNullException>(() => new FastRng.Distributions.InverseExponentialLa10(null));
 | 
			
		||||
        }
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public void NoRandomNumberGenerator01()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.Throws<ArgumentNullException>(() => new FastRng.Distributions.InverseExponentialLa10(null));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -5,80 +5,79 @@ using System.Threading.Tasks;
 | 
			
		||||
using FastRng;
 | 
			
		||||
using NUnit.Framework;
 | 
			
		||||
 | 
			
		||||
namespace FastRngTests.Distributions
 | 
			
		||||
namespace FastRngTests.Distributions;
 | 
			
		||||
 | 
			
		||||
[ExcludeFromCodeCoverage]
 | 
			
		||||
public class InverseExponentialLa5
 | 
			
		||||
{
 | 
			
		||||
    [ExcludeFromCodeCoverage]
 | 
			
		||||
    public class InverseExponentialLa5
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestExponentialDistribution01()
 | 
			
		||||
    {
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestExponentialDistribution01()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new FastRng.Distributions.InverseExponentialLa5(rng);
 | 
			
		||||
            var fqa = new FrequencyAnalysis();
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new FastRng.Distributions.InverseExponentialLa5(rng);
 | 
			
		||||
        var fqa = new FrequencyAnalysis();
 | 
			
		||||
            
 | 
			
		||||
            for (var n = 0; n < 100_000; n++)
 | 
			
		||||
                fqa.CountThis(await dist.NextNumber());
 | 
			
		||||
        for (var n = 0; n < 100_000; n++)
 | 
			
		||||
            fqa.CountThis(await dist.NextNumber());
 | 
			
		||||
            
 | 
			
		||||
            var result = fqa.NormalizeAndPlotEvents(TestContext.WriteLine);
 | 
			
		||||
        var result = fqa.NormalizeAndPlotEvents(TestContext.WriteLine);
 | 
			
		||||
 | 
			
		||||
            Assert.That(result[0], Is.EqualTo(0.007083408929052f).Within(0.008f));
 | 
			
		||||
            Assert.That(result[1], Is.EqualTo(0.007446583070924f).Within(0.008f));
 | 
			
		||||
            Assert.That(result[2], Is.EqualTo(0.007828377549226f).Within(0.008f));
 | 
			
		||||
        Assert.That(result[0], Is.EqualTo(0.007083408929052f).Within(0.008f));
 | 
			
		||||
        Assert.That(result[1], Is.EqualTo(0.007446583070924f).Within(0.008f));
 | 
			
		||||
        Assert.That(result[2], Is.EqualTo(0.007828377549226f).Within(0.008f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[21], Is.EqualTo(0.020241911445804f).Within(0.05f));
 | 
			
		||||
            Assert.That(result[22], Is.EqualTo(0.021279736438377f).Within(0.05f));
 | 
			
		||||
            Assert.That(result[23], Is.EqualTo(0.022370771856166f).Within(0.05f));
 | 
			
		||||
        Assert.That(result[21], Is.EqualTo(0.020241911445804f).Within(0.05f));
 | 
			
		||||
        Assert.That(result[22], Is.EqualTo(0.021279736438377f).Within(0.05f));
 | 
			
		||||
        Assert.That(result[23], Is.EqualTo(0.022370771856166f).Within(0.05f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[50], Is.EqualTo(0.08629358649937f).Within(0.02f));
 | 
			
		||||
        Assert.That(result[50], Is.EqualTo(0.08629358649937f).Within(0.02f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[75], Is.EqualTo(0.301194211912202f).Within(0.03f));
 | 
			
		||||
            Assert.That(result[85], Is.EqualTo(0.496585303791409f).Within(0.05f));
 | 
			
		||||
            Assert.That(result[90], Is.EqualTo(0.637628151621772f).Within(0.06f));
 | 
			
		||||
        Assert.That(result[75], Is.EqualTo(0.301194211912202f).Within(0.03f));
 | 
			
		||||
        Assert.That(result[85], Is.EqualTo(0.496585303791409f).Within(0.05f));
 | 
			
		||||
        Assert.That(result[90], Is.EqualTo(0.637628151621772f).Within(0.06f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[97], Is.EqualTo(0.904837418035959f).Within(0.08f));
 | 
			
		||||
            Assert.That(result[98], Is.EqualTo(0.951229424500713f).Within(0.08f));
 | 
			
		||||
            Assert.That(result[99], Is.EqualTo(1f).Within(0.08f));
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(result[97], Is.EqualTo(0.904837418035959f).Within(0.08f));
 | 
			
		||||
        Assert.That(result[98], Is.EqualTo(0.951229424500713f).Within(0.08f));
 | 
			
		||||
        Assert.That(result[99], Is.EqualTo(1f).Within(0.08f));
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestExponentialGeneratorWithRange01()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new FastRng.Distributions.InverseExponentialLa5(rng);
 | 
			
		||||
            var samples = new float[1_000];
 | 
			
		||||
            for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
                samples[n] = await dist.NextNumber(-1.0f, 1.0f);
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestExponentialGeneratorWithRange01()
 | 
			
		||||
    {
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new FastRng.Distributions.InverseExponentialLa5(rng);
 | 
			
		||||
        var samples = new float[1_000];
 | 
			
		||||
        for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
            samples[n] = await dist.NextNumber(-1.0f, 1.0f);
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range");
 | 
			
		||||
            Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range");
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range");
 | 
			
		||||
        Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range");
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestExponentialGeneratorWithRange02()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new FastRng.Distributions.InverseExponentialLa5(rng);
 | 
			
		||||
            var samples = new float[1_000];
 | 
			
		||||
            for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
                samples[n] = await dist.NextNumber(0.0f, 1.0f);
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestExponentialGeneratorWithRange02()
 | 
			
		||||
    {
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new FastRng.Distributions.InverseExponentialLa5(rng);
 | 
			
		||||
        var samples = new float[1_000];
 | 
			
		||||
        for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
            samples[n] = await dist.NextNumber(0.0f, 1.0f);
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range");
 | 
			
		||||
            Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range");
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range");
 | 
			
		||||
        Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public void NoRandomNumberGenerator01()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.Throws<ArgumentNullException>(() => new FastRng.Distributions.InverseExponentialLa5(null));
 | 
			
		||||
        }
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public void NoRandomNumberGenerator01()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.Throws<ArgumentNullException>(() => new FastRng.Distributions.InverseExponentialLa5(null));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -5,80 +5,79 @@ using System.Threading.Tasks;
 | 
			
		||||
using FastRng;
 | 
			
		||||
using NUnit.Framework;
 | 
			
		||||
 | 
			
		||||
namespace FastRngTests.Distributions
 | 
			
		||||
namespace FastRngTests.Distributions;
 | 
			
		||||
 | 
			
		||||
[ExcludeFromCodeCoverage]
 | 
			
		||||
public class InverseGammaA3B05
 | 
			
		||||
{
 | 
			
		||||
    [ExcludeFromCodeCoverage]
 | 
			
		||||
    public class InverseGammaA3B05
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestInverseGammaDistribution01()
 | 
			
		||||
    {
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestInverseGammaDistribution01()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new FastRng.Distributions.InverseGammaA3B05(rng);
 | 
			
		||||
            var fra = new FrequencyAnalysis();
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new FastRng.Distributions.InverseGammaA3B05(rng);
 | 
			
		||||
        var fra = new FrequencyAnalysis();
 | 
			
		||||
            
 | 
			
		||||
            for (var n = 0; n < 100_000; n++)
 | 
			
		||||
                fra.CountThis(await dist.NextNumber());
 | 
			
		||||
        for (var n = 0; n < 100_000; n++)
 | 
			
		||||
            fra.CountThis(await dist.NextNumber());
 | 
			
		||||
            
 | 
			
		||||
            var result = fra.NormalizeAndPlotEvents(TestContext.WriteLine);
 | 
			
		||||
        var result = fra.NormalizeAndPlotEvents(TestContext.WriteLine);
 | 
			
		||||
 | 
			
		||||
            Assert.That(result[0], Is.EqualTo(0.0000000000000003f).Within(0.0000001f));
 | 
			
		||||
            Assert.That(result[1], Is.EqualTo(0.0000011605257228f).Within(0.00001f));
 | 
			
		||||
            Assert.That(result[2], Is.EqualTo(0.0009536970016103f).Within(0.0015f));
 | 
			
		||||
        Assert.That(result[0], Is.EqualTo(0.0000000000000003f).Within(0.0000001f));
 | 
			
		||||
        Assert.That(result[1], Is.EqualTo(0.0000011605257228f).Within(0.00001f));
 | 
			
		||||
        Assert.That(result[2], Is.EqualTo(0.0009536970016103f).Within(0.0015f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[21], Is.EqualTo(0.5880485243048120f).Within(0.05f));
 | 
			
		||||
            Assert.That(result[22], Is.EqualTo(0.5433842148912880f).Within(0.05f));
 | 
			
		||||
            Assert.That(result[23], Is.EqualTo(0.5017780549216030f).Within(0.05f));
 | 
			
		||||
        Assert.That(result[21], Is.EqualTo(0.5880485243048120f).Within(0.05f));
 | 
			
		||||
        Assert.That(result[22], Is.EqualTo(0.5433842148912880f).Within(0.05f));
 | 
			
		||||
        Assert.That(result[23], Is.EqualTo(0.5017780549216030f).Within(0.05f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[50], Is.EqualTo(0.0741442015957425f).Within(0.009f));
 | 
			
		||||
        Assert.That(result[50], Is.EqualTo(0.0741442015957425f).Within(0.009f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[75], Is.EqualTo(0.0207568945092484f).Within(0.006f));
 | 
			
		||||
            Assert.That(result[85], Is.EqualTo(0.0136661506653688f).Within(0.006f));
 | 
			
		||||
            Assert.That(result[90], Is.EqualTo(0.0112550619601327f).Within(0.006f));
 | 
			
		||||
        Assert.That(result[75], Is.EqualTo(0.0207568945092484f).Within(0.006f));
 | 
			
		||||
        Assert.That(result[85], Is.EqualTo(0.0136661506653688f).Within(0.006f));
 | 
			
		||||
        Assert.That(result[90], Is.EqualTo(0.0112550619601327f).Within(0.006f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[97], Is.EqualTo(0.0087026933539773f).Within(0.005f));
 | 
			
		||||
            Assert.That(result[98], Is.EqualTo(0.0083995375385004f).Within(0.005f));
 | 
			
		||||
            Assert.That(result[99], Is.EqualTo(0.0081094156379928f).Within(0.005f));
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(result[97], Is.EqualTo(0.0087026933539773f).Within(0.005f));
 | 
			
		||||
        Assert.That(result[98], Is.EqualTo(0.0083995375385004f).Within(0.005f));
 | 
			
		||||
        Assert.That(result[99], Is.EqualTo(0.0081094156379928f).Within(0.005f));
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestInverseGammaGeneratorWithRange01()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new FastRng.Distributions.InverseGammaA3B05(rng);
 | 
			
		||||
            var samples = new float[1_000];
 | 
			
		||||
            for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
                samples[n] = await dist.NextNumber(-1.0f, 1.0f);
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestInverseGammaGeneratorWithRange01()
 | 
			
		||||
    {
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new FastRng.Distributions.InverseGammaA3B05(rng);
 | 
			
		||||
        var samples = new float[1_000];
 | 
			
		||||
        for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
            samples[n] = await dist.NextNumber(-1.0f, 1.0f);
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range");
 | 
			
		||||
            Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range");
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range");
 | 
			
		||||
        Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range");
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestInverseGammaGeneratorWithRange02()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new FastRng.Distributions.InverseGammaA3B05(rng);
 | 
			
		||||
            var samples = new float[1_000];
 | 
			
		||||
            for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
                samples[n] = await dist.NextNumber(0.0f, 1.0f);
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestInverseGammaGeneratorWithRange02()
 | 
			
		||||
    {
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new FastRng.Distributions.InverseGammaA3B05(rng);
 | 
			
		||||
        var samples = new float[1_000];
 | 
			
		||||
        for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
            samples[n] = await dist.NextNumber(0.0f, 1.0f);
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range");
 | 
			
		||||
            Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range");
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range");
 | 
			
		||||
        Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public void NoRandomNumberGenerator01()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.Throws<ArgumentNullException>(() => new FastRng.Distributions.InverseGammaA3B05(null));
 | 
			
		||||
        }
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public void NoRandomNumberGenerator01()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.Throws<ArgumentNullException>(() => new FastRng.Distributions.InverseGammaA3B05(null));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -5,80 +5,79 @@ using System.Threading.Tasks;
 | 
			
		||||
using FastRng;
 | 
			
		||||
using NUnit.Framework;
 | 
			
		||||
 | 
			
		||||
namespace FastRngTests.Distributions
 | 
			
		||||
namespace FastRngTests.Distributions;
 | 
			
		||||
 | 
			
		||||
[ExcludeFromCodeCoverage]
 | 
			
		||||
public class LaplaceB01M0
 | 
			
		||||
{
 | 
			
		||||
    [ExcludeFromCodeCoverage]
 | 
			
		||||
    public class LaplaceB01M0
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestLaplaceDistribution01()
 | 
			
		||||
    {
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestLaplaceDistribution01()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new FastRng.Distributions.LaplaceB01M0(rng);
 | 
			
		||||
            var fra = new FrequencyAnalysis();
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new FastRng.Distributions.LaplaceB01M0(rng);
 | 
			
		||||
        var fra = new FrequencyAnalysis();
 | 
			
		||||
            
 | 
			
		||||
            for (var n = 0; n < 100_000; n++)
 | 
			
		||||
                fra.CountThis(await dist.NextNumber());
 | 
			
		||||
        for (var n = 0; n < 100_000; n++)
 | 
			
		||||
            fra.CountThis(await dist.NextNumber());
 | 
			
		||||
            
 | 
			
		||||
            var result = fra.NormalizeAndPlotEvents(TestContext.WriteLine);
 | 
			
		||||
        var result = fra.NormalizeAndPlotEvents(TestContext.WriteLine);
 | 
			
		||||
 | 
			
		||||
            Assert.That(result[0], Is.EqualTo(1.0000000000000000f).Within(0.05f));
 | 
			
		||||
            Assert.That(result[1], Is.EqualTo(0.9048374180359590f).Within(0.05f));
 | 
			
		||||
            Assert.That(result[2], Is.EqualTo(0.8187307530779810f).Within(0.05f));
 | 
			
		||||
        Assert.That(result[0], Is.EqualTo(1.0000000000000000f).Within(0.05f));
 | 
			
		||||
        Assert.That(result[1], Is.EqualTo(0.9048374180359590f).Within(0.05f));
 | 
			
		||||
        Assert.That(result[2], Is.EqualTo(0.8187307530779810f).Within(0.05f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[21], Is.EqualTo(0.1224564282529820f).Within(0.05f));
 | 
			
		||||
            Assert.That(result[22], Is.EqualTo(0.1108031583623340f).Within(0.05f));
 | 
			
		||||
            Assert.That(result[23], Is.EqualTo(0.1002588437228040f).Within(0.05f));
 | 
			
		||||
        Assert.That(result[21], Is.EqualTo(0.1224564282529820f).Within(0.05f));
 | 
			
		||||
        Assert.That(result[22], Is.EqualTo(0.1108031583623340f).Within(0.05f));
 | 
			
		||||
        Assert.That(result[23], Is.EqualTo(0.1002588437228040f).Within(0.05f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[50], Is.EqualTo(0.0067379469990855f).Within(0.003f));
 | 
			
		||||
        Assert.That(result[50], Is.EqualTo(0.0067379469990855f).Within(0.003f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[75], Is.EqualTo(0.0005530843701478f).Within(0.0015f));
 | 
			
		||||
            Assert.That(result[85], Is.EqualTo(0.0002034683690106f).Within(0.0015f));
 | 
			
		||||
            Assert.That(result[90], Is.EqualTo(0.0001234098040867f).Within(0.0015f));
 | 
			
		||||
        Assert.That(result[75], Is.EqualTo(0.0005530843701478f).Within(0.0015f));
 | 
			
		||||
        Assert.That(result[85], Is.EqualTo(0.0002034683690106f).Within(0.0015f));
 | 
			
		||||
        Assert.That(result[90], Is.EqualTo(0.0001234098040867f).Within(0.0015f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[97], Is.EqualTo(0.0000612834950532f).Within(0.0002f));
 | 
			
		||||
            Assert.That(result[98], Is.EqualTo(0.0000554515994322f).Within(0.0002f));
 | 
			
		||||
            Assert.That(result[99], Is.EqualTo(0.0000501746820562f).Within(0.0002f));
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(result[97], Is.EqualTo(0.0000612834950532f).Within(0.0002f));
 | 
			
		||||
        Assert.That(result[98], Is.EqualTo(0.0000554515994322f).Within(0.0002f));
 | 
			
		||||
        Assert.That(result[99], Is.EqualTo(0.0000501746820562f).Within(0.0002f));
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestLaplaceGeneratorWithRange01()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new FastRng.Distributions.LaplaceB01M0(rng);
 | 
			
		||||
            var samples = new float[1_000];
 | 
			
		||||
            for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
                samples[n] = await dist.NextNumber(-1.0f, 1.0f);
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestLaplaceGeneratorWithRange01()
 | 
			
		||||
    {
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new FastRng.Distributions.LaplaceB01M0(rng);
 | 
			
		||||
        var samples = new float[1_000];
 | 
			
		||||
        for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
            samples[n] = await dist.NextNumber(-1.0f, 1.0f);
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range");
 | 
			
		||||
            Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range");
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range");
 | 
			
		||||
        Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range");
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestLaplaceGeneratorWithRange02()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new FastRng.Distributions.LaplaceB01M0(rng);
 | 
			
		||||
            var samples = new float[1_000];
 | 
			
		||||
            for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
                samples[n] = await dist.NextNumber(0.0f, 1.0f);
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestLaplaceGeneratorWithRange02()
 | 
			
		||||
    {
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new FastRng.Distributions.LaplaceB01M0(rng);
 | 
			
		||||
        var samples = new float[1_000];
 | 
			
		||||
        for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
            samples[n] = await dist.NextNumber(0.0f, 1.0f);
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range");
 | 
			
		||||
            Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range");
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range");
 | 
			
		||||
        Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public void NoRandomNumberGenerator01()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.Throws<ArgumentNullException>(() => new FastRng.Distributions.LaplaceB01M0(null));
 | 
			
		||||
        }
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public void NoRandomNumberGenerator01()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.Throws<ArgumentNullException>(() => new FastRng.Distributions.LaplaceB01M0(null));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -5,80 +5,79 @@ using System.Threading.Tasks;
 | 
			
		||||
using FastRng;
 | 
			
		||||
using NUnit.Framework;
 | 
			
		||||
 | 
			
		||||
namespace FastRngTests.Distributions
 | 
			
		||||
namespace FastRngTests.Distributions;
 | 
			
		||||
 | 
			
		||||
[ExcludeFromCodeCoverage]
 | 
			
		||||
public class LaplaceB01M05
 | 
			
		||||
{
 | 
			
		||||
    [ExcludeFromCodeCoverage]
 | 
			
		||||
    public class LaplaceB01M05
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestLaplaceDistribution01()
 | 
			
		||||
    {
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestLaplaceDistribution01()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new FastRng.Distributions.LaplaceB01M05(rng);
 | 
			
		||||
            var fra = new FrequencyAnalysis();
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new FastRng.Distributions.LaplaceB01M05(rng);
 | 
			
		||||
        var fra = new FrequencyAnalysis();
 | 
			
		||||
            
 | 
			
		||||
            for (var n = 0; n < 100_000; n++)
 | 
			
		||||
                fra.CountThis(await dist.NextNumber());
 | 
			
		||||
        for (var n = 0; n < 100_000; n++)
 | 
			
		||||
            fra.CountThis(await dist.NextNumber());
 | 
			
		||||
            
 | 
			
		||||
            var result = fra.NormalizeAndPlotEvents(TestContext.WriteLine);
 | 
			
		||||
        var result = fra.NormalizeAndPlotEvents(TestContext.WriteLine);
 | 
			
		||||
 | 
			
		||||
            Assert.That(result[0], Is.EqualTo(0.0074465830709244f).Within(0.004f));
 | 
			
		||||
            Assert.That(result[1], Is.EqualTo(0.0082297470490200f).Within(0.004f));
 | 
			
		||||
            Assert.That(result[2], Is.EqualTo(0.0090952771016958f).Within(0.01f));
 | 
			
		||||
        Assert.That(result[0], Is.EqualTo(0.0074465830709244f).Within(0.004f));
 | 
			
		||||
        Assert.That(result[1], Is.EqualTo(0.0082297470490200f).Within(0.004f));
 | 
			
		||||
        Assert.That(result[2], Is.EqualTo(0.0090952771016958f).Within(0.01f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[21], Is.EqualTo(0.0608100626252180f).Within(0.02f));
 | 
			
		||||
            Assert.That(result[22], Is.EqualTo(0.0672055127397498f).Within(0.02f));
 | 
			
		||||
            Assert.That(result[23], Is.EqualTo(0.0742735782143340f).Within(0.02f));
 | 
			
		||||
        Assert.That(result[21], Is.EqualTo(0.0608100626252180f).Within(0.02f));
 | 
			
		||||
        Assert.That(result[22], Is.EqualTo(0.0672055127397498f).Within(0.02f));
 | 
			
		||||
        Assert.That(result[23], Is.EqualTo(0.0742735782143340f).Within(0.02f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[50], Is.EqualTo(1.0000000000000000f).Within(0.2f));
 | 
			
		||||
        Assert.That(result[50], Is.EqualTo(1.0000000000000000f).Within(0.2f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[75], Is.EqualTo(0.0742735782143335f).Within(0.01f));
 | 
			
		||||
            Assert.That(result[85], Is.EqualTo(0.0273237224472924f).Within(0.01f));
 | 
			
		||||
            Assert.That(result[90], Is.EqualTo(0.0165726754017612f).Within(0.01f));
 | 
			
		||||
        Assert.That(result[75], Is.EqualTo(0.0742735782143335f).Within(0.01f));
 | 
			
		||||
        Assert.That(result[85], Is.EqualTo(0.0273237224472924f).Within(0.01f));
 | 
			
		||||
        Assert.That(result[90], Is.EqualTo(0.0165726754017612f).Within(0.01f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[97], Is.EqualTo(0.0082297470490200f).Within(0.004f));
 | 
			
		||||
            Assert.That(result[98], Is.EqualTo(0.0074465830709243f).Within(0.004f));
 | 
			
		||||
            Assert.That(result[99], Is.EqualTo(0.0067379469990854f).Within(0.004f));
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(result[97], Is.EqualTo(0.0082297470490200f).Within(0.004f));
 | 
			
		||||
        Assert.That(result[98], Is.EqualTo(0.0074465830709243f).Within(0.004f));
 | 
			
		||||
        Assert.That(result[99], Is.EqualTo(0.0067379469990854f).Within(0.004f));
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestLaplaceGeneratorWithRange01()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new FastRng.Distributions.LaplaceB01M05(rng);
 | 
			
		||||
            var samples = new float[1_000];
 | 
			
		||||
            for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
                samples[n] = await dist.NextNumber(-1.0f, 1.0f);
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestLaplaceGeneratorWithRange01()
 | 
			
		||||
    {
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new FastRng.Distributions.LaplaceB01M05(rng);
 | 
			
		||||
        var samples = new float[1_000];
 | 
			
		||||
        for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
            samples[n] = await dist.NextNumber(-1.0f, 1.0f);
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range");
 | 
			
		||||
            Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range");
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range");
 | 
			
		||||
        Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range");
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestLaplaceGeneratorWithRange02()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new FastRng.Distributions.LaplaceB01M05(rng);
 | 
			
		||||
            var samples = new float[1_000];
 | 
			
		||||
            for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
                samples[n] = await dist.NextNumber(0.0f, 1.0f);
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestLaplaceGeneratorWithRange02()
 | 
			
		||||
    {
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new FastRng.Distributions.LaplaceB01M05(rng);
 | 
			
		||||
        var samples = new float[1_000];
 | 
			
		||||
        for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
            samples[n] = await dist.NextNumber(0.0f, 1.0f);
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range");
 | 
			
		||||
            Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range");
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range");
 | 
			
		||||
        Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public void NoRandomNumberGenerator01()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.Throws<ArgumentNullException>(() => new FastRng.Distributions.LaplaceB01M05(null));
 | 
			
		||||
        }
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public void NoRandomNumberGenerator01()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.Throws<ArgumentNullException>(() => new FastRng.Distributions.LaplaceB01M05(null));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -5,80 +5,79 @@ using System.Threading.Tasks;
 | 
			
		||||
using FastRng;
 | 
			
		||||
using NUnit.Framework;
 | 
			
		||||
 | 
			
		||||
namespace FastRngTests.Distributions
 | 
			
		||||
namespace FastRngTests.Distributions;
 | 
			
		||||
 | 
			
		||||
[ExcludeFromCodeCoverage]
 | 
			
		||||
public class LogNormalS1M0
 | 
			
		||||
{
 | 
			
		||||
    [ExcludeFromCodeCoverage]
 | 
			
		||||
    public class LogNormalS1M0
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestLogNormalDistribution01()
 | 
			
		||||
    {
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestLogNormalDistribution01()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new FastRng.Distributions.LogNormalS1M0(rng);
 | 
			
		||||
            var fra = new FrequencyAnalysis();
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new FastRng.Distributions.LogNormalS1M0(rng);
 | 
			
		||||
        var fra = new FrequencyAnalysis();
 | 
			
		||||
            
 | 
			
		||||
            for (var n = 0; n < 100_000; n++)
 | 
			
		||||
                fra.CountThis(await dist.NextNumber());
 | 
			
		||||
        for (var n = 0; n < 100_000; n++)
 | 
			
		||||
            fra.CountThis(await dist.NextNumber());
 | 
			
		||||
            
 | 
			
		||||
            var result = fra.NormalizeAndPlotEvents(TestContext.WriteLine);
 | 
			
		||||
        var result = fra.NormalizeAndPlotEvents(TestContext.WriteLine);
 | 
			
		||||
 | 
			
		||||
            Assert.That(result[0], Is.EqualTo(0.001505531f).Within(0.003f));
 | 
			
		||||
            Assert.That(result[1], Is.EqualTo(0.014408709f).Within(0.01f));
 | 
			
		||||
            Assert.That(result[2], Is.EqualTo(0.043222256f).Within(0.02f));
 | 
			
		||||
        Assert.That(result[0], Is.EqualTo(0.001505531f).Within(0.003f));
 | 
			
		||||
        Assert.That(result[1], Is.EqualTo(0.014408709f).Within(0.01f));
 | 
			
		||||
        Assert.That(result[2], Is.EqualTo(0.043222256f).Within(0.02f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[21], Is.EqualTo(0.876212056f).Within(0.15f));
 | 
			
		||||
            Assert.That(result[22], Is.EqualTo(0.895582226f).Within(0.15f));
 | 
			
		||||
            Assert.That(result[23], Is.EqualTo(0.912837250f).Within(0.15f));
 | 
			
		||||
        Assert.That(result[21], Is.EqualTo(0.876212056f).Within(0.15f));
 | 
			
		||||
        Assert.That(result[22], Is.EqualTo(0.895582226f).Within(0.15f));
 | 
			
		||||
        Assert.That(result[23], Is.EqualTo(0.912837250f).Within(0.15f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[50], Is.EqualTo(0.948062005f).Within(0.2f));
 | 
			
		||||
        Assert.That(result[50], Is.EqualTo(0.948062005f).Within(0.2f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[75], Is.EqualTo(0.768584762f).Within(0.089f));
 | 
			
		||||
            Assert.That(result[85], Is.EqualTo(0.697303612f).Within(0.089f));
 | 
			
		||||
            Assert.That(result[90], Is.EqualTo(0.663570581f).Within(0.089f));
 | 
			
		||||
        Assert.That(result[75], Is.EqualTo(0.768584762f).Within(0.089f));
 | 
			
		||||
        Assert.That(result[85], Is.EqualTo(0.697303612f).Within(0.089f));
 | 
			
		||||
        Assert.That(result[90], Is.EqualTo(0.663570581f).Within(0.089f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[97], Is.EqualTo(0.618792767f).Within(0.089f));
 | 
			
		||||
            Assert.That(result[98], Is.EqualTo(0.612636410f).Within(0.089f));
 | 
			
		||||
            Assert.That(result[99], Is.EqualTo(0.606540679f).Within(0.089f));
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(result[97], Is.EqualTo(0.618792767f).Within(0.089f));
 | 
			
		||||
        Assert.That(result[98], Is.EqualTo(0.612636410f).Within(0.089f));
 | 
			
		||||
        Assert.That(result[99], Is.EqualTo(0.606540679f).Within(0.089f));
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestLogNormalGeneratorWithRange01()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new FastRng.Distributions.LogNormalS1M0(rng);
 | 
			
		||||
            var samples = new float[1_000];
 | 
			
		||||
            for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
                samples[n] = await dist.NextNumber(-1.0f, 1.0f);
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestLogNormalGeneratorWithRange01()
 | 
			
		||||
    {
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new FastRng.Distributions.LogNormalS1M0(rng);
 | 
			
		||||
        var samples = new float[1_000];
 | 
			
		||||
        for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
            samples[n] = await dist.NextNumber(-1.0f, 1.0f);
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range");
 | 
			
		||||
            Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range");
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range");
 | 
			
		||||
        Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range");
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestLogNormalGeneratorWithRange02()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new FastRng.Distributions.LogNormalS1M0(rng);
 | 
			
		||||
            var samples = new float[1_000];
 | 
			
		||||
            for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
                samples[n] = await dist.NextNumber(0.0f, 1.0f);
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestLogNormalGeneratorWithRange02()
 | 
			
		||||
    {
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new FastRng.Distributions.LogNormalS1M0(rng);
 | 
			
		||||
        var samples = new float[1_000];
 | 
			
		||||
        for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
            samples[n] = await dist.NextNumber(0.0f, 1.0f);
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range");
 | 
			
		||||
            Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range");
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range");
 | 
			
		||||
        Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public void NoRandomNumberGenerator01()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.Throws<ArgumentNullException>(() => new FastRng.Distributions.LogNormalS1M0(null));
 | 
			
		||||
        }
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public void NoRandomNumberGenerator01()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.Throws<ArgumentNullException>(() => new FastRng.Distributions.LogNormalS1M0(null));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -5,76 +5,75 @@ using System.Threading.Tasks;
 | 
			
		||||
using FastRng;
 | 
			
		||||
using NUnit.Framework;
 | 
			
		||||
 | 
			
		||||
namespace FastRngTests.Distributions
 | 
			
		||||
namespace FastRngTests.Distributions;
 | 
			
		||||
 | 
			
		||||
[ExcludeFromCodeCoverage]
 | 
			
		||||
public class NormalS02M05
 | 
			
		||||
{
 | 
			
		||||
    [ExcludeFromCodeCoverage]
 | 
			
		||||
    public class NormalS02M05
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestNormalDistribution01()
 | 
			
		||||
    {
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestNormalDistribution01()
 | 
			
		||||
        const float MEAN = 0.5f;
 | 
			
		||||
        const float STANDARD_DEVIATION = 0.2f;
 | 
			
		||||
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new FastRng.Distributions.NormalS02M05(rng);
 | 
			
		||||
        var stats = new RunningStatistics();
 | 
			
		||||
        var fra = new FrequencyAnalysis();
 | 
			
		||||
 | 
			
		||||
        for (var n = 0; n < 100_000; n++)
 | 
			
		||||
        {
 | 
			
		||||
            const float MEAN = 0.5f;
 | 
			
		||||
            const float STANDARD_DEVIATION = 0.2f;
 | 
			
		||||
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new FastRng.Distributions.NormalS02M05(rng);
 | 
			
		||||
            var stats = new RunningStatistics();
 | 
			
		||||
            var fra = new FrequencyAnalysis();
 | 
			
		||||
 | 
			
		||||
            for (var n = 0; n < 100_000; n++)
 | 
			
		||||
            {
 | 
			
		||||
                var nextNumber = await dist.NextNumber();
 | 
			
		||||
                stats.Push(nextNumber);
 | 
			
		||||
                fra.CountThis(nextNumber);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            fra.NormalizeAndPlotEvents(TestContext.WriteLine);
 | 
			
		||||
            
 | 
			
		||||
            TestContext.WriteLine($"mean={MEAN} vs. {stats.Mean}");
 | 
			
		||||
            TestContext.WriteLine($"variance={STANDARD_DEVIATION * STANDARD_DEVIATION} vs {stats.Variance}");
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(stats.Mean, Is.EqualTo(MEAN).Within(0.01f), "Mean is out of range");
 | 
			
		||||
            Assert.That(stats.Variance, Is.EqualTo(STANDARD_DEVIATION*STANDARD_DEVIATION).Within(0.01f), "Variance is out of range");
 | 
			
		||||
            var nextNumber = await dist.NextNumber();
 | 
			
		||||
            stats.Push(nextNumber);
 | 
			
		||||
            fra.CountThis(nextNumber);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestNormalGeneratorWithRange01()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var samples = new float[1_000];
 | 
			
		||||
            var dist = new FastRng.Distributions.NormalS02M05(rng);
 | 
			
		||||
            for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
                samples[n] = await dist.NextNumber(-1.0f, 1.0f);
 | 
			
		||||
        fra.NormalizeAndPlotEvents(TestContext.WriteLine);
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min is out of range");
 | 
			
		||||
            Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range");
 | 
			
		||||
        }
 | 
			
		||||
        TestContext.WriteLine($"mean={MEAN} vs. {stats.Mean}");
 | 
			
		||||
        TestContext.WriteLine($"variance={STANDARD_DEVIATION * STANDARD_DEVIATION} vs {stats.Variance}");
 | 
			
		||||
            
 | 
			
		||||
        Assert.That(stats.Mean, Is.EqualTo(MEAN).Within(0.01f), "Mean is out of range");
 | 
			
		||||
        Assert.That(stats.Variance, Is.EqualTo(STANDARD_DEVIATION*STANDARD_DEVIATION).Within(0.01f), "Variance is out of range");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestNormalGeneratorWithRange01()
 | 
			
		||||
    {
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var samples = new float[1_000];
 | 
			
		||||
        var dist = new FastRng.Distributions.NormalS02M05(rng);
 | 
			
		||||
        for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
            samples[n] = await dist.NextNumber(-1.0f, 1.0f);
 | 
			
		||||
            
 | 
			
		||||
        Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min is out of range");
 | 
			
		||||
        Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range");
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestNormalGeneratorWithRange02()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var samples = new float[1_000];
 | 
			
		||||
            var dist = new FastRng.Distributions.NormalS02M05(rng);
 | 
			
		||||
            for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
                samples[n] = await dist.NextNumber(0.0f, 1.0f);
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestNormalGeneratorWithRange02()
 | 
			
		||||
    {
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var samples = new float[1_000];
 | 
			
		||||
        var dist = new FastRng.Distributions.NormalS02M05(rng);
 | 
			
		||||
        for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
            samples[n] = await dist.NextNumber(0.0f, 1.0f);
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range");
 | 
			
		||||
            Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range");
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range");
 | 
			
		||||
        Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public void NoRandomNumberGenerator01()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.Throws<ArgumentNullException>(() => new FastRng.Distributions.NormalS02M05(null));
 | 
			
		||||
        }
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public void NoRandomNumberGenerator01()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.Throws<ArgumentNullException>(() => new FastRng.Distributions.NormalS02M05(null));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -5,80 +5,79 @@ using System.Threading.Tasks;
 | 
			
		||||
using FastRng;
 | 
			
		||||
using NUnit.Framework;
 | 
			
		||||
 | 
			
		||||
namespace FastRngTests.Distributions
 | 
			
		||||
namespace FastRngTests.Distributions;
 | 
			
		||||
 | 
			
		||||
[ExcludeFromCodeCoverage]
 | 
			
		||||
public class StudentTNu1
 | 
			
		||||
{
 | 
			
		||||
    [ExcludeFromCodeCoverage]
 | 
			
		||||
    public class StudentTNu1
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestStudentTDistribution01()
 | 
			
		||||
    {
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestStudentTDistribution01()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new FastRng.Distributions.StudentTNu1(rng);
 | 
			
		||||
            var fra = new FrequencyAnalysis();
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new FastRng.Distributions.StudentTNu1(rng);
 | 
			
		||||
        var fra = new FrequencyAnalysis();
 | 
			
		||||
 | 
			
		||||
            for (var n = 0; n < 100_000; n++)
 | 
			
		||||
                fra.CountThis(await dist.NextNumber());
 | 
			
		||||
        for (var n = 0; n < 100_000; n++)
 | 
			
		||||
            fra.CountThis(await dist.NextNumber());
 | 
			
		||||
            
 | 
			
		||||
            var result = fra.NormalizeAndPlotEvents(TestContext.WriteLine);
 | 
			
		||||
        var result = fra.NormalizeAndPlotEvents(TestContext.WriteLine);
 | 
			
		||||
 | 
			
		||||
            Assert.That(result[0], Is.EqualTo(1.000000000f).Within(0.2f));
 | 
			
		||||
            Assert.That(result[1], Is.EqualTo(0.999700120f).Within(0.2f));
 | 
			
		||||
            Assert.That(result[2], Is.EqualTo(0.999200719f).Within(0.2f));
 | 
			
		||||
        Assert.That(result[0], Is.EqualTo(1.000000000f).Within(0.2f));
 | 
			
		||||
        Assert.That(result[1], Is.EqualTo(0.999700120f).Within(0.2f));
 | 
			
		||||
        Assert.That(result[2], Is.EqualTo(0.999200719f).Within(0.2f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[21], Is.EqualTo(0.953929798f).Within(0.2f));
 | 
			
		||||
            Assert.That(result[22], Is.EqualTo(0.949852788f).Within(0.2f));
 | 
			
		||||
            Assert.That(result[23], Is.EqualTo(0.945631619f).Within(0.2f));
 | 
			
		||||
        Assert.That(result[21], Is.EqualTo(0.953929798f).Within(0.2f));
 | 
			
		||||
        Assert.That(result[22], Is.EqualTo(0.949852788f).Within(0.2f));
 | 
			
		||||
        Assert.That(result[23], Is.EqualTo(0.945631619f).Within(0.2f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[50], Is.EqualTo(0.793667169f).Within(0.095f));
 | 
			
		||||
        Assert.That(result[50], Is.EqualTo(0.793667169f).Within(0.095f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[75], Is.EqualTo(0.633937627f).Within(0.09f));
 | 
			
		||||
            Assert.That(result[85], Is.EqualTo(0.574902276f).Within(0.09f));
 | 
			
		||||
            Assert.That(result[90], Is.EqualTo(0.547070729f).Within(0.09f));
 | 
			
		||||
        Assert.That(result[75], Is.EqualTo(0.633937627f).Within(0.09f));
 | 
			
		||||
        Assert.That(result[85], Is.EqualTo(0.574902276f).Within(0.09f));
 | 
			
		||||
        Assert.That(result[90], Is.EqualTo(0.547070729f).Within(0.09f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[97], Is.EqualTo(0.510150990f).Within(0.09f));
 | 
			
		||||
            Assert.That(result[98], Is.EqualTo(0.505075501f).Within(0.09f));
 | 
			
		||||
            Assert.That(result[99], Is.EqualTo(0.500050000f).Within(0.09f));
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(result[97], Is.EqualTo(0.510150990f).Within(0.09f));
 | 
			
		||||
        Assert.That(result[98], Is.EqualTo(0.505075501f).Within(0.09f));
 | 
			
		||||
        Assert.That(result[99], Is.EqualTo(0.500050000f).Within(0.09f));
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestStudentTGeneratorWithRange01()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new FastRng.Distributions.StudentTNu1(rng);
 | 
			
		||||
            var samples = new float[1_000];
 | 
			
		||||
            for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
                samples[n] = await dist.NextNumber(-1.0f, 1.0f);
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestStudentTGeneratorWithRange01()
 | 
			
		||||
    {
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new FastRng.Distributions.StudentTNu1(rng);
 | 
			
		||||
        var samples = new float[1_000];
 | 
			
		||||
        for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
            samples[n] = await dist.NextNumber(-1.0f, 1.0f);
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range");
 | 
			
		||||
            Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range");
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range");
 | 
			
		||||
        Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range");
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestStudentTGeneratorWithRange02()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new FastRng.Distributions.StudentTNu1(rng);
 | 
			
		||||
            var samples = new float[1_000];
 | 
			
		||||
            for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
                samples[n] = await dist.NextNumber(0.0f, 1.0f);
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestStudentTGeneratorWithRange02()
 | 
			
		||||
    {
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new FastRng.Distributions.StudentTNu1(rng);
 | 
			
		||||
        var samples = new float[1_000];
 | 
			
		||||
        for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
            samples[n] = await dist.NextNumber(0.0f, 1.0f);
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range");
 | 
			
		||||
            Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range");
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range");
 | 
			
		||||
        Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public void NoRandomNumberGenerator01()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.Throws<ArgumentNullException>(() => new FastRng.Distributions.StudentTNu1(null));
 | 
			
		||||
        }
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public void NoRandomNumberGenerator01()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.Throws<ArgumentNullException>(() => new FastRng.Distributions.StudentTNu1(null));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -5,293 +5,292 @@ using System.Threading.Tasks;
 | 
			
		||||
using FastRng;
 | 
			
		||||
using NUnit.Framework;
 | 
			
		||||
 | 
			
		||||
namespace FastRngTests.Distributions
 | 
			
		||||
namespace FastRngTests.Distributions;
 | 
			
		||||
 | 
			
		||||
[ExcludeFromCodeCoverage]
 | 
			
		||||
public class Uniform
 | 
			
		||||
{
 | 
			
		||||
    [ExcludeFromCodeCoverage]
 | 
			
		||||
    public class Uniform
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestUniformDistribution01()
 | 
			
		||||
    {
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestUniformDistribution01()
 | 
			
		||||
        const float A = 0.0f;
 | 
			
		||||
        const float B = 1.0f;
 | 
			
		||||
        const float MEAN = 0.5f * (A + B);
 | 
			
		||||
        const float VARIANCE = (1.0f / 12.0f) * (B - A) * (B - A);
 | 
			
		||||
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var stats = new RunningStatistics();
 | 
			
		||||
        var fra = new FrequencyAnalysis();
 | 
			
		||||
            
 | 
			
		||||
        for (var n = 0; n < 100_000; n++)
 | 
			
		||||
        {
 | 
			
		||||
            const float A = 0.0f;
 | 
			
		||||
            const float B = 1.0f;
 | 
			
		||||
            const float MEAN = 0.5f * (A + B);
 | 
			
		||||
            const float VARIANCE = (1.0f / 12.0f) * (B - A) * (B - A);
 | 
			
		||||
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var stats = new RunningStatistics();
 | 
			
		||||
            var fra = new FrequencyAnalysis();
 | 
			
		||||
            
 | 
			
		||||
            for (var n = 0; n < 100_000; n++)
 | 
			
		||||
            {
 | 
			
		||||
                var value = await rng.GetUniform();
 | 
			
		||||
                stats.Push(value);
 | 
			
		||||
                fra.CountThis(value);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            fra.NormalizeAndPlotEvents(TestContext.WriteLine);
 | 
			
		||||
            fra.PlotOccurence(TestContext.WriteLine);
 | 
			
		||||
            TestContext.WriteLine($"mean={MEAN} vs. {stats.Mean}");
 | 
			
		||||
            TestContext.WriteLine($"variance={VARIANCE} vs {stats.Variance}");
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(stats.Mean, Is.EqualTo(MEAN).Within(0.01f), "Mean is out of range");
 | 
			
		||||
            Assert.That(stats.Variance, Is.EqualTo(VARIANCE).Within(0.001f), "Variance is out of range");
 | 
			
		||||
            var value = await rng.GetUniform();
 | 
			
		||||
            stats.Push(value);
 | 
			
		||||
            fra.CountThis(value);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fra.NormalizeAndPlotEvents(TestContext.WriteLine);
 | 
			
		||||
        fra.PlotOccurence(TestContext.WriteLine);
 | 
			
		||||
        TestContext.WriteLine($"mean={MEAN} vs. {stats.Mean}");
 | 
			
		||||
        TestContext.WriteLine($"variance={VARIANCE} vs {stats.Variance}");
 | 
			
		||||
            
 | 
			
		||||
        Assert.That(stats.Mean, Is.EqualTo(MEAN).Within(0.01f), "Mean is out of range");
 | 
			
		||||
        Assert.That(stats.Variance, Is.EqualTo(VARIANCE).Within(0.001f), "Variance is out of range");
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task KolmogorovSmirnovTest()
 | 
			
		||||
        {
 | 
			
		||||
            // Kolmogorov-Smirnov test for distributions.
 | 
			
		||||
            // See Knuth volume 2, page 48-51 (third edition).
 | 
			
		||||
            // This test should *fail* on average one time in 1000 runs.
 | 
			
		||||
            // That's life with random number generators: if the test passed all the time, 
 | 
			
		||||
            // the source wouldn't be random enough!  If the test were to fail more frequently,
 | 
			
		||||
            // the most likely explanation would be a bug in the code.
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task KolmogorovSmirnovTest()
 | 
			
		||||
    {
 | 
			
		||||
        // Kolmogorov-Smirnov test for distributions.
 | 
			
		||||
        // See Knuth volume 2, page 48-51 (third edition).
 | 
			
		||||
        // This test should *fail* on average one time in 1000 runs.
 | 
			
		||||
        // That's life with random number generators: if the test passed all the time, 
 | 
			
		||||
        // the source wouldn't be random enough!  If the test were to fail more frequently,
 | 
			
		||||
        // the most likely explanation would be a bug in the code.
 | 
			
		||||
            
 | 
			
		||||
            const int NUM_ROUNDS = 10_000;
 | 
			
		||||
            const float FAILURE_PROBABILITY = 0.001f; // probability of test failing with normal distributed input
 | 
			
		||||
            const float P_LOW = 0.25f * FAILURE_PROBABILITY;
 | 
			
		||||
            const float P_HIGH = 1.0f - 0.25f * FAILURE_PROBABILITY;
 | 
			
		||||
        const int NUM_ROUNDS = 10_000;
 | 
			
		||||
        const float FAILURE_PROBABILITY = 0.001f; // probability of test failing with normal distributed input
 | 
			
		||||
        const float P_LOW = 0.25f * FAILURE_PROBABILITY;
 | 
			
		||||
        const float P_HIGH = 1.0f - 0.25f * FAILURE_PROBABILITY;
 | 
			
		||||
            
 | 
			
		||||
            var samples = new float[NUM_ROUNDS];
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            int n;
 | 
			
		||||
        var samples = new float[NUM_ROUNDS];
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        int n;
 | 
			
		||||
             
 | 
			
		||||
            for (n = 0; n != NUM_ROUNDS; ++n)
 | 
			
		||||
                samples[n] = await rng.GetUniform();
 | 
			
		||||
        for (n = 0; n != NUM_ROUNDS; ++n)
 | 
			
		||||
            samples[n] = await rng.GetUniform();
 | 
			
		||||
 
 | 
			
		||||
            Array.Sort(samples);
 | 
			
		||||
        Array.Sort(samples);
 | 
			
		||||
 | 
			
		||||
            var jMinus = 0;
 | 
			
		||||
            var jPlus = 0;
 | 
			
		||||
            var kPlus = -float.MaxValue;
 | 
			
		||||
            var kMinus = -float.MaxValue;
 | 
			
		||||
        var jMinus = 0;
 | 
			
		||||
        var jPlus = 0;
 | 
			
		||||
        var kPlus = -float.MaxValue;
 | 
			
		||||
        var kMinus = -float.MaxValue;
 | 
			
		||||
 
 | 
			
		||||
            for (n = 0; n != NUM_ROUNDS; ++n)
 | 
			
		||||
        for (n = 0; n != NUM_ROUNDS; ++n)
 | 
			
		||||
        {
 | 
			
		||||
            var cdf = samples[n];
 | 
			
		||||
            var temp = (n + 1.0f) / NUM_ROUNDS - cdf;
 | 
			
		||||
                
 | 
			
		||||
            if (kPlus < temp)
 | 
			
		||||
            {
 | 
			
		||||
                var cdf = samples[n];
 | 
			
		||||
                var temp = (n + 1.0f) / NUM_ROUNDS - cdf;
 | 
			
		||||
                
 | 
			
		||||
                if (kPlus < temp)
 | 
			
		||||
                {
 | 
			
		||||
                    kPlus = temp;
 | 
			
		||||
                    jPlus = n;
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                temp = cdf - (n + 0.0f) / NUM_ROUNDS;
 | 
			
		||||
                if (kMinus < temp)
 | 
			
		||||
                {
 | 
			
		||||
                    kMinus = temp;
 | 
			
		||||
                    jMinus = n;
 | 
			
		||||
                }
 | 
			
		||||
                kPlus = temp;
 | 
			
		||||
                jPlus = n;
 | 
			
		||||
            }
 | 
			
		||||
                
 | 
			
		||||
            temp = cdf - (n + 0.0f) / NUM_ROUNDS;
 | 
			
		||||
            if (kMinus < temp)
 | 
			
		||||
            {
 | 
			
		||||
                kMinus = temp;
 | 
			
		||||
                jMinus = n;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
            var sqrtNumReps = MathF.Sqrt(NUM_ROUNDS);
 | 
			
		||||
            kPlus *= sqrtNumReps;
 | 
			
		||||
            kMinus *= sqrtNumReps;
 | 
			
		||||
        var sqrtNumReps = MathF.Sqrt(NUM_ROUNDS);
 | 
			
		||||
        kPlus *= sqrtNumReps;
 | 
			
		||||
        kMinus *= sqrtNumReps;
 | 
			
		||||
 
 | 
			
		||||
            // We divide the failure probability by four because we have four tests:
 | 
			
		||||
            // left and right tests for K+ and K-.
 | 
			
		||||
            var cutoffLow = MathF.Sqrt(0.5f * MathF.Log(1.0f / (1.0f - P_LOW))) - 1.0f / (6.0f * sqrtNumReps);
 | 
			
		||||
            var cutoffHigh = MathF.Sqrt(0.5f * MathF.Log(1.0f / (1.0f - P_HIGH))) - 1.0f / (6.0f * sqrtNumReps);
 | 
			
		||||
        // We divide the failure probability by four because we have four tests:
 | 
			
		||||
        // left and right tests for K+ and K-.
 | 
			
		||||
        var cutoffLow = MathF.Sqrt(0.5f * MathF.Log(1.0f / (1.0f - P_LOW))) - 1.0f / (6.0f * sqrtNumReps);
 | 
			
		||||
        var cutoffHigh = MathF.Sqrt(0.5f * MathF.Log(1.0f / (1.0f - P_HIGH))) - 1.0f / (6.0f * sqrtNumReps);
 | 
			
		||||
 
 | 
			
		||||
            TestContext.WriteLine($"K+ = {kPlus} | K- = {kMinus}");
 | 
			
		||||
            TestContext.WriteLine($"K+ max at position {jPlus} = {samples[jPlus]}");
 | 
			
		||||
            TestContext.WriteLine($"K- max at position {jMinus} = {samples[jMinus]}");
 | 
			
		||||
            TestContext.WriteLine($"Acceptable interval: [{cutoffLow}, {cutoffHigh}]");
 | 
			
		||||
        TestContext.WriteLine($"K+ = {kPlus} | K- = {kMinus}");
 | 
			
		||||
        TestContext.WriteLine($"K+ max at position {jPlus} = {samples[jPlus]}");
 | 
			
		||||
        TestContext.WriteLine($"K- max at position {jMinus} = {samples[jMinus]}");
 | 
			
		||||
        TestContext.WriteLine($"Acceptable interval: [{cutoffLow}, {cutoffHigh}]");
 | 
			
		||||
 | 
			
		||||
            Assert.That(kPlus, Is.GreaterThanOrEqualTo(cutoffLow), "K+ is lower than low cutoff");
 | 
			
		||||
            Assert.That(kPlus, Is.LessThanOrEqualTo(cutoffHigh), "K+ is higher than high cutoff");
 | 
			
		||||
            Assert.That(kMinus, Is.GreaterThanOrEqualTo(cutoffLow), "K- is lower than low cutoff");
 | 
			
		||||
            Assert.That(kMinus, Is.LessThanOrEqualTo(cutoffHigh), "K- is lower than high cutoff");
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(kPlus, Is.GreaterThanOrEqualTo(cutoffLow), "K+ is lower than low cutoff");
 | 
			
		||||
        Assert.That(kPlus, Is.LessThanOrEqualTo(cutoffHigh), "K+ is higher than high cutoff");
 | 
			
		||||
        Assert.That(kMinus, Is.GreaterThanOrEqualTo(cutoffLow), "K- is lower than low cutoff");
 | 
			
		||||
        Assert.That(kMinus, Is.LessThanOrEqualTo(cutoffHigh), "K- is lower than high cutoff");
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestUniformGeneratorWithRange01()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var samples = new float[1_000];
 | 
			
		||||
            var dist = new FastRng.Distributions.Uniform(rng);
 | 
			
		||||
            for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
                samples[n] = await dist.NextNumber(-1.0f, 1.0f);
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestUniformGeneratorWithRange01()
 | 
			
		||||
    {
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var samples = new float[1_000];
 | 
			
		||||
        var dist = new FastRng.Distributions.Uniform(rng);
 | 
			
		||||
        for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
            samples[n] = await dist.NextNumber(-1.0f, 1.0f);
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min is out of range");
 | 
			
		||||
            Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range");
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min is out of range");
 | 
			
		||||
        Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range");
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestUniformGeneratorWithRange02()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var samples = new float[1_000];
 | 
			
		||||
            var dist = new FastRng.Distributions.Uniform(rng);
 | 
			
		||||
            for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
                samples[n] = await dist.NextNumber(0.0f, 1.0f);
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestUniformGeneratorWithRange02()
 | 
			
		||||
    {
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var samples = new float[1_000];
 | 
			
		||||
        var dist = new FastRng.Distributions.Uniform(rng);
 | 
			
		||||
        for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
            samples[n] = await dist.NextNumber(0.0f, 1.0f);
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range");
 | 
			
		||||
            Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range");
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range");
 | 
			
		||||
        Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestUniformGeneratorWithRange04()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var samples = new float[1_000];
 | 
			
		||||
            for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
                samples[n] = await rng.GetUniform();
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestUniformGeneratorWithRange04()
 | 
			
		||||
    {
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var samples = new float[1_000];
 | 
			
		||||
        for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
            samples[n] = await rng.GetUniform();
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range");
 | 
			
		||||
            Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range");
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range");
 | 
			
		||||
        Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range");
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestRange05Uint()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new FastRng.Distributions.Uniform(rng);
 | 
			
		||||
            var distribution = new uint[101];
 | 
			
		||||
            var runs = 1_000_000;
 | 
			
		||||
            for (var n = 0; n < runs; n++)
 | 
			
		||||
                distribution[await dist.NextNumber(0, 100)]++;
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestRange05Uint()
 | 
			
		||||
    {
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new FastRng.Distributions.Uniform(rng);
 | 
			
		||||
        var distribution = new uint[101];
 | 
			
		||||
        var runs = 1_000_000;
 | 
			
		||||
        for (var n = 0; n < runs; n++)
 | 
			
		||||
            distribution[await dist.NextNumber(0, 100)]++;
 | 
			
		||||
            
 | 
			
		||||
            for (var n = 0; n < distribution.Length - 1; n++)
 | 
			
		||||
                Assert.That(distribution[n], Is.GreaterThan(0));
 | 
			
		||||
        }
 | 
			
		||||
        for (var n = 0; n < distribution.Length - 1; n++)
 | 
			
		||||
            Assert.That(distribution[n], Is.GreaterThan(0));
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestRange05Ulong()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new FastRng.Distributions.Uniform(rng);
 | 
			
		||||
            var distribution = new uint[101];
 | 
			
		||||
            var runs = 1_000_000;
 | 
			
		||||
            for (var n = 0; n < runs; n++)
 | 
			
		||||
                distribution[await dist.NextNumber(0UL, 100)]++;
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestRange05Ulong()
 | 
			
		||||
    {
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new FastRng.Distributions.Uniform(rng);
 | 
			
		||||
        var distribution = new uint[101];
 | 
			
		||||
        var runs = 1_000_000;
 | 
			
		||||
        for (var n = 0; n < runs; n++)
 | 
			
		||||
            distribution[await dist.NextNumber(0UL, 100)]++;
 | 
			
		||||
            
 | 
			
		||||
            for (var n = 0; n < distribution.Length - 1; n++)
 | 
			
		||||
                Assert.That(distribution[n], Is.GreaterThan(0));
 | 
			
		||||
        }
 | 
			
		||||
        for (var n = 0; n < distribution.Length - 1; n++)
 | 
			
		||||
            Assert.That(distribution[n], Is.GreaterThan(0));
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestRange05Float()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new FastRng.Distributions.Uniform(rng);
 | 
			
		||||
            var distribution = new uint[101];
 | 
			
		||||
            var runs = 1_000_000;
 | 
			
		||||
            for (var n = 0; n < runs; n++)
 | 
			
		||||
                distribution[(uint)MathF.Floor(await dist.NextNumber(0.0f, 100.0f))]++;
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestRange05Float()
 | 
			
		||||
    {
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new FastRng.Distributions.Uniform(rng);
 | 
			
		||||
        var distribution = new uint[101];
 | 
			
		||||
        var runs = 1_000_000;
 | 
			
		||||
        for (var n = 0; n < runs; n++)
 | 
			
		||||
            distribution[(uint)MathF.Floor(await dist.NextNumber(0.0f, 100.0f))]++;
 | 
			
		||||
            
 | 
			
		||||
            for (var n = 0; n < distribution.Length - 1; n++)
 | 
			
		||||
                Assert.That(distribution[n], Is.GreaterThan(0));
 | 
			
		||||
        }
 | 
			
		||||
        for (var n = 0; n < distribution.Length - 1; n++)
 | 
			
		||||
            Assert.That(distribution[n], Is.GreaterThan(0));
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestDistribution001Uint()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new FastRng.Distributions.Uniform(rng);
 | 
			
		||||
            var distribution = new uint[101];
 | 
			
		||||
            var runs = 1_000_000;
 | 
			
		||||
            for (var n = 0; n < runs; n++)
 | 
			
		||||
                distribution[await dist.NextNumber(0, 100)]++;
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestDistribution001Uint()
 | 
			
		||||
    {
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new FastRng.Distributions.Uniform(rng);
 | 
			
		||||
        var distribution = new uint[101];
 | 
			
		||||
        var runs = 1_000_000;
 | 
			
		||||
        for (var n = 0; n < runs; n++)
 | 
			
		||||
            distribution[await dist.NextNumber(0, 100)]++;
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(distribution[..^1].Max() - distribution[..^1].Min(), Is.InRange(0, 600));
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(distribution[..^1].Max() - distribution[..^1].Min(), Is.InRange(0, 600));
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestDistribution001Ulong()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new FastRng.Distributions.Uniform(rng);
 | 
			
		||||
            var distribution = new uint[101];
 | 
			
		||||
            var runs = 1_000_000;
 | 
			
		||||
            for (var n = 0; n < runs; n++)
 | 
			
		||||
                distribution[await dist.NextNumber(0UL, 100)]++;
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestDistribution001Ulong()
 | 
			
		||||
    {
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new FastRng.Distributions.Uniform(rng);
 | 
			
		||||
        var distribution = new uint[101];
 | 
			
		||||
        var runs = 1_000_000;
 | 
			
		||||
        for (var n = 0; n < runs; n++)
 | 
			
		||||
            distribution[await dist.NextNumber(0UL, 100)]++;
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(distribution[..^1].Max() - distribution[..^1].Min(), Is.InRange(0, 600));
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(distribution[..^1].Max() - distribution[..^1].Min(), Is.InRange(0, 600));
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestDistribution001Float()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new FastRng.Distributions.Uniform(rng);
 | 
			
		||||
            var distribution = new uint[101];
 | 
			
		||||
            var runs = 1_000_000;
 | 
			
		||||
            for (var n = 0; n < runs; n++)
 | 
			
		||||
                distribution[(uint)MathF.Floor(await dist.NextNumber(0.0f, 100.0f))]++;
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestDistribution001Float()
 | 
			
		||||
    {
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new FastRng.Distributions.Uniform(rng);
 | 
			
		||||
        var distribution = new uint[101];
 | 
			
		||||
        var runs = 1_000_000;
 | 
			
		||||
        for (var n = 0; n < runs; n++)
 | 
			
		||||
            distribution[(uint)MathF.Floor(await dist.NextNumber(0.0f, 100.0f))]++;
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(distribution[..^1].Max() - distribution[..^1].Min(), Is.InRange(0, 600));
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(distribution[..^1].Max() - distribution[..^1].Min(), Is.InRange(0, 600));
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.LONG_RUNNING)]
 | 
			
		||||
        public async Task TestDistribution002Uint()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new FastRng.Distributions.Uniform(rng);
 | 
			
		||||
            var distribution = new uint[101];
 | 
			
		||||
            var runs = 100_000_000;
 | 
			
		||||
            for (var n = 0; n < runs; n++)
 | 
			
		||||
                distribution[await dist.NextNumber(0, 100)]++;
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.LONG_RUNNING)]
 | 
			
		||||
    public async Task TestDistribution002Uint()
 | 
			
		||||
    {
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new FastRng.Distributions.Uniform(rng);
 | 
			
		||||
        var distribution = new uint[101];
 | 
			
		||||
        var runs = 100_000_000;
 | 
			
		||||
        for (var n = 0; n < runs; n++)
 | 
			
		||||
            distribution[await dist.NextNumber(0, 100)]++;
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(distribution[..^1].Max() - distribution[..^1].Min(), Is.InRange(0, 6_000));
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(distribution[..^1].Max() - distribution[..^1].Min(), Is.InRange(0, 6_000));
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.LONG_RUNNING)]
 | 
			
		||||
        public async Task TestDistribution002Ulong()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new FastRng.Distributions.Uniform(rng);
 | 
			
		||||
            var distribution = new uint[101];
 | 
			
		||||
            var runs = 100_000_000;
 | 
			
		||||
            for (var n = 0; n < runs; n++)
 | 
			
		||||
                distribution[await dist.NextNumber(0UL, 100)]++;
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.LONG_RUNNING)]
 | 
			
		||||
    public async Task TestDistribution002Ulong()
 | 
			
		||||
    {
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new FastRng.Distributions.Uniform(rng);
 | 
			
		||||
        var distribution = new uint[101];
 | 
			
		||||
        var runs = 100_000_000;
 | 
			
		||||
        for (var n = 0; n < runs; n++)
 | 
			
		||||
            distribution[await dist.NextNumber(0UL, 100)]++;
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(distribution[..^1].Max() - distribution[..^1].Min(), Is.InRange(0, 6_000));
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(distribution[..^1].Max() - distribution[..^1].Min(), Is.InRange(0, 6_000));
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.LONG_RUNNING)]
 | 
			
		||||
        public async Task TestDistribution002Float()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new FastRng.Distributions.Uniform(rng);
 | 
			
		||||
            var distribution = new uint[101];
 | 
			
		||||
            var runs = 100_000_000;
 | 
			
		||||
            for (var n = 0; n < runs; n++)
 | 
			
		||||
                distribution[(uint)MathF.Floor(await dist.NextNumber(0.0f, 100.0f))]++;
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.LONG_RUNNING)]
 | 
			
		||||
    public async Task TestDistribution002Float()
 | 
			
		||||
    {
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new FastRng.Distributions.Uniform(rng);
 | 
			
		||||
        var distribution = new uint[101];
 | 
			
		||||
        var runs = 100_000_000;
 | 
			
		||||
        for (var n = 0; n < runs; n++)
 | 
			
		||||
            distribution[(uint)MathF.Floor(await dist.NextNumber(0.0f, 100.0f))]++;
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(distribution[..^1].Max() - distribution[..^1].Min(), Is.InRange(0, 6_000));
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(distribution[..^1].Max() - distribution[..^1].Min(), Is.InRange(0, 6_000));
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public void NoRandomNumberGenerator01()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.Throws<ArgumentNullException>(() => new FastRng.Distributions.Uniform(null));
 | 
			
		||||
        }
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public void NoRandomNumberGenerator01()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.Throws<ArgumentNullException>(() => new FastRng.Distributions.Uniform(null));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -5,80 +5,79 @@ using System.Threading.Tasks;
 | 
			
		||||
using FastRng;
 | 
			
		||||
using NUnit.Framework;
 | 
			
		||||
 | 
			
		||||
namespace FastRngTests.Distributions
 | 
			
		||||
namespace FastRngTests.Distributions;
 | 
			
		||||
 | 
			
		||||
[ExcludeFromCodeCoverage]
 | 
			
		||||
public class WeibullK05La1
 | 
			
		||||
{
 | 
			
		||||
    [ExcludeFromCodeCoverage]
 | 
			
		||||
    public class WeibullK05La1
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestWeibullDistribution01()
 | 
			
		||||
    {
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestWeibullDistribution01()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new FastRng.Distributions.WeibullK05La1(rng);
 | 
			
		||||
            var fra = new FrequencyAnalysis();
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new FastRng.Distributions.WeibullK05La1(rng);
 | 
			
		||||
        var fra = new FrequencyAnalysis();
 | 
			
		||||
            
 | 
			
		||||
            for (var n = 0; n < 100_000; n++)
 | 
			
		||||
                fra.CountThis(await dist.NextNumber());
 | 
			
		||||
        for (var n = 0; n < 100_000; n++)
 | 
			
		||||
            fra.CountThis(await dist.NextNumber());
 | 
			
		||||
            
 | 
			
		||||
            var result = fra.NormalizeAndPlotEvents(TestContext.WriteLine);
 | 
			
		||||
        var result = fra.NormalizeAndPlotEvents(TestContext.WriteLine);
 | 
			
		||||
 | 
			
		||||
            Assert.That(result[0], Is.EqualTo(1.000000000f).Within(0.2f));
 | 
			
		||||
            Assert.That(result[1], Is.EqualTo(0.678415772f).Within(0.09f));
 | 
			
		||||
            Assert.That(result[2], Is.EqualTo(0.536595233f).Within(0.09f));
 | 
			
		||||
        Assert.That(result[0], Is.EqualTo(1.000000000f).Within(0.2f));
 | 
			
		||||
        Assert.That(result[1], Is.EqualTo(0.678415772f).Within(0.09f));
 | 
			
		||||
        Assert.That(result[2], Is.EqualTo(0.536595233f).Within(0.09f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[21], Is.EqualTo(0.147406264f).Within(0.02f));
 | 
			
		||||
            Assert.That(result[22], Is.EqualTo(0.142654414f).Within(0.02f));
 | 
			
		||||
            Assert.That(result[23], Is.EqualTo(0.138217760f).Within(0.02f));
 | 
			
		||||
        Assert.That(result[21], Is.EqualTo(0.147406264f).Within(0.02f));
 | 
			
		||||
        Assert.That(result[22], Is.EqualTo(0.142654414f).Within(0.02f));
 | 
			
		||||
        Assert.That(result[23], Is.EqualTo(0.138217760f).Within(0.02f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[50], Is.EqualTo(0.075769787f).Within(0.095f));
 | 
			
		||||
        Assert.That(result[50], Is.EqualTo(0.075769787f).Within(0.095f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[75], Is.EqualTo(0.053016799f).Within(0.05f));
 | 
			
		||||
            Assert.That(result[85], Is.EqualTo(0.047144614f).Within(0.05f));
 | 
			
		||||
            Assert.That(result[90], Is.EqualTo(0.044629109f).Within(0.05f));
 | 
			
		||||
        Assert.That(result[75], Is.EqualTo(0.053016799f).Within(0.05f));
 | 
			
		||||
        Assert.That(result[85], Is.EqualTo(0.047144614f).Within(0.05f));
 | 
			
		||||
        Assert.That(result[90], Is.EqualTo(0.044629109f).Within(0.05f));
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(result[97], Is.EqualTo(0.041484591f).Within(0.05f));
 | 
			
		||||
            Assert.That(result[98], Is.EqualTo(0.041067125f).Within(0.05f));
 | 
			
		||||
            Assert.That(result[99], Is.EqualTo(0.040656966f).Within(0.05f));
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(result[97], Is.EqualTo(0.041484591f).Within(0.05f));
 | 
			
		||||
        Assert.That(result[98], Is.EqualTo(0.041067125f).Within(0.05f));
 | 
			
		||||
        Assert.That(result[99], Is.EqualTo(0.040656966f).Within(0.05f));
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestWeibullGeneratorWithRange01()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new FastRng.Distributions.WeibullK05La1(rng);
 | 
			
		||||
            var samples = new float[1_000];
 | 
			
		||||
            for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
                samples[n] = await dist.NextNumber(-1.0f, 1.0f);
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestWeibullGeneratorWithRange01()
 | 
			
		||||
    {
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new FastRng.Distributions.WeibullK05La1(rng);
 | 
			
		||||
        var samples = new float[1_000];
 | 
			
		||||
        for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
            samples[n] = await dist.NextNumber(-1.0f, 1.0f);
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range");
 | 
			
		||||
            Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range");
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range");
 | 
			
		||||
        Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range");
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public async Task TestWeibullGeneratorWithRange02()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new FastRng.Distributions.WeibullK05La1(rng);
 | 
			
		||||
            var samples = new float[1_000];
 | 
			
		||||
            for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
                samples[n] = await dist.NextNumber(0.0f, 1.0f);
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public async Task TestWeibullGeneratorWithRange02()
 | 
			
		||||
    {
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new FastRng.Distributions.WeibullK05La1(rng);
 | 
			
		||||
        var samples = new float[1_000];
 | 
			
		||||
        for (var n = 0; n < samples.Length; n++)
 | 
			
		||||
            samples[n] = await dist.NextNumber(0.0f, 1.0f);
 | 
			
		||||
            
 | 
			
		||||
            Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range");
 | 
			
		||||
            Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range");
 | 
			
		||||
        }
 | 
			
		||||
        Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range");
 | 
			
		||||
        Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public void NoRandomNumberGenerator01()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.Throws<ArgumentNullException>(() => new FastRng.Distributions.WeibullK05La1(null));
 | 
			
		||||
        }
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public void NoRandomNumberGenerator01()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.Throws<ArgumentNullException>(() => new FastRng.Distributions.WeibullK05La1(null));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -3,82 +3,81 @@ using System.Diagnostics.CodeAnalysis;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
 | 
			
		||||
namespace FastRngTests
 | 
			
		||||
namespace FastRngTests;
 | 
			
		||||
 | 
			
		||||
[ExcludeFromCodeCoverage]
 | 
			
		||||
public sealed class FrequencyAnalysis
 | 
			
		||||
{
 | 
			
		||||
    [ExcludeFromCodeCoverage]
 | 
			
		||||
    public sealed class FrequencyAnalysis
 | 
			
		||||
    private readonly uint[] data;
 | 
			
		||||
        
 | 
			
		||||
    public FrequencyAnalysis(int samples = 100)
 | 
			
		||||
    {
 | 
			
		||||
        private readonly uint[] data;
 | 
			
		||||
        
 | 
			
		||||
        public FrequencyAnalysis(int samples = 100)
 | 
			
		||||
        this.data = new uint[samples];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void CountThis(float value)
 | 
			
		||||
    {
 | 
			
		||||
        var bucket = (int)MathF.Floor(value * this.data.Length);
 | 
			
		||||
        this.data[bucket]++;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public float[] GetNormalizedEvents()
 | 
			
		||||
    {
 | 
			
		||||
        var max = (float) this.data.Max();
 | 
			
		||||
        var result = new float[this.data.Length];
 | 
			
		||||
        for (var n = 0; n < this.data.Length; n++)
 | 
			
		||||
        {
 | 
			
		||||
            this.data = new uint[samples];
 | 
			
		||||
            result[n] = this.data[n] / max;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void CountThis(float value)
 | 
			
		||||
        {
 | 
			
		||||
            var bucket = (int)MathF.Floor(value * this.data.Length);
 | 
			
		||||
            this.data[bucket]++;
 | 
			
		||||
        }
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        public float[] GetNormalizedEvents()
 | 
			
		||||
        {
 | 
			
		||||
            var max = (float) this.data.Max();
 | 
			
		||||
            var result = new float[this.data.Length];
 | 
			
		||||
            for (var n = 0; n < this.data.Length; n++)
 | 
			
		||||
            {
 | 
			
		||||
                result[n] = this.data[n] / max;
 | 
			
		||||
            }
 | 
			
		||||
    private float[] Normalize()
 | 
			
		||||
    {
 | 
			
		||||
        var max = (float)this.data.Max();
 | 
			
		||||
        var result = new float[this.data.Length];
 | 
			
		||||
        for (var n = 0; n < this.data.Length; n++)
 | 
			
		||||
            result[n] = this.data[n] / max;
 | 
			
		||||
 | 
			
		||||
            return result;
 | 
			
		||||
        }
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        private float[] Normalize()
 | 
			
		||||
        {
 | 
			
		||||
            var max = (float)this.data.Max();
 | 
			
		||||
            var result = new float[this.data.Length];
 | 
			
		||||
            for (var n = 0; n < this.data.Length; n++)
 | 
			
		||||
                result[n] = this.data[n] / max;
 | 
			
		||||
 | 
			
		||||
            return result;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public float[] NormalizeAndPlotEvents(Action<string> writer)
 | 
			
		||||
        {
 | 
			
		||||
            var result = this.Normalize();
 | 
			
		||||
            FrequencyAnalysis.Plot(result, writer, "Event Distribution");
 | 
			
		||||
    public float[] NormalizeAndPlotEvents(Action<string> writer)
 | 
			
		||||
    {
 | 
			
		||||
        var result = this.Normalize();
 | 
			
		||||
        Plot(result, writer, "Event Distribution");
 | 
			
		||||
            
 | 
			
		||||
            return result;
 | 
			
		||||
        }
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
        public void PlotOccurence(Action<string> writer)
 | 
			
		||||
    public void PlotOccurence(Action<string> writer)
 | 
			
		||||
    {
 | 
			
		||||
        var data = this.data.Select(n => n > 0f ? 1.0f : 0.0f).ToArray();
 | 
			
		||||
        Plot(data, writer, "Occurrence Distribution");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static void Plot(float[] data, Action<string> writer, string name)
 | 
			
		||||
    {
 | 
			
		||||
        const int HEIGHT = 16;
 | 
			
		||||
            
 | 
			
		||||
        var values = new float[data.Length];
 | 
			
		||||
        for (var n = 0; n < data.Length; n++)
 | 
			
		||||
        {
 | 
			
		||||
            var data = this.data.Select(n => n > 0f ? 1.0f : 0.0f).ToArray();
 | 
			
		||||
            FrequencyAnalysis.Plot(data, writer, "Occurrence Distribution");
 | 
			
		||||
            values[n] = data[n] * HEIGHT;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static void Plot(float[] data, Action<string> writer, string name)
 | 
			
		||||
        var sb = new StringBuilder();
 | 
			
		||||
        for (var line = HEIGHT; line > 0; line--)
 | 
			
		||||
        {
 | 
			
		||||
            const int HEIGHT = 16;
 | 
			
		||||
            
 | 
			
		||||
            var values = new float[data.Length];
 | 
			
		||||
            for (var n = 0; n < data.Length; n++)
 | 
			
		||||
            {
 | 
			
		||||
                values[n] = data[n] * HEIGHT;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var sb = new StringBuilder();
 | 
			
		||||
            for (var line = HEIGHT; line > 0; line--)
 | 
			
		||||
            {
 | 
			
		||||
                for (var column = 0; column < data.Length; column++)
 | 
			
		||||
                    sb.Append(values[column] >= line ? '█' : '░');
 | 
			
		||||
            for (var column = 0; column < data.Length; column++)
 | 
			
		||||
                sb.Append(values[column] >= line ? '█' : '░');
 | 
			
		||||
                
 | 
			
		||||
                writer.Invoke(sb.ToString());
 | 
			
		||||
                sb.Clear();
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            writer.Invoke(name);
 | 
			
		||||
            writer.Invoke(string.Empty);
 | 
			
		||||
            writer.Invoke(sb.ToString());
 | 
			
		||||
            sb.Clear();
 | 
			
		||||
        }
 | 
			
		||||
            
 | 
			
		||||
        writer.Invoke(name);
 | 
			
		||||
        writer.Invoke(string.Empty);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -3,339 +3,338 @@ using System.Diagnostics.CodeAnalysis;
 | 
			
		||||
using FastRng;
 | 
			
		||||
using NUnit.Framework;
 | 
			
		||||
 | 
			
		||||
namespace FastRngTests
 | 
			
		||||
namespace FastRngTests;
 | 
			
		||||
 | 
			
		||||
[ExcludeFromCodeCoverage]
 | 
			
		||||
public class MathToolsTests
 | 
			
		||||
{
 | 
			
		||||
    [ExcludeFromCodeCoverage]
 | 
			
		||||
    public class MathToolsTests
 | 
			
		||||
    #region Gamma
 | 
			
		||||
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public void GammaTest01()
 | 
			
		||||
    {
 | 
			
		||||
        #region Gamma
 | 
			
		||||
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public void GammaTest01()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.That(MathTools.Gamma(-0.5f), Is.EqualTo(-3.544907701811087f).Within(1e-6f));
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public void GammaTest02()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.That(MathTools.Gamma(0.1f), Is.EqualTo(9.51350975f).Within(1e-6f));
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public void GammaTest03()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.That(MathTools.Gamma(0.5f), Is.EqualTo(1.772453850905517f).Within(1e-6f));
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public void GammaTest04()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.That(MathTools.Gamma(1.0f), Is.EqualTo(1.0f).Within(1e-6f));
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public void GammaTest05()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.That(MathTools.Gamma(1.5f), Is.EqualTo(0.8862269254527587f).Within(1e-6f));
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public void GammaTest06()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.That(MathTools.Gamma(2.0f), Is.EqualTo(1.0f).Within(1e-6f));
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public void GammaTest07()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.That(MathTools.Gamma(3.0f), Is.EqualTo(2.0f).Within(1e-6f));
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public void GammaTest08()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.That(MathTools.Gamma(10.0f), Is.EqualTo(362_880.719f).Within(1e-6f));
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public void GammaTest09()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.That(MathTools.Gamma(140.0f), Is.EqualTo(float.NaN));
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public void GammaTest10()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.That(MathTools.Gamma(170.0f), Is.EqualTo(float.NaN));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        #endregion
 | 
			
		||||
 | 
			
		||||
        #region Factorial (integer)
 | 
			
		||||
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public void FactorialInteger01()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.That(MathTools.Factorial(0), Is.EqualTo(1));
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public void FactorialInteger02()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.That(MathTools.Factorial(1), Is.EqualTo(1));
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public void FactorialInteger03()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.That(MathTools.Factorial(2), Is.EqualTo(2));
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public void FactorialInteger04()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.That(MathTools.Factorial(3), Is.EqualTo(6));
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public void FactorialInteger05()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.That(MathTools.Factorial(4), Is.EqualTo(24));
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public void FactorialInteger06()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.That(MathTools.Factorial(5), Is.EqualTo(120));
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public void FactorialInteger07()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.That(MathTools.Factorial(6), Is.EqualTo(720));
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public void FactorialInteger08()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.That(MathTools.Factorial(7), Is.EqualTo(5_040));
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public void FactorialInteger09()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.That(MathTools.Factorial(8), Is.EqualTo(40_320));
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public void FactorialInteger10()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.That(MathTools.Factorial(9), Is.EqualTo(362_880));
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public void FactorialInteger11()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.That(MathTools.Factorial(10), Is.EqualTo(3_628_800));
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public void FactorialInteger12()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.That(MathTools.Factorial(11), Is.EqualTo(39_916_800));
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public void FactorialInteger13()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.That(MathTools.Factorial(12), Is.EqualTo(479_001_600));
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public void FactorialInteger14()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.That(MathTools.Factorial(13), Is.EqualTo(6_227_020_800));
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public void FactorialInteger15()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.That(MathTools.Factorial(14), Is.EqualTo(87_178_291_200));
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public void FactorialInteger16()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.That(MathTools.Factorial(15), Is.EqualTo(1_307_674_368_000));
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public void FactorialInteger17()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.That(MathTools.Factorial(16), Is.EqualTo(20_922_789_888_000));
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public void FactorialInteger18()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.That(MathTools.Factorial(17), Is.EqualTo(355_687_428_096_000));
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public void FactorialInteger19()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.That(MathTools.Factorial(18), Is.EqualTo(6_402_373_705_728_000));
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public void FactorialInteger20()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.That(MathTools.Factorial(19), Is.EqualTo(121_645_100_408_832_000));
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public void FactorialInteger21()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.That(MathTools.Factorial(20), Is.EqualTo(2_432_902_008_176_640_000));
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public void FactorialInteger22()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.Throws<ArgumentOutOfRangeException>(() => MathTools.Factorial(21));
 | 
			
		||||
 | 
			
		||||
            // Note: 21! is not possible in C# until we got 128 bit integers, since:
 | 
			
		||||
            //       ulong.max == 18_446_744_073_709_551_615 < 51_090_942_171_709_400_000
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public void FactorialInteger23()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.Throws<ArgumentOutOfRangeException>(() => MathTools.Factorial(45_646));
 | 
			
		||||
 | 
			
		||||
            // Note: 45_646! is not possible in C# since:
 | 
			
		||||
            //       ulong.max == 18_446_744_073_709_551_615
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public void FactorialInteger24()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.Throws<ArgumentOutOfRangeException>(() => MathTools.Factorial(-1));
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public void FactorialInteger25()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.Throws<ArgumentOutOfRangeException>(() => MathTools.Factorial(-6_565));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        #endregion
 | 
			
		||||
 | 
			
		||||
        #region Factorial (floating point)
 | 
			
		||||
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public void FactorialFloatingPoint01()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.That(MathTools.Factorial(0.5f), Is.EqualTo(0.886226925f).Within(1e6f));
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public void FactorialFloatingPoint02()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.That(MathTools.Factorial(1.5f), Is.EqualTo(1.329340388f).Within(1e6f));
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public void FactorialFloatingPoint03()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.That(MathTools.Factorial(-1.5f), Is.EqualTo(-1.329340388f).Within(1e6f));
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.COVER)]
 | 
			
		||||
        [Category(TestCategories.NORMAL)]
 | 
			
		||||
        public void FactorialFloatingPoint04()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.That(MathTools.Factorial(7.5f), Is.EqualTo(14_034.407293483f).Within(1e6f));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        #endregion
 | 
			
		||||
        Assert.That(MathTools.Gamma(-0.5f), Is.EqualTo(-3.544907701811087f).Within(1e-6f));
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public void GammaTest02()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.That(MathTools.Gamma(0.1f), Is.EqualTo(9.51350975f).Within(1e-6f));
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public void GammaTest03()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.That(MathTools.Gamma(0.5f), Is.EqualTo(1.772453850905517f).Within(1e-6f));
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public void GammaTest04()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.That(MathTools.Gamma(1.0f), Is.EqualTo(1.0f).Within(1e-6f));
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public void GammaTest05()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.That(MathTools.Gamma(1.5f), Is.EqualTo(0.8862269254527587f).Within(1e-6f));
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public void GammaTest06()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.That(MathTools.Gamma(2.0f), Is.EqualTo(1.0f).Within(1e-6f));
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public void GammaTest07()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.That(MathTools.Gamma(3.0f), Is.EqualTo(2.0f).Within(1e-6f));
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public void GammaTest08()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.That(MathTools.Gamma(10.0f), Is.EqualTo(362_880.719f).Within(1e-6f));
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public void GammaTest09()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.That(MathTools.Gamma(140.0f), Is.EqualTo(float.NaN));
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public void GammaTest10()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.That(MathTools.Gamma(170.0f), Is.EqualTo(float.NaN));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #endregion
 | 
			
		||||
 | 
			
		||||
    #region Factorial (integer)
 | 
			
		||||
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public void FactorialInteger01()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.That(MathTools.Factorial(0), Is.EqualTo(1));
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public void FactorialInteger02()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.That(MathTools.Factorial(1), Is.EqualTo(1));
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public void FactorialInteger03()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.That(MathTools.Factorial(2), Is.EqualTo(2));
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public void FactorialInteger04()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.That(MathTools.Factorial(3), Is.EqualTo(6));
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public void FactorialInteger05()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.That(MathTools.Factorial(4), Is.EqualTo(24));
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public void FactorialInteger06()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.That(MathTools.Factorial(5), Is.EqualTo(120));
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public void FactorialInteger07()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.That(MathTools.Factorial(6), Is.EqualTo(720));
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public void FactorialInteger08()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.That(MathTools.Factorial(7), Is.EqualTo(5_040));
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public void FactorialInteger09()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.That(MathTools.Factorial(8), Is.EqualTo(40_320));
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public void FactorialInteger10()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.That(MathTools.Factorial(9), Is.EqualTo(362_880));
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public void FactorialInteger11()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.That(MathTools.Factorial(10), Is.EqualTo(3_628_800));
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public void FactorialInteger12()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.That(MathTools.Factorial(11), Is.EqualTo(39_916_800));
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public void FactorialInteger13()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.That(MathTools.Factorial(12), Is.EqualTo(479_001_600));
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public void FactorialInteger14()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.That(MathTools.Factorial(13), Is.EqualTo(6_227_020_800));
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public void FactorialInteger15()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.That(MathTools.Factorial(14), Is.EqualTo(87_178_291_200));
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public void FactorialInteger16()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.That(MathTools.Factorial(15), Is.EqualTo(1_307_674_368_000));
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public void FactorialInteger17()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.That(MathTools.Factorial(16), Is.EqualTo(20_922_789_888_000));
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public void FactorialInteger18()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.That(MathTools.Factorial(17), Is.EqualTo(355_687_428_096_000));
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public void FactorialInteger19()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.That(MathTools.Factorial(18), Is.EqualTo(6_402_373_705_728_000));
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public void FactorialInteger20()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.That(MathTools.Factorial(19), Is.EqualTo(121_645_100_408_832_000));
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public void FactorialInteger21()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.That(MathTools.Factorial(20), Is.EqualTo(2_432_902_008_176_640_000));
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public void FactorialInteger22()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.Throws<ArgumentOutOfRangeException>(() => MathTools.Factorial(21));
 | 
			
		||||
 | 
			
		||||
        // Note: 21! is not possible in C# until we got 128 bit integers, since:
 | 
			
		||||
        //       ulong.max == 18_446_744_073_709_551_615 < 51_090_942_171_709_400_000
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public void FactorialInteger23()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.Throws<ArgumentOutOfRangeException>(() => MathTools.Factorial(45_646));
 | 
			
		||||
 | 
			
		||||
        // Note: 45_646! is not possible in C# since:
 | 
			
		||||
        //       ulong.max == 18_446_744_073_709_551_615
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public void FactorialInteger24()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.Throws<ArgumentOutOfRangeException>(() => MathTools.Factorial(-1));
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public void FactorialInteger25()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.Throws<ArgumentOutOfRangeException>(() => MathTools.Factorial(-6_565));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #endregion
 | 
			
		||||
 | 
			
		||||
    #region Factorial (floating point)
 | 
			
		||||
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public void FactorialFloatingPoint01()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.That(MathTools.Factorial(0.5f), Is.EqualTo(0.886226925f).Within(1e6f));
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public void FactorialFloatingPoint02()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.That(MathTools.Factorial(1.5f), Is.EqualTo(1.329340388f).Within(1e6f));
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public void FactorialFloatingPoint03()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.That(MathTools.Factorial(-1.5f), Is.EqualTo(-1.329340388f).Within(1e6f));
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.COVER)]
 | 
			
		||||
    [Category(TestCategories.NORMAL)]
 | 
			
		||||
    public void FactorialFloatingPoint04()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.That(MathTools.Factorial(7.5f), Is.EqualTo(14_034.407293483f).Within(1e6f));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #endregion
 | 
			
		||||
}
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@ -9,129 +9,128 @@ using MathNet.Numerics.Distributions;
 | 
			
		||||
using MathNet.Numerics.Random;
 | 
			
		||||
using NUnit.Framework;
 | 
			
		||||
 | 
			
		||||
namespace FastRngTests
 | 
			
		||||
namespace FastRngTests;
 | 
			
		||||
 | 
			
		||||
[ExcludeFromCodeCoverage]
 | 
			
		||||
public class PerformanceTests
 | 
			
		||||
{
 | 
			
		||||
    [ExcludeFromCodeCoverage]
 | 
			
		||||
    public class PerformanceTests
 | 
			
		||||
    #region FastRng
 | 
			
		||||
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.PERFORMANCE)]
 | 
			
		||||
    public async Task Generate1MUniform()
 | 
			
		||||
    {
 | 
			
		||||
        #region FastRng
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var data = new float[1_000_000];
 | 
			
		||||
        var stopwatch = new Stopwatch();
 | 
			
		||||
        Thread.Sleep(TimeSpan.FromSeconds(10)); // Warm-up phase of generator
 | 
			
		||||
            
 | 
			
		||||
        stopwatch.Start();
 | 
			
		||||
        for (uint n = 0; n < data.Length; n++)
 | 
			
		||||
            data[n] = await rng.GetUniform();
 | 
			
		||||
            
 | 
			
		||||
        stopwatch.Stop();
 | 
			
		||||
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.PERFORMANCE)]
 | 
			
		||||
        public async Task Generate1MUniform()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var data = new float[1_000_000];
 | 
			
		||||
            var stopwatch = new Stopwatch();
 | 
			
		||||
            Thread.Sleep(TimeSpan.FromSeconds(10)); // Warm-up phase of generator
 | 
			
		||||
            
 | 
			
		||||
            stopwatch.Start();
 | 
			
		||||
            for (uint n = 0; n < data.Length; n++)
 | 
			
		||||
                data[n] = await rng.GetUniform();
 | 
			
		||||
            
 | 
			
		||||
            stopwatch.Stop();
 | 
			
		||||
 | 
			
		||||
            TestContext.WriteLine($"Generated 1M uniform distributed random numbers in {stopwatch.Elapsed.Minutes} minute(s), {stopwatch.Elapsed.Seconds} second(s), and {stopwatch.Elapsed.Milliseconds} milliseconds.");
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.PERFORMANCE)]
 | 
			
		||||
        public async Task Generate1MNormal()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new NormalS02M05(rng);
 | 
			
		||||
            var data = new float[1_000_000];
 | 
			
		||||
            var stopwatch = new Stopwatch();
 | 
			
		||||
            Thread.Sleep(TimeSpan.FromSeconds(10)); // Warm-up phase of generator
 | 
			
		||||
            
 | 
			
		||||
            stopwatch.Start();
 | 
			
		||||
            for (uint n = 0; n < data.Length; n++)
 | 
			
		||||
                data[n] = await dist.NextNumber();
 | 
			
		||||
            
 | 
			
		||||
            stopwatch.Stop();
 | 
			
		||||
 | 
			
		||||
            TestContext.WriteLine($"Generated 1M normal distributed random numbers in {stopwatch.Elapsed.Minutes} minute(s), {stopwatch.Elapsed.Seconds} second(s), and {stopwatch.Elapsed.Milliseconds} milliseconds.");
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.PERFORMANCE)]
 | 
			
		||||
        public async Task Generate1MChiSquare()
 | 
			
		||||
        {
 | 
			
		||||
            using var rng = new MultiThreadedRng();
 | 
			
		||||
            var dist = new ChiSquareK4(rng);
 | 
			
		||||
            var data = new float[1_000_000];
 | 
			
		||||
            var stopwatch = new Stopwatch();
 | 
			
		||||
            Thread.Sleep(TimeSpan.FromSeconds(10)); // Warm-up phase of generator
 | 
			
		||||
            
 | 
			
		||||
            stopwatch.Start();
 | 
			
		||||
            for (uint n = 0; n < data.Length; n++)
 | 
			
		||||
                data[n] = await dist.NextNumber();
 | 
			
		||||
            
 | 
			
		||||
            stopwatch.Stop();
 | 
			
		||||
 | 
			
		||||
            TestContext.WriteLine($"Generated 1M chi-square distributed random numbers in {stopwatch.Elapsed.Minutes} minute(s), {stopwatch.Elapsed.Seconds} second(s), and {stopwatch.Elapsed.Milliseconds} milliseconds.");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        #endregion
 | 
			
		||||
 | 
			
		||||
        #region Math.NET
 | 
			
		||||
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.PERFORMANCE)]
 | 
			
		||||
        public void ComparisonMathNet1MUniform()
 | 
			
		||||
        {
 | 
			
		||||
            var rng = new Xorshift(true);
 | 
			
		||||
            var data = new float[1_000_000];
 | 
			
		||||
            var stopwatch = new Stopwatch();
 | 
			
		||||
            Thread.Sleep(TimeSpan.FromSeconds(10)); // Warm-up phase of generator
 | 
			
		||||
            
 | 
			
		||||
            stopwatch.Start();
 | 
			
		||||
            for (uint n = 0; n < data.Length; n++)
 | 
			
		||||
                data[n] = (float) rng.NextDouble();
 | 
			
		||||
            
 | 
			
		||||
            stopwatch.Stop();
 | 
			
		||||
            
 | 
			
		||||
            TestContext.WriteLine($"Generated 1M uniform distributed random numbers by means of Math.NET in {stopwatch.Elapsed.Minutes} minute(s), {stopwatch.Elapsed.Seconds} second(s), and {stopwatch.Elapsed.Milliseconds} milliseconds.");
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.PERFORMANCE)]
 | 
			
		||||
        public void ComparisonMathNet1MNormal()
 | 
			
		||||
        {
 | 
			
		||||
            var rng = new Xorshift(true);
 | 
			
		||||
            var dist = new Normal(stddev: 0.2f, mean: 0.5f, randomSource: rng);
 | 
			
		||||
            var data = new float[1_000_000];
 | 
			
		||||
            var stopwatch = new Stopwatch();
 | 
			
		||||
            Thread.Sleep(TimeSpan.FromSeconds(10)); // Warm-up phase of generator
 | 
			
		||||
            
 | 
			
		||||
            stopwatch.Start();
 | 
			
		||||
            for (uint n = 0; n < data.Length; n++)
 | 
			
		||||
                data[n] = (float) dist.Sample();
 | 
			
		||||
            
 | 
			
		||||
            stopwatch.Stop();
 | 
			
		||||
            
 | 
			
		||||
            TestContext.WriteLine($"Generated 1M normal distributed random numbers by means of Math.NET in {stopwatch.Elapsed.Minutes} minute(s), {stopwatch.Elapsed.Seconds} second(s), and {stopwatch.Elapsed.Milliseconds} milliseconds.");
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        [Test]
 | 
			
		||||
        [Category(TestCategories.PERFORMANCE)]
 | 
			
		||||
        public void ComparisonMathNet1MChiSquare()
 | 
			
		||||
        {
 | 
			
		||||
            var rng = new Xorshift(true);
 | 
			
		||||
            var dist = new ChiSquared(4);
 | 
			
		||||
            var data = new float[1_000_000];
 | 
			
		||||
            var stopwatch = new Stopwatch();
 | 
			
		||||
            Thread.Sleep(TimeSpan.FromSeconds(10)); // Warm-up phase of generator
 | 
			
		||||
            
 | 
			
		||||
            stopwatch.Start();
 | 
			
		||||
            for (uint n = 0; n < data.Length; n++)
 | 
			
		||||
                data[n] = (float) dist.Sample();
 | 
			
		||||
            
 | 
			
		||||
            stopwatch.Stop();
 | 
			
		||||
            
 | 
			
		||||
            TestContext.WriteLine($"Generated 1M chi-squared distributed random numbers by means of Math.NET in {stopwatch.Elapsed.Minutes} minute(s), {stopwatch.Elapsed.Seconds} second(s), and {stopwatch.Elapsed.Milliseconds} milliseconds.");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        #endregion
 | 
			
		||||
        TestContext.WriteLine($"Generated 1M uniform distributed random numbers in {stopwatch.Elapsed.Minutes} minute(s), {stopwatch.Elapsed.Seconds} second(s), and {stopwatch.Elapsed.Milliseconds} milliseconds.");
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.PERFORMANCE)]
 | 
			
		||||
    public async Task Generate1MNormal()
 | 
			
		||||
    {
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new NormalS02M05(rng);
 | 
			
		||||
        var data = new float[1_000_000];
 | 
			
		||||
        var stopwatch = new Stopwatch();
 | 
			
		||||
        Thread.Sleep(TimeSpan.FromSeconds(10)); // Warm-up phase of generator
 | 
			
		||||
            
 | 
			
		||||
        stopwatch.Start();
 | 
			
		||||
        for (uint n = 0; n < data.Length; n++)
 | 
			
		||||
            data[n] = await dist.NextNumber();
 | 
			
		||||
            
 | 
			
		||||
        stopwatch.Stop();
 | 
			
		||||
 | 
			
		||||
        TestContext.WriteLine($"Generated 1M normal distributed random numbers in {stopwatch.Elapsed.Minutes} minute(s), {stopwatch.Elapsed.Seconds} second(s), and {stopwatch.Elapsed.Milliseconds} milliseconds.");
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.PERFORMANCE)]
 | 
			
		||||
    public async Task Generate1MChiSquare()
 | 
			
		||||
    {
 | 
			
		||||
        using var rng = new MultiThreadedRng();
 | 
			
		||||
        var dist = new ChiSquareK4(rng);
 | 
			
		||||
        var data = new float[1_000_000];
 | 
			
		||||
        var stopwatch = new Stopwatch();
 | 
			
		||||
        Thread.Sleep(TimeSpan.FromSeconds(10)); // Warm-up phase of generator
 | 
			
		||||
            
 | 
			
		||||
        stopwatch.Start();
 | 
			
		||||
        for (uint n = 0; n < data.Length; n++)
 | 
			
		||||
            data[n] = await dist.NextNumber();
 | 
			
		||||
            
 | 
			
		||||
        stopwatch.Stop();
 | 
			
		||||
 | 
			
		||||
        TestContext.WriteLine($"Generated 1M chi-square distributed random numbers in {stopwatch.Elapsed.Minutes} minute(s), {stopwatch.Elapsed.Seconds} second(s), and {stopwatch.Elapsed.Milliseconds} milliseconds.");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #endregion
 | 
			
		||||
 | 
			
		||||
    #region Math.NET
 | 
			
		||||
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.PERFORMANCE)]
 | 
			
		||||
    public void ComparisonMathNet1MUniform()
 | 
			
		||||
    {
 | 
			
		||||
        var rng = new Xorshift(true);
 | 
			
		||||
        var data = new float[1_000_000];
 | 
			
		||||
        var stopwatch = new Stopwatch();
 | 
			
		||||
        Thread.Sleep(TimeSpan.FromSeconds(10)); // Warm-up phase of generator
 | 
			
		||||
            
 | 
			
		||||
        stopwatch.Start();
 | 
			
		||||
        for (uint n = 0; n < data.Length; n++)
 | 
			
		||||
            data[n] = (float) rng.NextDouble();
 | 
			
		||||
            
 | 
			
		||||
        stopwatch.Stop();
 | 
			
		||||
            
 | 
			
		||||
        TestContext.WriteLine($"Generated 1M uniform distributed random numbers by means of Math.NET in {stopwatch.Elapsed.Minutes} minute(s), {stopwatch.Elapsed.Seconds} second(s), and {stopwatch.Elapsed.Milliseconds} milliseconds.");
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.PERFORMANCE)]
 | 
			
		||||
    public void ComparisonMathNet1MNormal()
 | 
			
		||||
    {
 | 
			
		||||
        var rng = new Xorshift(true);
 | 
			
		||||
        var dist = new Normal(stddev: 0.2f, mean: 0.5f, randomSource: rng);
 | 
			
		||||
        var data = new float[1_000_000];
 | 
			
		||||
        var stopwatch = new Stopwatch();
 | 
			
		||||
        Thread.Sleep(TimeSpan.FromSeconds(10)); // Warm-up phase of generator
 | 
			
		||||
            
 | 
			
		||||
        stopwatch.Start();
 | 
			
		||||
        for (uint n = 0; n < data.Length; n++)
 | 
			
		||||
            data[n] = (float) dist.Sample();
 | 
			
		||||
            
 | 
			
		||||
        stopwatch.Stop();
 | 
			
		||||
            
 | 
			
		||||
        TestContext.WriteLine($"Generated 1M normal distributed random numbers by means of Math.NET in {stopwatch.Elapsed.Minutes} minute(s), {stopwatch.Elapsed.Seconds} second(s), and {stopwatch.Elapsed.Milliseconds} milliseconds.");
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    [Test]
 | 
			
		||||
    [Category(TestCategories.PERFORMANCE)]
 | 
			
		||||
    public void ComparisonMathNet1MChiSquare()
 | 
			
		||||
    {
 | 
			
		||||
        var rng = new Xorshift(true);
 | 
			
		||||
        var dist = new ChiSquared(4);
 | 
			
		||||
        var data = new float[1_000_000];
 | 
			
		||||
        var stopwatch = new Stopwatch();
 | 
			
		||||
        Thread.Sleep(TimeSpan.FromSeconds(10)); // Warm-up phase of generator
 | 
			
		||||
            
 | 
			
		||||
        stopwatch.Start();
 | 
			
		||||
        for (uint n = 0; n < data.Length; n++)
 | 
			
		||||
            data[n] = (float) dist.Sample();
 | 
			
		||||
            
 | 
			
		||||
        stopwatch.Stop();
 | 
			
		||||
            
 | 
			
		||||
        TestContext.WriteLine($"Generated 1M chi-squared distributed random numbers by means of Math.NET in {stopwatch.Elapsed.Minutes} minute(s), {stopwatch.Elapsed.Seconds} second(s), and {stopwatch.Elapsed.Milliseconds} milliseconds.");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #endregion
 | 
			
		||||
}
 | 
			
		||||
@ -1,49 +1,44 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Diagnostics.CodeAnalysis;
 | 
			
		||||
 | 
			
		||||
namespace FastRngTests
 | 
			
		||||
namespace FastRngTests;
 | 
			
		||||
 | 
			
		||||
[ExcludeFromCodeCoverage]
 | 
			
		||||
internal sealed class RunningStatistics
 | 
			
		||||
{
 | 
			
		||||
    [ExcludeFromCodeCoverage]
 | 
			
		||||
    internal sealed class RunningStatistics
 | 
			
		||||
    {
 | 
			
		||||
        private float previousM;
 | 
			
		||||
        private float previousS;
 | 
			
		||||
        private float nextM;
 | 
			
		||||
        private float nextS;
 | 
			
		||||
  
 | 
			
		||||
        public RunningStatistics()
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
        public int NumberRecords { get; private set; } = 0;
 | 
			
		||||
    private float previousM;
 | 
			
		||||
    private float previousS;
 | 
			
		||||
    private float nextM;
 | 
			
		||||
    private float nextS;
 | 
			
		||||
 | 
			
		||||
    private int NumberRecords { get; set; } = 0;
 | 
			
		||||
        
 | 
			
		||||
        public void Clear() => this.NumberRecords = 0;
 | 
			
		||||
    public void Clear() => this.NumberRecords = 0;
 | 
			
		||||
 | 
			
		||||
        public void Push(float x)
 | 
			
		||||
        {
 | 
			
		||||
            this.NumberRecords++;
 | 
			
		||||
    public void Push(float x)
 | 
			
		||||
    {
 | 
			
		||||
        this.NumberRecords++;
 | 
			
		||||
 
 | 
			
		||||
            // See Knuth TAOCP vol 2, 3rd edition, page 232
 | 
			
		||||
            if (this.NumberRecords == 1)
 | 
			
		||||
            {
 | 
			
		||||
                this.previousM = this.nextM = x;
 | 
			
		||||
                this.previousS = 0.0f;
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                this.nextM = this.previousM + (x - this.previousM) / this.NumberRecords;
 | 
			
		||||
                this.nextS = this.previousS + (x - this.previousM) * (x - this.nextM);
 | 
			
		||||
     
 | 
			
		||||
                // set up for next iteration
 | 
			
		||||
                this.previousM = this.nextM;
 | 
			
		||||
                this.previousS = this.nextS;
 | 
			
		||||
            }
 | 
			
		||||
        // See Knuth TAOCP vol 2, 3rd edition, page 232
 | 
			
		||||
        if (this.NumberRecords == 1)
 | 
			
		||||
        {
 | 
			
		||||
            this.previousM = this.nextM = x;
 | 
			
		||||
            this.previousS = 0.0f;
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            this.nextM = this.previousM + (x - this.previousM) / this.NumberRecords;
 | 
			
		||||
            this.nextS = this.previousS + (x - this.previousM) * (x - this.nextM);
 | 
			
		||||
     
 | 
			
		||||
            // set up for next iteration
 | 
			
		||||
            this.previousM = this.nextM;
 | 
			
		||||
            this.previousS = this.nextS;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public float Mean => this.NumberRecords > 0 ? this.nextM : 0.0f;
 | 
			
		||||
 | 
			
		||||
        public float Variance => this.NumberRecords > 1 ? this.nextS / (this.NumberRecords - 1f) : 0.0f;
 | 
			
		||||
 | 
			
		||||
        public float StandardDeviation => MathF.Sqrt(this.Variance);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public float Mean => this.NumberRecords > 0 ? this.nextM : 0.0f;
 | 
			
		||||
 | 
			
		||||
    public float Variance => this.NumberRecords > 1 ? this.nextS / (this.NumberRecords - 1f) : 0.0f;
 | 
			
		||||
 | 
			
		||||
    public float StandardDeviation => MathF.Sqrt(this.Variance);
 | 
			
		||||
}
 | 
			
		||||
@ -1,11 +1,10 @@
 | 
			
		||||
namespace FastRngTests
 | 
			
		||||
namespace FastRngTests;
 | 
			
		||||
 | 
			
		||||
public static class TestCategories
 | 
			
		||||
{
 | 
			
		||||
    public class TestCategories
 | 
			
		||||
    {
 | 
			
		||||
        public const string COVER = "cover";
 | 
			
		||||
        public const string PERFORMANCE = "performance";
 | 
			
		||||
        public const string NORMAL = "normal";
 | 
			
		||||
        public const string EXAMPLE = "example";
 | 
			
		||||
        public const string LONG_RUNNING = "long running";
 | 
			
		||||
    }
 | 
			
		||||
    public const string COVER = "cover";
 | 
			
		||||
    public const string PERFORMANCE = "performance";
 | 
			
		||||
    public const string NORMAL = "normal";
 | 
			
		||||
    public const string EXAMPLE = "example";
 | 
			
		||||
    public const string LONG_RUNNING = "long running";
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user