diff --git a/FastRng/Double/Distributions/Distribution.cs b/FastRng/Double/Distributions/Distribution.cs index ad58d5a..80c5c67 100644 --- a/FastRng/Double/Distributions/Distribution.cs +++ b/FastRng/Double/Distributions/Distribution.cs @@ -65,5 +65,11 @@ namespace FastRng.Double.Distributions } public async ValueTask NextNumber(CancellationToken cancel = default) => await this.NextNumber(0.0, 1.0, cancel); + + public async ValueTask HasDecisionBeenMade(double above, double below = 1, CancellationToken cancel = default) + { + var number = await this.NextNumber(cancel); + return number > above && number < below; + } } } \ No newline at end of file diff --git a/FastRng/Double/Distributions/IDistribution.cs b/FastRng/Double/Distributions/IDistribution.cs index 7794497..7338e00 100644 --- a/FastRng/Double/Distributions/IDistribution.cs +++ b/FastRng/Double/Distributions/IDistribution.cs @@ -14,5 +14,7 @@ namespace FastRng.Double.Distributions public ValueTask NextNumber(double rangeStart, double rangeEnd, CancellationToken cancel = default); public ValueTask NextNumber(CancellationToken cancel = default); + + public ValueTask HasDecisionBeenMade(double above, double below = 1.0, CancellationToken cancel = default); } } \ No newline at end of file diff --git a/FastRng/Double/Distributions/Uniform.cs b/FastRng/Double/Distributions/Uniform.cs index 073dbfa..31259f7 100644 --- a/FastRng/Double/Distributions/Uniform.cs +++ b/FastRng/Double/Distributions/Uniform.cs @@ -61,5 +61,11 @@ namespace FastRng.Double.Distributions } public async ValueTask NextNumber(CancellationToken cancel = default) => await this.NextNumber(0.0, 1.0, cancel); + + public async ValueTask HasDecisionBeenMade(double above, double below = 1, CancellationToken cancel = default) + { + var number = await this.NextNumber(cancel); + return number > above && number < below; + } } } \ No newline at end of file diff --git a/FastRng/Float/Distributions/Distribution.cs b/FastRng/Float/Distributions/Distribution.cs index ded9a51..4fec032 100644 --- a/FastRng/Float/Distributions/Distribution.cs +++ b/FastRng/Float/Distributions/Distribution.cs @@ -65,5 +65,11 @@ namespace FastRng.Float.Distributions } public async ValueTask NextNumber(CancellationToken cancel = default) => await this.NextNumber(0.0f, 1.0f, cancel); + + public async ValueTask HasDecisionBeenMade(float above, float below = 1, CancellationToken cancel = default) + { + var number = await this.NextNumber(cancel); + return number > above && number < below; + } } } \ No newline at end of file diff --git a/FastRng/Float/Distributions/IDistribution.cs b/FastRng/Float/Distributions/IDistribution.cs index 7381870..150080e 100644 --- a/FastRng/Float/Distributions/IDistribution.cs +++ b/FastRng/Float/Distributions/IDistribution.cs @@ -14,5 +14,7 @@ namespace FastRng.Float.Distributions public ValueTask NextNumber(float rangeStart, float rangeEnd, CancellationToken cancel = default); public ValueTask NextNumber(CancellationToken cancel = default); + + public ValueTask HasDecisionBeenMade(float above, float below = 1.0f, CancellationToken cancel = default); } } \ No newline at end of file diff --git a/FastRng/Float/Distributions/Uniform.cs b/FastRng/Float/Distributions/Uniform.cs index 13650f7..8149f6e 100644 --- a/FastRng/Float/Distributions/Uniform.cs +++ b/FastRng/Float/Distributions/Uniform.cs @@ -61,5 +61,11 @@ namespace FastRng.Float.Distributions } public async ValueTask NextNumber(CancellationToken cancel = default) => await this.NextNumber(0.0f, 1.0f, cancel); + + public async ValueTask HasDecisionBeenMade(float above, float below = 1, CancellationToken cancel = default) + { + var number = await this.NextNumber(cancel); + return number > above && number < below; + } } } \ No newline at end of file diff --git a/FastRngTests/Double/DecisionTester.cs b/FastRngTests/Double/DecisionTester.cs new file mode 100644 index 0000000..d4a4ef8 --- /dev/null +++ b/FastRngTests/Double/DecisionTester.cs @@ -0,0 +1,62 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Threading.Tasks; +using FastRng.Double; +using NUnit.Framework; +using Uniform = FastRng.Double.Distributions.Uniform; + +namespace FastRngTests.Double +{ + [ExcludeFromCodeCoverage] + public class DecisionTester + { + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public async Task DecisionUniform01() + { + using var rng = new MultiThreadedRng(); + var dist = new Uniform(rng); + + 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++; + + 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)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public async Task DecisionWeibull01() + { + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Double.Distributions.WeibullK05La1(rng); + + 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++; + + 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)); + } + } +} \ No newline at end of file diff --git a/FastRngTests/Float/DecisionTester.cs b/FastRngTests/Float/DecisionTester.cs new file mode 100644 index 0000000..88001b5 --- /dev/null +++ b/FastRngTests/Float/DecisionTester.cs @@ -0,0 +1,64 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Threading.Tasks; +using FastRng.Float; +using FastRng.Float.Distributions; +using FastRngTests.Float.Distributions; +using NUnit.Framework; +using Uniform = FastRng.Float.Distributions.Uniform; + +namespace FastRngTests.Float +{ + [ExcludeFromCodeCoverage] + public class DecisionTester + { + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public async Task DecisionUniform01() + { + using var rng = new MultiThreadedRng(); + var dist = new Uniform(rng); + + 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++; + + 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)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public async Task DecisionWeibull01() + { + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Float.Distributions.WeibullK05La1(rng); + + 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++; + + 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)); + } + } +} \ No newline at end of file