This commit is contained in:
Thorsten Sommer 2020-09-26 12:44:18 +02:00
parent 0432dd066e
commit d1d7abc43f
7 changed files with 270 additions and 0 deletions

View File

@ -0,0 +1,52 @@
using System;
using System.Threading;
using System.Threading.Tasks;
namespace FastRng.Double.Distributions
{
public sealed class Beta : IDistribution
{
private double a = 1.0;
private double b = 1.0;
public IRandom Random { get; set; }
public double A
{
get => this.a;
set
{
if(value <= 0.0)
throw new ArgumentOutOfRangeException(message: "Parameter must be greater than 0", null);
this.a = value;
}
}
public double B
{
get => this.b;
set
{
if(value <= 0.0)
throw new ArgumentOutOfRangeException(message: "Parameter must be greater than 0", null);
this.b = value;
}
}
public async ValueTask<double> GetDistributedValue(CancellationToken token)
{
if (this.Random == null)
return System.Double.NaN;
// There are more efficient methods for generating beta samples.
// However such methods are a little more efficient and much more complicated.
// For an explanation of why the following method works, see
// http://www.johndcook.com/distribution_chart.html#gamma_beta
var u = await this.Random.NextNumber(new Gamma{Shape = this.A, Scale = 1.0}, token);
var v = await this.Random.NextNumber(new Gamma{Shape = this.B, Scale = 1.0}, token);
return u / (u + v);
}
}
}

View File

@ -0,0 +1,36 @@
using System;
using System.Threading;
using System.Threading.Tasks;
namespace FastRng.Double.Distributions
{
public sealed class Cauchy : IDistribution
{
private double scale = 1.0;
public IRandom Random { get; set; }
public double Scale
{
get => this.scale;
set
{
if(value <= 0.0)
throw new ArgumentOutOfRangeException(message: "Scale must be greater than 0", null);
this.scale = value;
}
}
public double Median { get; set; } = 0.0;
public async ValueTask<double> GetDistributedValue(CancellationToken token)
{
if (this.Random == null)
return System.Double.NaN;
var value = await this.Random.GetUniform(token);
return this.Median + scale * Math.Tan(Math.PI * (value - 0.5));
}
}
}

View File

@ -0,0 +1,36 @@
using System;
using System.Threading;
using System.Threading.Tasks;
namespace FastRng.Double.Distributions
{
public sealed class InverseGamma : IDistribution
{
private double shape = 1.0;
public IRandom Random { get; set; }
public double Shape
{
get => this.shape;
set
{
if(value <= 0.0)
throw new ArgumentOutOfRangeException(message: "Shape must be greater than 0", null);
this.shape = value;
}
}
public double Scale { get; set; } = 1.0;
public async ValueTask<double> GetDistributedValue(CancellationToken token)
{
if (this.Random == null)
return System.Double.NaN;
var gammaDist = new Gamma{ Shape = this.Shape, Scale = 1.0 / this.Scale };
return 1.0 / await this.Random.NextNumber(gammaDist, token);
}
}
}

View File

@ -0,0 +1,28 @@
using System;
using System.Threading;
using System.Threading.Tasks;
namespace FastRng.Double.Distributions
{
public sealed class Laplace : IDistribution
{
public IRandom Random { get; set; }
public double Mean { get; set; } = 0.0;
public double Scale { get; set; } = 1.0;
public async ValueTask<double> GetDistributedValue(CancellationToken token)
{
if (this.Random == null)
return System.Double.NaN;
var value = await this.Random.GetUniform(token);
if (value < 0.5)
return this.Mean + this.Scale * Math.Log(2.0 * value);
else
return this.Mean - this.Scale * Math.Log(2.0 * (1.0 - value));
}
}
}

View File

@ -0,0 +1,35 @@
using System;
using System.Threading;
using System.Threading.Tasks;
namespace FastRng.Double.Distributions
{
public sealed class LogNormal : IDistribution
{
private double sigma = 1.0;
public IRandom Random { get; set; }
public double Mu { get; set; } = 0.0;
public double Sigma
{
get => this.sigma;
set
{
if(value <= 0.0)
throw new ArgumentOutOfRangeException(message: "Sigma must be greater than 0", null);
this.sigma = value;
}
}
public async ValueTask<double> GetDistributedValue(CancellationToken token)
{
if (this.Random == null)
return System.Double.NaN;
var normal = await this.Random.NextNumber(new Normal {Mean = this.Mu, StandardDeviation = this.Sigma}, token);
return Math.Exp(normal);
}
}
}

View File

@ -0,0 +1,36 @@
using System;
using System.Threading;
using System.Threading.Tasks;
namespace FastRng.Double.Distributions
{
public sealed class StudentT : IDistribution
{
private static readonly IDistribution NORMAL_DISTRIBUTED = new Normal();
private double degreesOfFreedom = 1.0;
public IRandom Random { get; set; }
public double DegreesOfFreedom
{
get => this.degreesOfFreedom;
set
{
if(value <= 0.0)
throw new ArgumentOutOfRangeException(message: "DegreesOfFreedom must be greater than 0", null);
this.degreesOfFreedom = value;
}
}
public async ValueTask<double> GetDistributedValue(CancellationToken token)
{
if (this.Random == null)
return System.Double.NaN;
var normal = await this.Random.NextNumber(NORMAL_DISTRIBUTED, token);
var chiSquare = await this.Random.NextNumber(new ChiSquare {DegreesOfFreedom = this.DegreesOfFreedom}, token);
return normal / Math.Sqrt(chiSquare / this.DegreesOfFreedom);
}
}
}

View File

@ -0,0 +1,47 @@
using System;
using System.Threading;
using System.Threading.Tasks;
namespace FastRng.Double.Distributions
{
public sealed class Weibull : IDistribution
{
private double shape = 1.0;
private double scale = 1.0;
public IRandom Random { get; set; }
public double Shape
{
get => this.shape;
set
{
if(value <= 0.0)
throw new ArgumentOutOfRangeException(message: "Shape must be greater than 0", null);
this.shape = value;
}
}
public double Scale
{
get => this.scale;
set
{
if(value <= 0.0)
throw new ArgumentOutOfRangeException(message: "Scale must be greater than 0", null);
this.scale = value;
}
}
public async ValueTask<double> GetDistributedValue(CancellationToken token)
{
if (this.Random == null)
return System.Double.NaN;
var value = await this.Random.GetUniform(token);
return this.Scale * Math.Pow(-Math.Log(value), 1.0 / this.Shape);
}
}
}