diff --git a/FastRng/Double/Distributions/BetaA2B5.cs b/FastRng/Double/Distributions/BetaA2B5.cs new file mode 100644 index 0000000..3f5febd --- /dev/null +++ b/FastRng/Double/Distributions/BetaA2B5.cs @@ -0,0 +1,40 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace FastRng.Double.Distributions +{ + public sealed class BetaA2B5 : IDistribution + { + private const double ALPHA = 2; + private const double BETA = 5; + private const double CONSTANT = 12.2; + + private ShapeFitter fitter; + private IRandom random; + + public BetaA2B5() + { + } + + public IRandom Random + { + get => this.random; + set + { + this.random = value; + this.fitter = new ShapeFitter(BetaA2B5.ShapeFunction, this.random, 100); + } + } + + private static double ShapeFunction(double x) => CONSTANT * Math.Pow(x, ALPHA - 1) * Math.Pow(1 - x, BETA - 1); + + 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/BetaA5B2.cs b/FastRng/Double/Distributions/BetaA5B2.cs new file mode 100644 index 0000000..df3d6d9 --- /dev/null +++ b/FastRng/Double/Distributions/BetaA5B2.cs @@ -0,0 +1,40 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace FastRng.Double.Distributions +{ + public sealed class BetaA5B2 : IDistribution + { + private const double ALPHA = 5; + private const double BETA = 2; + private const double CONSTANT = 12.2; + + private ShapeFitter fitter; + private IRandom random; + + public BetaA5B2() + { + } + + public IRandom Random + { + get => this.random; + set + { + this.random = value; + this.fitter = new ShapeFitter(BetaA5B2.ShapeFunction, this.random, 100); + } + } + + private static double ShapeFunction(double x) => CONSTANT * Math.Pow(x, ALPHA - 1) * Math.Pow(1 - x, BETA - 1); + + 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/BetaA2B5.cs b/FastRngTests/Double/Distributions/BetaA2B5.cs new file mode 100644 index 0000000..9df1ddd --- /dev/null +++ b/FastRngTests/Double/Distributions/BetaA2B5.cs @@ -0,0 +1,47 @@ +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 BetaA2B5 + { + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public async Task TestBetaDistribution01() + { + var dist = new FastRng.Double.Distributions.BetaA2B5(); + 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.11719271).Within(0.3)); + Assert.That(result[1], Is.EqualTo(0.22505783).Within(0.3)); + Assert.That(result[2], Is.EqualTo(0.32401717).Within(0.3)); + + Assert.That(result[21], Is.EqualTo(0.99348410).Within(0.3)); + Assert.That(result[22], Is.EqualTo(0.98639433).Within(0.3)); + Assert.That(result[23], Is.EqualTo(0.97684451).Within(0.3)); + + Assert.That(result[50], Is.EqualTo(0.35868592).Within(0.3)); + + Assert.That(result[75], Is.EqualTo(0.03076227).Within(0.03)); + Assert.That(result[85], Is.EqualTo(0.00403061).Within(0.03)); + Assert.That(result[90], Is.EqualTo(0.00109800).Within(0.01)); + + Assert.That(result[97], Is.EqualTo(0.00000191).Within(0.000003)); + Assert.That(result[98], Is.EqualTo(0.00000012).Within(0.0000003)); + Assert.That(result[99], Is.EqualTo(0.00000000).Within(0.0000003)); + } + } +} \ No newline at end of file diff --git a/FastRngTests/Double/Distributions/BetaA5B2.cs b/FastRngTests/Double/Distributions/BetaA5B2.cs new file mode 100644 index 0000000..a29c6d3 --- /dev/null +++ b/FastRngTests/Double/Distributions/BetaA5B2.cs @@ -0,0 +1,47 @@ +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 BetaA5B2 + { + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public async Task TestBetaDistribution01() + { + var dist = new FastRng.Double.Distributions.BetaA5B2(); + 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.0000001).Within(0.0000003)); + Assert.That(result[1], Is.EqualTo(0.0000019).Within(0.0000020)); + Assert.That(result[2], Is.EqualTo(0.0000096).Within(0.0000100)); + + Assert.That(result[21], Is.EqualTo(0.0222918).Within(0.03)); + Assert.That(result[22], Is.EqualTo(0.0262883).Within(0.03)); + Assert.That(result[23], Is.EqualTo(0.0307623).Within(0.03)); + + Assert.That(result[50], Is.EqualTo(0.4044237).Within(0.2)); + + Assert.That(result[75], Is.EqualTo(0.9768445).Within(0.03)); + Assert.That(result[85], Is.EqualTo(0.9552714).Within(0.05)); + Assert.That(result[90], Is.EqualTo(0.8004420).Within(0.15)); + + Assert.That(result[97], Is.EqualTo(0.2250578).Within(0.03)); + Assert.That(result[98], Is.EqualTo(0.1171927).Within(0.03)); + Assert.That(result[99], Is.EqualTo(0.0000000).Within(0.00)); + } + } +} \ No newline at end of file