Refactored to use a shape fitter
This commit is contained in:
		
							parent
							
								
									f69330d79e
								
							
						
					
					
						commit
						25c773b411
					
				@ -1,4 +1,5 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Runtime.CompilerServices;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
@ -6,42 +7,38 @@ namespace FastRng.Double.Distributions
 | 
			
		||||
{
 | 
			
		||||
    public sealed class Normal : IDistribution
 | 
			
		||||
    {
 | 
			
		||||
        private double standardDeviation = 1.0;
 | 
			
		||||
        private const double SQRT_2PI = 2.506628275;
 | 
			
		||||
        private const double STDDEV = 0.4;
 | 
			
		||||
        private const double MEAN = 0.5;
 | 
			
		||||
        
 | 
			
		||||
        public IRandom Random { get; set; }
 | 
			
		||||
        private ShapeFitter fitter;
 | 
			
		||||
        private IRandom random;
 | 
			
		||||
 | 
			
		||||
        public double Mean { get; set; } = 0.0;
 | 
			
		||||
 | 
			
		||||
        public double StandardDeviation
 | 
			
		||||
        public Normal()
 | 
			
		||||
        {
 | 
			
		||||
            get => this.standardDeviation;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        public IRandom Random
 | 
			
		||||
        {
 | 
			
		||||
            get => this.random;
 | 
			
		||||
            set
 | 
			
		||||
            {
 | 
			
		||||
                if(value <= 0.0)
 | 
			
		||||
                    throw new ArgumentOutOfRangeException(message: "Standard deviation must be greater than 0", null);
 | 
			
		||||
                
 | 
			
		||||
                this.standardDeviation = value;
 | 
			
		||||
                this.random = value;
 | 
			
		||||
                this.fitter = new ShapeFitter(ShapeFunction, this.random, 100, 0.99);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        private static double ShapeFunction(double x)
 | 
			
		||||
        {
 | 
			
		||||
            return 1.0 / (STDDEV * SQRT_2PI) * Math.Exp(-Math.Pow((x - MEAN) / STDDEV, 2.0));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public async ValueTask<double> GetDistributedValue(CancellationToken token = default)
 | 
			
		||||
        {
 | 
			
		||||
            if (this.Random == null)
 | 
			
		||||
                return double.NaN;
 | 
			
		||||
 | 
			
		||||
            //
 | 
			
		||||
            // Previously:
 | 
			
		||||
            //
 | 
			
		||||
            // var u1 = await this.Random.GetUniform(token);
 | 
			
		||||
            // var u2 = await this.Random.GetUniform(token);
 | 
			
		||||
            // var r = Math.Sqrt(-2.0 * Math.Log(u1));
 | 
			
		||||
            // var theta = 2.0 * Math.PI * u2;
 | 
			
		||||
            // var value = r * Math.Sin(theta);
 | 
			
		||||
            // return this.Mean + this.StandardDeviation * value;
 | 
			
		||||
            
 | 
			
		||||
            const double SQRT_2PI = 2.506628275;
 | 
			
		||||
            var x = await this.Random.GetUniform(token); // BUG: It seems, that uniform is not uniform (enough) or RunningStatistics had specific issues. Test, if Math.NET's uniform is better.
 | 
			
		||||
            return 1.0 / (this.StandardDeviation * SQRT_2PI) * Math.Exp(-0.5 * Math.Pow((x - this.Mean) / this.StandardDeviation, 2.0));
 | 
			
		||||
            return await this.fitter.NextNumber(); // TODO: Add token!
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user