diff --git a/FastRng/Double/Distributions/InverseExponentialLa10.cs b/FastRng/Double/Distributions/InverseExponentialLa10.cs new file mode 100644 index 0000000..98b8d3e --- /dev/null +++ b/FastRng/Double/Distributions/InverseExponentialLa10.cs @@ -0,0 +1,35 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace FastRng.Double.Distributions +{ + public sealed class InverseExponentialLa10 : IDistribution + { + private const double LAMBDA = 10.0; + private const double CONSTANT = 4.539992976248453e-06; + + private ShapeFitter fitter; + private IRandom random; + + public IRandom Random + { + get => this.random; + set + { + this.random = value; + this.fitter = new ShapeFitter(InverseExponentialLa10.ShapeFunction, this.random, 100); + } + } + + private static double ShapeFunction(double x) => CONSTANT * LAMBDA * Math.Exp(LAMBDA * x); + + public async ValueTask GetDistributedValue(CancellationToken token = default) + { + if (this.Random == null) + return double.NaN; + + return await this.fitter.NextNumber(token); + } + } +} \ No newline at end of file diff --git a/FastRng/Double/Distributions/InverseExponentialLa5.cs b/FastRng/Double/Distributions/InverseExponentialLa5.cs new file mode 100644 index 0000000..0318d3f --- /dev/null +++ b/FastRng/Double/Distributions/InverseExponentialLa5.cs @@ -0,0 +1,35 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace FastRng.Double.Distributions +{ + public sealed class InverseExponentialLa5 : IDistribution + { + private const double LAMBDA = 5.0; + private const double CONSTANT = 0.001347589399817; + + private ShapeFitter fitter; + private IRandom random; + + public IRandom Random + { + get => this.random; + set + { + this.random = value; + this.fitter = new ShapeFitter(InverseExponentialLa5.ShapeFunction, this.random, 100); + } + } + + private static double ShapeFunction(double x) => CONSTANT * LAMBDA * Math.Exp(LAMBDA * x); + + public async ValueTask GetDistributedValue(CancellationToken token = default) + { + if (this.Random == null) + return double.NaN; + + return await this.fitter.NextNumber(token); + } + } +} \ No newline at end of file diff --git a/FastRngTests/Double/Distributions/InverseExponentialLa10.cs b/FastRngTests/Double/Distributions/InverseExponentialLa10.cs new file mode 100644 index 0000000..791ac1d --- /dev/null +++ b/FastRngTests/Double/Distributions/InverseExponentialLa10.cs @@ -0,0 +1,104 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Threading.Tasks; +using FastRng.Double; +using NUnit.Framework; + +namespace FastRngTests.Double.Distributions +{ + [ExcludeFromCodeCoverage] + public class InverseExponentialLa10 + { + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public async Task TestExponentialDistribution01() + { + var dist = new FastRng.Double.Distributions.InverseExponentialLa10(); + var fqa = new FrequencyAnalysis(); + var rng = new MultiThreadedRng(); + + for (var n = 0; n < 100_000; n++) + fqa.CountThis(await rng.NextNumber(dist)); + + rng.StopProducer(); + var result = fqa.NormalizeAndPlotEvents(TestContext.WriteLine); + + Assert.That(result[0], Is.EqualTo(0.0000501746820562).Within(0.0003)); + Assert.That(result[1], Is.EqualTo(0.0000554515994322).Within(0.0003)); + Assert.That(result[2], Is.EqualTo(0.0000612834950532).Within(0.0003)); + + Assert.That(result[21], Is.EqualTo(0.00040973497898).Within(0.00045)); + Assert.That(result[22], Is.EqualTo(0.000452827182887).Within(0.00050)); + Assert.That(result[23], Is.EqualTo(0.000500451433441).Within(0.00051)); + + Assert.That(result[50], Is.EqualTo(0.007446583070924).Within(0.002)); + + Assert.That(result[75], Is.EqualTo(0.090717953289412).Within(0.02)); + Assert.That(result[85], Is.EqualTo(0.246596963941606).Within(0.05)); + Assert.That(result[90], Is.EqualTo(0.406569659740598).Within(0.08)); + + Assert.That(result[97], Is.EqualTo(0.81873075307798).Within(0.08)); + Assert.That(result[98], Is.EqualTo(0.904837418035957).Within(0.08)); + Assert.That(result[99], Is.EqualTo(0.999999999999999).Within(0.08)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public async Task TestExponentialGeneratorWithRange01() + { + var dist = new FastRng.Double.Distributions.InverseExponentialLa10(); + var rng = new MultiThreadedRng(); + var samples = new double[1_000]; + for (var n = 0; n < samples.Length; n++) + samples[n] = await rng.NextNumber(-1.0, 1.0, dist); + + rng.StopProducer(); + Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0), "Min out of range"); + Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0), "Max out of range"); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public async Task TestExponentialGeneratorWithRange02() + { + var dist = new FastRng.Double.Distributions.InverseExponentialLa10(); + var rng = new MultiThreadedRng(); + var samples = new double[1_000]; + for (var n = 0; n < samples.Length; n++) + samples[n] = await rng.NextNumber(0.0, 1.0, dist); + + rng.StopProducer(); + Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0), "Min is out of range"); + Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0), "Max is out of range"); + } + + [Test] [Category(TestCategories.COVER)] [Category(TestCategories.NORMAL)] + public async Task TestExponentialGeneratorWithRange03() + { + var rng = new MultiThreadedRng(); + var dist = new FastRng.Double.Distributions.InverseExponentialLa10 { Random = rng }; // Test default parameters + + var samples = new double[1_000]; + for (var n = 0; n < samples.Length; n++) + samples[n] = await dist.GetDistributedValue(); + + rng.StopProducer(); + Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0), "Min is out of range"); + Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0), "Max is out of range"); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public async Task NoRandomNumberGenerator01() + { + var dist = new FastRng.Double.Distributions.InverseExponentialLa10(); + Assert.DoesNotThrowAsync(async () => await dist.GetDistributedValue()); + Assert.That(await dist.GetDistributedValue(), Is.NaN); + } + } +} \ No newline at end of file diff --git a/FastRngTests/Double/Distributions/InverseExponentialLa5.cs b/FastRngTests/Double/Distributions/InverseExponentialLa5.cs new file mode 100644 index 0000000..c894f9d --- /dev/null +++ b/FastRngTests/Double/Distributions/InverseExponentialLa5.cs @@ -0,0 +1,104 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Threading.Tasks; +using FastRng.Double; +using NUnit.Framework; + +namespace FastRngTests.Double.Distributions +{ + [ExcludeFromCodeCoverage] + public class InverseExponentialLa5 + { + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public async Task TestExponentialDistribution01() + { + var dist = new FastRng.Double.Distributions.InverseExponentialLa5(); + var fqa = new FrequencyAnalysis(); + var rng = new MultiThreadedRng(); + + for (var n = 0; n < 100_000; n++) + fqa.CountThis(await rng.NextNumber(dist)); + + rng.StopProducer(); + var result = fqa.NormalizeAndPlotEvents(TestContext.WriteLine); + + Assert.That(result[0], Is.EqualTo(0.007083408929052).Within(0.008)); + Assert.That(result[1], Is.EqualTo(0.007446583070924).Within(0.008)); + Assert.That(result[2], Is.EqualTo(0.007828377549226).Within(0.008)); + + Assert.That(result[21], Is.EqualTo(0.020241911445804).Within(0.05)); + Assert.That(result[22], Is.EqualTo(0.021279736438377).Within(0.05)); + Assert.That(result[23], Is.EqualTo(0.022370771856166).Within(0.05)); + + Assert.That(result[50], Is.EqualTo(0.08629358649937).Within(0.02)); + + Assert.That(result[75], Is.EqualTo(0.301194211912202).Within(0.03)); + Assert.That(result[85], Is.EqualTo(0.496585303791409).Within(0.05)); + Assert.That(result[90], Is.EqualTo(0.637628151621772).Within(0.06)); + + Assert.That(result[97], Is.EqualTo(0.904837418035959).Within(0.08)); + Assert.That(result[98], Is.EqualTo(0.951229424500713).Within(0.08)); + Assert.That(result[99], Is.EqualTo(1).Within(0.08)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public async Task TestExponentialGeneratorWithRange01() + { + var dist = new FastRng.Double.Distributions.InverseExponentialLa5(); + var rng = new MultiThreadedRng(); + var samples = new double[1_000]; + for (var n = 0; n < samples.Length; n++) + samples[n] = await rng.NextNumber(-1.0, 1.0, dist); + + rng.StopProducer(); + Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0), "Min out of range"); + Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0), "Max out of range"); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public async Task TestExponentialGeneratorWithRange02() + { + var dist = new FastRng.Double.Distributions.InverseExponentialLa5(); + var rng = new MultiThreadedRng(); + var samples = new double[1_000]; + for (var n = 0; n < samples.Length; n++) + samples[n] = await rng.NextNumber(0.0, 1.0, dist); + + rng.StopProducer(); + Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0), "Min is out of range"); + Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0), "Max is out of range"); + } + + [Test] [Category(TestCategories.COVER)] [Category(TestCategories.NORMAL)] + public async Task TestExponentialGeneratorWithRange03() + { + var rng = new MultiThreadedRng(); + var dist = new FastRng.Double.Distributions.InverseExponentialLa5 { Random = rng }; // Test default parameters + + var samples = new double[1_000]; + for (var n = 0; n < samples.Length; n++) + samples[n] = await dist.GetDistributedValue(); + + rng.StopProducer(); + Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0), "Min is out of range"); + Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0), "Max is out of range"); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public async Task NoRandomNumberGenerator01() + { + var dist = new FastRng.Double.Distributions.InverseExponentialLa5(); + Assert.DoesNotThrowAsync(async () => await dist.GetDistributedValue()); + Assert.That(await dist.GetDistributedValue(), Is.NaN); + } + } +} \ No newline at end of file