diff --git a/.idea/.idea.FastRng/.idea/indexLayout.xml b/.idea/.idea.FastRng/.idea/indexLayout.xml index 27ba142..7b08163 100644 --- a/.idea/.idea.FastRng/.idea/indexLayout.xml +++ b/.idea/.idea.FastRng/.idea/indexLayout.xml @@ -1,6 +1,6 @@ - + diff --git a/.idea/.idea.FastRng/.idea/modules.xml b/.idea/.idea.FastRng/.idea/modules.xml deleted file mode 100644 index 9886bfb..0000000 --- a/.idea/.idea.FastRng/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/.idea.FastRng/riderModule.iml b/.idea/.idea.FastRng/riderModule.iml deleted file mode 100644 index 665b347..0000000 --- a/.idea/.idea.FastRng/riderModule.iml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/FastRng/Distributions/BetaA2B2.cs b/FastRng/Distributions/BetaA2B2.cs new file mode 100644 index 0000000..81e9564 --- /dev/null +++ b/FastRng/Distributions/BetaA2B2.cs @@ -0,0 +1,16 @@ +using System.Numerics; + +namespace FastRng.Distributions; + +public sealed class BetaA2B2 : Distribution where TNum : IFloatingPointIeee754 +{ + private static readonly TNum ALPHA = TNum.One + TNum.One; + private static readonly TNum BETA = TNum.One + TNum.One; + private static readonly TNum CONSTANT = TNum.CreateChecked(4); + + public BetaA2B2(IRandom rng) : base(rng) + { + } + + private protected override TNum ShapeFunction(TNum x) => CONSTANT * TNum.Pow(x, ALPHA - TNum.One) * TNum.Pow(TNum.One - x, BETA - TNum.One); +} \ No newline at end of file diff --git a/FastRng/Distributions/BetaA2B5.cs b/FastRng/Distributions/BetaA2B5.cs new file mode 100644 index 0000000..77b7315 --- /dev/null +++ b/FastRng/Distributions/BetaA2B5.cs @@ -0,0 +1,16 @@ +using System.Numerics; + +namespace FastRng.Distributions; + +public sealed class BetaA2B5 : Distribution where TNum : IFloatingPointIeee754 +{ + private static readonly TNum ALPHA = TNum.One + TNum.One; + private static readonly TNum BETA = TNum.CreateChecked(5); + private static readonly TNum CONSTANT = TNum.CreateChecked(12.2f); + + public BetaA2B5(IRandom rng) : base(rng) + { + } + + private protected override TNum ShapeFunction(TNum x) => CONSTANT * TNum.Pow(x, ALPHA - TNum.One) * TNum.Pow(TNum.One - x, BETA - TNum.One); +} \ No newline at end of file diff --git a/FastRng/Distributions/BetaA5B2.cs b/FastRng/Distributions/BetaA5B2.cs new file mode 100644 index 0000000..f9af4f1 --- /dev/null +++ b/FastRng/Distributions/BetaA5B2.cs @@ -0,0 +1,16 @@ +using System.Numerics; + +namespace FastRng.Distributions; + +public sealed class BetaA5B2 : Distribution where TNum : IFloatingPointIeee754 +{ + private static readonly TNum ALPHA = TNum.CreateChecked(5f); + private static readonly TNum BETA = TNum.One + TNum.One; + private static readonly TNum CONSTANT = TNum.CreateChecked(12.2f); + + public BetaA5B2(IRandom rng) : base(rng) + { + } + + private protected override TNum ShapeFunction(TNum x) => CONSTANT * TNum.Pow(x, ALPHA - TNum.One) * TNum.Pow(TNum.One - x, BETA - TNum.One); +} \ No newline at end of file diff --git a/FastRng/Distributions/CauchyLorentzX0.cs b/FastRng/Distributions/CauchyLorentzX0.cs new file mode 100644 index 0000000..52fc302 --- /dev/null +++ b/FastRng/Distributions/CauchyLorentzX0.cs @@ -0,0 +1,17 @@ +using System.Numerics; + +namespace FastRng.Distributions; + +public sealed class CauchyLorentzX0 : Distribution where TNum : IFloatingPointIeee754 +{ + private static readonly TNum CONSTANT = TNum.CreateChecked(0.31f); + private static readonly TNum SCALE = TNum.CreateChecked(0.1f); + private static readonly TNum MEDIAN = TNum.Zero; + private static readonly TNum TWO = TNum.CreateChecked(2f); + + public CauchyLorentzX0(IRandom rng) : base(rng) + { + } + + private protected override TNum ShapeFunction(TNum x) => CONSTANT * ( TNum.One / (TNum.Pi * SCALE)) * ((SCALE * SCALE) / (TNum.Pow(x - MEDIAN, TWO) + (SCALE * SCALE))); +} \ No newline at end of file diff --git a/FastRng/Distributions/CauchyLorentzX1.cs b/FastRng/Distributions/CauchyLorentzX1.cs new file mode 100644 index 0000000..bda6296 --- /dev/null +++ b/FastRng/Distributions/CauchyLorentzX1.cs @@ -0,0 +1,17 @@ +using System.Numerics; + +namespace FastRng.Distributions; + +public sealed class CauchyLorentzX1 : Distribution where TNum : IFloatingPointIeee754 +{ + private static readonly TNum CONSTANT = TNum.CreateChecked(0.31f); + private static readonly TNum SCALE = TNum.CreateChecked(0.1f); + private static readonly TNum MEDIAN = TNum.One; + private static readonly TNum TWO = TNum.CreateChecked(2f); + + public CauchyLorentzX1(IRandom rng) : base(rng) + { + } + + private protected override TNum ShapeFunction(TNum x) => CONSTANT * (TNum.One / (TNum.Pi * SCALE)) * ((SCALE * SCALE) / (TNum.Pow(x - MEDIAN, TWO) + (SCALE * SCALE))); +} \ No newline at end of file diff --git a/FastRng/Distributions/ChiSquareK1.cs b/FastRng/Distributions/ChiSquareK1.cs new file mode 100644 index 0000000..8857f0e --- /dev/null +++ b/FastRng/Distributions/ChiSquareK1.cs @@ -0,0 +1,28 @@ +using System.Numerics; + +namespace FastRng.Distributions; + +public sealed class ChiSquareK1 : Distribution where TNum : IFloatingPointIeee754 +{ + private static readonly TNum HALF = TNum.CreateChecked(0.5f); + private static readonly TNum TWO = TNum.CreateChecked(2f); + private static readonly TNum K = TNum.One; + private static readonly TNum K_HALF = K * HALF; + private static readonly TNum K_HALF_MINUS_ONE = K_HALF - TNum.One; + private static readonly TNum CONSTANT = TNum.CreateChecked(0.252f); + + private static readonly TNum DIVISOR; + + static ChiSquareK1() + { + var twoToTheKHalf = TNum.Pow(TWO, K_HALF); + var gammaKHalf = MathToolsFloatingPoint.Gamma(K_HALF); + DIVISOR = twoToTheKHalf * gammaKHalf; + } + + public ChiSquareK1(IRandom rng) : base(rng) + { + } + + private protected override TNum ShapeFunction(TNum x) => CONSTANT * ((TNum.Pow(x, K_HALF_MINUS_ONE) * TNum.Exp(-x * HALF)) / DIVISOR); +} \ No newline at end of file diff --git a/FastRng/Distributions/ChiSquareK10.cs b/FastRng/Distributions/ChiSquareK10.cs new file mode 100644 index 0000000..155ad9b --- /dev/null +++ b/FastRng/Distributions/ChiSquareK10.cs @@ -0,0 +1,28 @@ +using System.Numerics; + +namespace FastRng.Distributions; + +public sealed class ChiSquareK10 : Distribution where TNum : IFloatingPointIeee754 +{ + private static readonly TNum HALF = TNum.CreateChecked(0.5f); + private static readonly TNum TWO = TNum.CreateChecked(2f); + private static readonly TNum K = TNum.CreateChecked(10.0f); + private static readonly TNum K_HALF = K * HALF; + private static readonly TNum K_HALF_MINUS_ONE = K_HALF - TNum.One; + private static readonly TNum CONSTANT = TNum.CreateChecked(0.252f); + + private static readonly TNum DIVISOR; + + static ChiSquareK10() + { + var twoToTheKHalf = TNum.Pow(TWO, K_HALF); + var gammaKHalf = MathToolsFloatingPoint.Gamma(K_HALF); + DIVISOR = twoToTheKHalf * gammaKHalf; + } + + public ChiSquareK10(IRandom rng) : base(rng) + { + } + + private protected override TNum ShapeFunction(TNum x) => CONSTANT * ((TNum.Pow(x, K_HALF_MINUS_ONE) * TNum.Exp(-x * HALF)) / DIVISOR); +} \ No newline at end of file diff --git a/FastRng/Distributions/ChiSquareK4.cs b/FastRng/Distributions/ChiSquareK4.cs new file mode 100644 index 0000000..a514063 --- /dev/null +++ b/FastRng/Distributions/ChiSquareK4.cs @@ -0,0 +1,28 @@ +using System.Numerics; + +namespace FastRng.Distributions; + +public sealed class ChiSquareK4 : Distribution where TNum : IFloatingPointIeee754 +{ + private static readonly TNum HALF = TNum.CreateChecked(0.5f); + private static readonly TNum TWO = TNum.CreateChecked(2f); + private static readonly TNum K = TNum.CreateChecked(4f); + private static readonly TNum K_HALF = K * HALF; + private static readonly TNum K_HALF_MINUS_ONE = K_HALF - TNum.One; + private static readonly TNum CONSTANT = TNum.CreateChecked(0.252f); + + private static readonly TNum DIVISOR; + + static ChiSquareK4() + { + var twoToTheKHalf = TNum.Pow(TWO, K_HALF); + var gammaKHalf = MathToolsFloatingPoint.Gamma(K_HALF); + DIVISOR = twoToTheKHalf * gammaKHalf; + } + + public ChiSquareK4(IRandom rng) : base(rng) + { + } + + private protected override TNum ShapeFunction(TNum x) => CONSTANT * ((TNum.Pow(x, K_HALF_MINUS_ONE) * TNum.Exp(-x * HALF)) / DIVISOR); +} \ No newline at end of file diff --git a/FastRng/Distributions/Distribution.cs b/FastRng/Distributions/Distribution.cs new file mode 100644 index 0000000..2844cf1 --- /dev/null +++ b/FastRng/Distributions/Distribution.cs @@ -0,0 +1,63 @@ +using System; +using System.Numerics; +using System.Threading; + +namespace FastRng.Distributions; + +public abstract class Distribution : IDistribution where TNum : IFloatingPointIeee754 +{ + private readonly ShapeFitter fitter; + + protected Distribution(IRandom rng) + { + if (rng == null) + throw new ArgumentNullException(nameof(rng), "An IRandom implementation is needed."); + + this.fitter = new ShapeFitter(this.ShapeFunction, rng, 100); + } + + private protected abstract TNum ShapeFunction(TNum x); + + public TNum GetDistributedValue(CancellationToken token = default) => this.fitter.NextNumber(token); + + public uint NextNumber(uint rangeStart, uint rangeEnd, CancellationToken cancel = default) + { + // Swap the values if the range start is greater than the range end: + if (rangeStart > rangeEnd) + (rangeStart, rangeEnd) = (rangeEnd, rangeStart); + + var range = rangeEnd - rangeStart; + var distributedValue = this.GetDistributedValue(cancel); + return (uint) ((float.CreateChecked(distributedValue) * range) + rangeStart); + } + + public ulong NextNumber(ulong rangeStart, ulong rangeEnd, CancellationToken cancel = default) + { + // Swap the values if the range start is greater than the range end: + if (rangeStart > rangeEnd) + (rangeStart, rangeEnd) = (rangeEnd, rangeStart); + + var range = rangeEnd - rangeStart; + var distributedValue = this.GetDistributedValue(cancel); + return (ulong) ((double.CreateChecked(distributedValue) * range) + rangeStart); + } + + public TNum NextNumber(TNum rangeStart, TNum rangeEnd, CancellationToken cancel = default) + { + // Swap the values if the range start is greater than the range end: + if (rangeStart > rangeEnd) + (rangeStart, rangeEnd) = (rangeEnd, rangeStart); + + var range = rangeEnd - rangeStart; + var distributedValue = this.GetDistributedValue(cancel); + return (distributedValue * range) + rangeStart; + } + + public TNum NextNumber(CancellationToken cancel = default) => this.NextNumber(TNum.Zero, TNum.One, cancel); + + public bool HasDecisionBeenMade(TNum above, TNum below, CancellationToken cancel = default) + { + var number = this.NextNumber(cancel); + return number > above && number < below; + } +} \ No newline at end of file diff --git a/FastRng/Distributions/ExponentialLa10.cs b/FastRng/Distributions/ExponentialLa10.cs new file mode 100644 index 0000000..8002bcc --- /dev/null +++ b/FastRng/Distributions/ExponentialLa10.cs @@ -0,0 +1,15 @@ +using System.Numerics; + +namespace FastRng.Distributions; + +public sealed class ExponentialLa10 : Distribution where TNum : IFloatingPointIeee754 +{ + private static readonly TNum LAMBDA = TNum.CreateChecked(10.0f); + private static readonly TNum CONSTANT = TNum.CreateChecked(0.1106f); + + public ExponentialLa10(IRandom rng) : base(rng) + { + } + + private protected override TNum ShapeFunction(TNum x) => CONSTANT * LAMBDA * TNum.Exp(-LAMBDA * x); +} \ No newline at end of file diff --git a/FastRng/Distributions/ExponentialLa5.cs b/FastRng/Distributions/ExponentialLa5.cs new file mode 100644 index 0000000..c48eb2c --- /dev/null +++ b/FastRng/Distributions/ExponentialLa5.cs @@ -0,0 +1,15 @@ +using System.Numerics; + +namespace FastRng.Distributions; + +public sealed class ExponentialLa5 : Distribution where TNum : IFloatingPointIeee754 +{ + private static readonly TNum LAMBDA = TNum.CreateChecked(5.0f); + private static readonly TNum CONSTANT = TNum.CreateChecked(0.2103f); + + public ExponentialLa5(IRandom rng) : base(rng) + { + } + + private protected override TNum ShapeFunction(TNum x) => CONSTANT * LAMBDA * TNum.Exp(-LAMBDA * x); +} \ No newline at end of file diff --git a/FastRng/Distributions/GammaA5B15.cs b/FastRng/Distributions/GammaA5B15.cs new file mode 100644 index 0000000..1aa509e --- /dev/null +++ b/FastRng/Distributions/GammaA5B15.cs @@ -0,0 +1,25 @@ +using System.Numerics; + +namespace FastRng.Distributions; + +public sealed class GammaA5B15 : Distribution where TNum : IFloatingPointIeee754 +{ + private static readonly TNum ALPHA = TNum.CreateChecked(5.0f); + private static readonly TNum BETA = TNum.CreateChecked(15.0f); + private static readonly TNum CONSTANT = TNum.CreateChecked(0.341344210715475f); + + private static readonly TNum GAMMA_ALPHA; + private static readonly TNum BETA_TO_THE_ALPHA; + + static GammaA5B15() + { + GAMMA_ALPHA = MathToolsFloatingPoint.Gamma(ALPHA); + BETA_TO_THE_ALPHA = TNum.Pow(BETA, ALPHA); + } + + public GammaA5B15(IRandom rng) : base(rng) + { + } + + private protected override TNum ShapeFunction(TNum x) => CONSTANT * ((BETA_TO_THE_ALPHA * TNum.Pow(x, ALPHA - TNum.One) * TNum.Exp(-BETA * x)) / GAMMA_ALPHA); +} \ No newline at end of file diff --git a/FastRng/Distributions/IDistribution.cs b/FastRng/Distributions/IDistribution.cs new file mode 100644 index 0000000..49b44db --- /dev/null +++ b/FastRng/Distributions/IDistribution.cs @@ -0,0 +1,19 @@ +using System.Numerics; +using System.Threading; + +namespace FastRng.Distributions; + +public interface IDistribution where TNum : IFloatingPointIeee754 +{ + public TNum GetDistributedValue(CancellationToken token = default); + + public uint NextNumber(uint rangeStart, uint rangeEnd, CancellationToken cancel = default); + + public ulong NextNumber(ulong rangeStart, ulong rangeEnd, CancellationToken cancel = default); + + public TNum NextNumber(TNum rangeStart, TNum rangeEnd, CancellationToken cancel = default); + + public TNum NextNumber(CancellationToken cancel = default); + + public bool HasDecisionBeenMade(TNum above, TNum below, CancellationToken cancel = default); +} \ No newline at end of file diff --git a/FastRng/Distributions/InverseExponentialLa10.cs b/FastRng/Distributions/InverseExponentialLa10.cs new file mode 100644 index 0000000..da6bc7d --- /dev/null +++ b/FastRng/Distributions/InverseExponentialLa10.cs @@ -0,0 +1,15 @@ +using System.Numerics; + +namespace FastRng.Distributions; + +public sealed class InverseExponentialLa10 : Distribution where TNum : IFloatingPointIeee754 +{ + private static readonly TNum LAMBDA = TNum.CreateChecked(10.0f); + private static readonly TNum CONSTANT = TNum.CreateChecked(4.539992976248453e-06f); + + public InverseExponentialLa10(IRandom rng) : base(rng) + { + } + + private protected override TNum ShapeFunction(TNum x) => CONSTANT * LAMBDA * TNum.Exp(LAMBDA * x); +} \ No newline at end of file diff --git a/FastRng/Distributions/InverseExponentialLa5.cs b/FastRng/Distributions/InverseExponentialLa5.cs new file mode 100644 index 0000000..817beef --- /dev/null +++ b/FastRng/Distributions/InverseExponentialLa5.cs @@ -0,0 +1,15 @@ +using System.Numerics; + +namespace FastRng.Distributions; + +public sealed class InverseExponentialLa5 : Distribution where TNum : IFloatingPointIeee754 +{ + private static readonly TNum LAMBDA = TNum.CreateChecked(5.0f); + private static readonly TNum CONSTANT = TNum.CreateChecked(0.001347589399817f); + + public InverseExponentialLa5(IRandom rng) : base(rng) + { + } + + private protected override TNum ShapeFunction(TNum x) => CONSTANT * LAMBDA * TNum.Exp(LAMBDA * x); +} \ No newline at end of file diff --git a/FastRng/Distributions/InverseGammaA3B05.cs b/FastRng/Distributions/InverseGammaA3B05.cs new file mode 100644 index 0000000..56465da --- /dev/null +++ b/FastRng/Distributions/InverseGammaA3B05.cs @@ -0,0 +1,26 @@ +using System.Numerics; + +namespace FastRng.Distributions; + +public sealed class InverseGammaA3B05 : Distribution where TNum : IFloatingPointIeee754 +{ + private static readonly TNum ALPHA = TNum.CreateChecked(3.0f); + private static readonly TNum BETA = TNum.CreateChecked(0.5f); + private static readonly TNum CONSTANT = TNum.CreateChecked(0.213922656884911f); + + private static readonly TNum FACTOR_LEFT; + + static InverseGammaA3B05() + { + var gammaAlpha = MathToolsFloatingPoint.Gamma(ALPHA); + var betaToTheAlpha = TNum.Pow(BETA, ALPHA); + + FACTOR_LEFT = CONSTANT * (betaToTheAlpha / gammaAlpha); + } + + public InverseGammaA3B05(IRandom rng) : base(rng) + { + } + + private protected override TNum ShapeFunction(TNum x) => FACTOR_LEFT * TNum.Pow(x, -ALPHA - TNum.One) * TNum.Exp(-BETA / x); +} \ No newline at end of file diff --git a/FastRng/Distributions/LaplaceB01M0.cs b/FastRng/Distributions/LaplaceB01M0.cs new file mode 100644 index 0000000..8e5dca7 --- /dev/null +++ b/FastRng/Distributions/LaplaceB01M0.cs @@ -0,0 +1,24 @@ +using System.Numerics; + +namespace FastRng.Distributions; + +public sealed class LaplaceB01M0 : Distribution where TNum : IFloatingPointIeee754 +{ + private static readonly TNum TWO = TNum.CreateChecked(2.0f); + private static readonly TNum B = TNum.CreateChecked(0.1f); + private static readonly TNum MU = TNum.Zero; + private static readonly TNum CONSTANT = TNum.CreateChecked(0.221034183615129f); + + private static readonly TNum FACTOR_LEFT; + + static LaplaceB01M0() + { + FACTOR_LEFT = CONSTANT / (TWO * B); + } + + public LaplaceB01M0(IRandom rng) : base(rng) + { + } + + private protected override TNum ShapeFunction(TNum x) => FACTOR_LEFT * TNum.Exp(-TNum.Abs(x - MU) / B); +} \ No newline at end of file diff --git a/FastRng/Distributions/LaplaceB01M05.cs b/FastRng/Distributions/LaplaceB01M05.cs new file mode 100644 index 0000000..5849316 --- /dev/null +++ b/FastRng/Distributions/LaplaceB01M05.cs @@ -0,0 +1,24 @@ +using System.Numerics; + +namespace FastRng.Distributions; + +public sealed class LaplaceB01M05 : Distribution where TNum : IFloatingPointIeee754 +{ + private static readonly TNum TWO = TNum.CreateChecked(2.0f); + private static readonly TNum B = TNum.CreateChecked(0.1f); + private static readonly TNum MU = TNum.CreateChecked(0.5f); + private static readonly TNum CONSTANT = TNum.CreateChecked(0.2f); + + private static readonly TNum FACTOR_LEFT; + + static LaplaceB01M05() + { + FACTOR_LEFT = CONSTANT / (TWO * B); + } + + public LaplaceB01M05(IRandom rng) : base(rng) + { + } + + private protected override TNum ShapeFunction(TNum x) => FACTOR_LEFT * TNum.Exp(-TNum.Abs(x - MU) / B); +} \ No newline at end of file diff --git a/FastRng/Distributions/LogNormalS1M0.cs b/FastRng/Distributions/LogNormalS1M0.cs new file mode 100644 index 0000000..1900ad4 --- /dev/null +++ b/FastRng/Distributions/LogNormalS1M0.cs @@ -0,0 +1,24 @@ +using System.Numerics; + +namespace FastRng.Distributions; + +public sealed class LogNormalS1M0 : Distribution where TNum : IFloatingPointIeee754 +{ + private static readonly TNum TWO = TNum.CreateChecked(2f); + private static readonly TNum SIGMA = TNum.One; + private static readonly TNum MU = TNum.Zero; + private static readonly TNum CONSTANT = TNum.CreateChecked(1.51998658387455f); + + private static readonly TNum FACTOR; + + static LogNormalS1M0() + { + FACTOR = SIGMA * TNum.Sqrt(TWO * TNum.Pi); + } + + public LogNormalS1M0(IRandom rng) : base(rng) + { + } + + private protected override TNum ShapeFunction(TNum x) => (CONSTANT / (x * FACTOR)) * TNum.Exp( -(TNum.Pow(TNum.Log(x) - MU, TWO) / (TWO * TNum.Pow(SIGMA, TWO)))); +} \ No newline at end of file diff --git a/FastRng/Distributions/NormalS02M05.cs b/FastRng/Distributions/NormalS02M05.cs new file mode 100644 index 0000000..93cf3c3 --- /dev/null +++ b/FastRng/Distributions/NormalS02M05.cs @@ -0,0 +1,18 @@ +using System.Numerics; + +namespace FastRng.Distributions; + +public sealed class NormalS02M05 : Distribution where TNum : IFloatingPointIeee754 +{ + private static readonly TNum TWO = TNum.CreateChecked(2f); + private static readonly TNum NEGATIVE_HALF = TNum.CreateChecked(-0.5f); + private static readonly TNum SQRT_2_PI = TNum.CreateChecked(2.506628275f); + private static readonly TNum STD_DEV = TNum.CreateChecked(0.2f); + private static readonly TNum MEAN = TNum.CreateChecked(0.5f); + + public NormalS02M05(IRandom rng) : base(rng) + { + } + + private protected override TNum ShapeFunction(TNum x) => TNum.One / (STD_DEV * SQRT_2_PI) * TNum.Exp(NEGATIVE_HALF * TNum.Pow((x - MEAN) / STD_DEV, TWO)); +} \ No newline at end of file diff --git a/FastRng/Distributions/StudentTNu1.cs b/FastRng/Distributions/StudentTNu1.cs new file mode 100644 index 0000000..b9706ae --- /dev/null +++ b/FastRng/Distributions/StudentTNu1.cs @@ -0,0 +1,30 @@ +using System.Numerics; + +namespace FastRng.Distributions; + +public sealed class StudentTNu1 : Distribution where TNum : IFloatingPointIeee754 +{ + private static readonly TNum HALF = TNum.CreateChecked(0.5f); + private static readonly TNum TWO = TNum.CreateChecked(2f); + private static readonly TNum NU = TNum.One; + private static readonly TNum START = TNum.Zero; + private static readonly TNum COMPRESS = TNum.One; + private static readonly TNum CONSTANT = TNum.CreateChecked(3.14190548592729f); + + private static readonly TNum DIVIDEND; + private static readonly TNum DIVISOR; + private static readonly TNum EXPONENT; + + static StudentTNu1() + { + DIVIDEND = MathToolsFloatingPoint.Gamma((NU + TNum.One) * HALF); + DIVISOR = TNum.Sqrt(NU * TNum.Pi) * MathToolsFloatingPoint.Gamma(NU * HALF); + EXPONENT = -((NU + TNum.One) * HALF); + } + + public StudentTNu1(IRandom rng) : base(rng) + { + } + + private protected override TNum ShapeFunction(TNum x) => CONSTANT * TNum.Pow((DIVIDEND / DIVISOR) * TNum.Pow( TNum.One + TNum.Pow(START + x * COMPRESS, TWO) / NU, EXPONENT), COMPRESS); +} \ No newline at end of file diff --git a/FastRng/Distributions/Uniform.cs b/FastRng/Distributions/Uniform.cs new file mode 100644 index 0000000..fb2e817 --- /dev/null +++ b/FastRng/Distributions/Uniform.cs @@ -0,0 +1,58 @@ +using System; +using System.Numerics; +using System.Threading; + +namespace FastRng.Distributions; + +public sealed class Uniform : IDistribution where TNum : IFloatingPointIeee754 +{ + private readonly IRandom rng; + + public Uniform(IRandom rng) + { + this.rng = rng ?? throw new ArgumentNullException(nameof(rng), "An IRandom implementation is needed."); + } + + public TNum GetDistributedValue(CancellationToken token = default) => this.rng.GetUniform(token); + + public uint NextNumber(uint rangeStart, uint rangeEnd, CancellationToken cancel = default) + { + // Swap the values if the range start is greater than the range end: + if (rangeStart > rangeEnd) + (rangeStart, rangeEnd) = (rangeEnd, rangeStart); + + var range = rangeEnd - rangeStart; + var distributedValue = this.GetDistributedValue(cancel); + return (uint) ((float.CreateChecked(distributedValue) * range) + rangeStart); + } + + public ulong NextNumber(ulong rangeStart, ulong rangeEnd, CancellationToken cancel = default) + { + // Swap the values if the range start is greater than the range end: + if (rangeStart > rangeEnd) + (rangeStart, rangeEnd) = (rangeEnd, rangeStart); + + var range = rangeEnd - rangeStart; + var distributedValue = this.GetDistributedValue(cancel); + return (ulong) ((double.CreateChecked(distributedValue) * range) + rangeStart); + } + + public TNum NextNumber(TNum rangeStart, TNum rangeEnd, CancellationToken cancel = default) + { + // Swap the values if the range start is greater than the range end: + if (rangeStart > rangeEnd) + (rangeStart, rangeEnd) = (rangeEnd, rangeStart); + + var range = rangeEnd - rangeStart; + var distributedValue = this.GetDistributedValue(cancel); + return (distributedValue * range) + rangeStart; + } + + public TNum NextNumber(CancellationToken cancel = default) => this.NextNumber(TNum.Zero, TNum.One, cancel); + + public bool HasDecisionBeenMade(TNum above, TNum below, CancellationToken cancel = default) + { + var number = this.NextNumber(cancel); + return number > above && number < below; + } +} \ No newline at end of file diff --git a/FastRng/Distributions/WeibullK05La1.cs b/FastRng/Distributions/WeibullK05La1.cs new file mode 100644 index 0000000..598bf8a --- /dev/null +++ b/FastRng/Distributions/WeibullK05La1.cs @@ -0,0 +1,16 @@ +using System.Numerics; + +namespace FastRng.Distributions; + +public sealed class WeibullK05La1 : Distribution where TNum : IFloatingPointIeee754 +{ + private static readonly TNum K = TNum.CreateChecked(0.5f); + private static readonly TNum LAMBDA = TNum.One; + private static readonly TNum CONSTANT = TNum.CreateChecked(0.221034183615129f); + + public WeibullK05La1(IRandom rng) : base(rng) + { + } + + private protected override TNum ShapeFunction(TNum x) => CONSTANT * ( (K / LAMBDA) * TNum.Pow(x / LAMBDA, K - TNum.One) * TNum.Exp(-TNum.Pow(x/LAMBDA, K))); +} \ No newline at end of file diff --git a/FastRng/Double/Distributions/BetaA2B2.cs b/FastRng/Double/Distributions/BetaA2B2.cs deleted file mode 100644 index b1d6c26..0000000 --- a/FastRng/Double/Distributions/BetaA2B2.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace FastRng.Double.Distributions -{ - public sealed class BetaA2B2 : Distribution - { - private const double ALPHA = 2; - private const double BETA = 2; - private const double CONSTANT = 4; - - public BetaA2B2(IRandom rng) : base(rng) - { - } - - private protected override double ShapeFunction(double x) => CONSTANT * Math.Pow(x, ALPHA - 1) * Math.Pow(1 - x, BETA - 1); - } -} \ No newline at end of file diff --git a/FastRng/Double/Distributions/BetaA2B5.cs b/FastRng/Double/Distributions/BetaA2B5.cs deleted file mode 100644 index e7d4677..0000000 --- a/FastRng/Double/Distributions/BetaA2B5.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace FastRng.Double.Distributions -{ - public sealed class BetaA2B5 : Distribution - { - private const double ALPHA = 2; - private const double BETA = 5; - private const double CONSTANT = 12.2; - - public BetaA2B5(IRandom rng) : base(rng) - { - } - - private protected override double ShapeFunction(double x) => CONSTANT * Math.Pow(x, ALPHA - 1) * Math.Pow(1 - x, BETA - 1); - } -} \ No newline at end of file diff --git a/FastRng/Double/Distributions/BetaA5B2.cs b/FastRng/Double/Distributions/BetaA5B2.cs deleted file mode 100644 index a7613e9..0000000 --- a/FastRng/Double/Distributions/BetaA5B2.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace FastRng.Double.Distributions -{ - public sealed class BetaA5B2 : Distribution - { - private const double ALPHA = 5; - private const double BETA = 2; - private const double CONSTANT = 12.2; - - public BetaA5B2(IRandom rng) : base(rng) - { - } - - private protected override double ShapeFunction(double x) => CONSTANT * Math.Pow(x, ALPHA - 1) * Math.Pow(1 - x, BETA - 1); - } -} \ No newline at end of file diff --git a/FastRng/Double/Distributions/CauchyLorentzX0.cs b/FastRng/Double/Distributions/CauchyLorentzX0.cs deleted file mode 100644 index c19851b..0000000 --- a/FastRng/Double/Distributions/CauchyLorentzX0.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace FastRng.Double.Distributions -{ - public sealed class CauchyLorentzX0 : Distribution - { - private const double CONSTANT = 0.31; - private const double SCALE = 0.1; - private const double MEDIAN = 0.0; - - public CauchyLorentzX0(IRandom rng) : base(rng) - { - } - - private protected override double ShapeFunction(double x) => CONSTANT * (1.0 / (Math.PI * SCALE)) * ((SCALE * SCALE) / (Math.Pow(x - MEDIAN, 2) + (SCALE * SCALE))); - } -} \ No newline at end of file diff --git a/FastRng/Double/Distributions/CauchyLorentzX1.cs b/FastRng/Double/Distributions/CauchyLorentzX1.cs deleted file mode 100644 index acb2151..0000000 --- a/FastRng/Double/Distributions/CauchyLorentzX1.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace FastRng.Double.Distributions -{ - public sealed class CauchyLorentzX1 : Distribution - { - private const double CONSTANT = 0.31; - private const double SCALE = 0.1; - private const double MEDIAN = 1.0; - - public CauchyLorentzX1(IRandom rng) : base(rng) - { - } - - private protected override double ShapeFunction(double x) => CONSTANT * (1.0 / (Math.PI * SCALE)) * ((SCALE * SCALE) / (Math.Pow(x - MEDIAN, 2) + (SCALE * SCALE))); - } -} \ No newline at end of file diff --git a/FastRng/Double/Distributions/ChiSquareK1.cs b/FastRng/Double/Distributions/ChiSquareK1.cs deleted file mode 100644 index 3290765..0000000 --- a/FastRng/Double/Distributions/ChiSquareK1.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace FastRng.Double.Distributions -{ - public sealed class ChiSquareK1 : Distribution - { - private const double K = 1.0; - private const double K_HALF = K * 0.5d; - private const double K_HALF_MINUS_ONE = K_HALF - 1.0d; - private const double CONSTANT = 0.252; - - private static readonly double DIVISOR; - - static ChiSquareK1() - { - var twoToTheKHalf = Math.Pow(2, K_HALF); - var gammaKHalf = MathTools.Gamma(K_HALF); - DIVISOR = twoToTheKHalf * gammaKHalf; - } - - public ChiSquareK1(IRandom rng) : base(rng) - { - } - - private protected override double ShapeFunction(double x) => CONSTANT * ((Math.Pow(x, K_HALF_MINUS_ONE) * Math.Exp(-x * 0.5d)) / DIVISOR); - } -} \ No newline at end of file diff --git a/FastRng/Double/Distributions/ChiSquareK10.cs b/FastRng/Double/Distributions/ChiSquareK10.cs deleted file mode 100644 index d13cf44..0000000 --- a/FastRng/Double/Distributions/ChiSquareK10.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace FastRng.Double.Distributions -{ - public sealed class ChiSquareK10 : Distribution - { - private const double K = 10.0; - private const double K_HALF = K * 0.5d; - private const double K_HALF_MINUS_ONE = K_HALF - 1.0d; - private const double CONSTANT = 0.252; - - private static readonly double DIVISOR; - - static ChiSquareK10() - { - var twoToTheKHalf = Math.Pow(2, K_HALF); - var gammaKHalf = MathTools.Gamma(K_HALF); - DIVISOR = twoToTheKHalf * gammaKHalf; - } - - public ChiSquareK10(IRandom rng) : base(rng) - { - } - - private protected override double ShapeFunction(double x) => CONSTANT * ((Math.Pow(x, K_HALF_MINUS_ONE) * Math.Exp(-x * 0.5d)) / DIVISOR); - } -} \ No newline at end of file diff --git a/FastRng/Double/Distributions/ChiSquareK4.cs b/FastRng/Double/Distributions/ChiSquareK4.cs deleted file mode 100644 index 1f854b5..0000000 --- a/FastRng/Double/Distributions/ChiSquareK4.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace FastRng.Double.Distributions -{ - public sealed class ChiSquareK4 : Distribution - { - private const double K = 4.0; - private const double K_HALF = K * 0.5d; - private const double K_HALF_MINUS_ONE = K_HALF - 1.0d; - private const double CONSTANT = 0.252; - - private static readonly double DIVISOR; - - static ChiSquareK4() - { - var twoToTheKHalf = Math.Pow(2, K_HALF); - var gammaKHalf = MathTools.Gamma(K_HALF); - DIVISOR = twoToTheKHalf * gammaKHalf; - } - - public ChiSquareK4(IRandom rng) : base(rng) - { - } - - private protected override double ShapeFunction(double x) => CONSTANT * ((Math.Pow(x, K_HALF_MINUS_ONE) * Math.Exp(-x * 0.5d)) / DIVISOR); - } -} \ No newline at end of file diff --git a/FastRng/Double/Distributions/Distribution.cs b/FastRng/Double/Distributions/Distribution.cs deleted file mode 100644 index 8de07c5..0000000 --- a/FastRng/Double/Distributions/Distribution.cs +++ /dev/null @@ -1,75 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace FastRng.Double.Distributions -{ - public abstract class Distribution : IDistribution - { - private readonly ShapeFitter fitter; - private readonly IRandom random; - - protected Distribution(IRandom rng) - { - if (rng == null) - throw new ArgumentNullException(nameof(rng), "An IRandom implementation is needed."); - - this.random = rng; - this.fitter = new ShapeFitter(this.ShapeFunction, this.random, 100); - } - - private protected abstract double ShapeFunction(double x); - - public async ValueTask GetDistributedValue(CancellationToken token = default) => await this.fitter.NextNumber(token); - - public async ValueTask NextNumber(uint rangeStart, uint rangeEnd, CancellationToken cancel = default) - { - if (rangeStart > rangeEnd) - { - var tmp = rangeStart; - rangeStart = rangeEnd; - rangeEnd = tmp; - } - - var range = rangeEnd - rangeStart; - var distributedValue = await this.GetDistributedValue(cancel); - return (uint) ((distributedValue * range) + rangeStart); - } - - public async ValueTask NextNumber(ulong rangeStart, ulong rangeEnd, CancellationToken cancel = default(CancellationToken)) - { - if (rangeStart > rangeEnd) - { - var tmp = rangeStart; - rangeStart = rangeEnd; - rangeEnd = tmp; - } - - var range = rangeEnd - rangeStart; - var distributedValue = await this.GetDistributedValue(cancel); - return (ulong) ((distributedValue * range) + rangeStart); - } - - public async ValueTask NextNumber(double rangeStart, double rangeEnd, CancellationToken cancel = default(CancellationToken)) - { - if (rangeStart > rangeEnd) - { - var tmp = rangeStart; - rangeStart = rangeEnd; - rangeEnd = tmp; - } - - var range = rangeEnd - rangeStart; - var distributedValue = await this.GetDistributedValue(cancel); - return (distributedValue * range) + rangeStart; - } - - 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/ExponentialLa10.cs b/FastRng/Double/Distributions/ExponentialLa10.cs deleted file mode 100644 index cb1d736..0000000 --- a/FastRng/Double/Distributions/ExponentialLa10.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace FastRng.Double.Distributions -{ - public sealed class ExponentialLa10 : Distribution - { - private const double LAMBDA = 10.0; - private const double CONSTANT = 0.1106; - - public ExponentialLa10(IRandom rng) : base(rng) - { - } - - private protected override double ShapeFunction(double x) => CONSTANT * LAMBDA * Math.Exp(-LAMBDA * x); - } -} \ No newline at end of file diff --git a/FastRng/Double/Distributions/ExponentialLa5.cs b/FastRng/Double/Distributions/ExponentialLa5.cs deleted file mode 100644 index 29151de..0000000 --- a/FastRng/Double/Distributions/ExponentialLa5.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace FastRng.Double.Distributions -{ - public sealed class ExponentialLa5 : Distribution - { - private const double LAMBDA = 5.0; - private const double CONSTANT = 0.2103; - - public ExponentialLa5(IRandom rng) : base(rng) - { - } - - private protected override double ShapeFunction(double x) => CONSTANT * LAMBDA * Math.Exp(-LAMBDA * x); - } -} \ No newline at end of file diff --git a/FastRng/Double/Distributions/GammaA5B15.cs b/FastRng/Double/Distributions/GammaA5B15.cs deleted file mode 100644 index 3a48a2d..0000000 --- a/FastRng/Double/Distributions/GammaA5B15.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace FastRng.Double.Distributions -{ - public sealed class GammaA5B15 : Distribution - { - private const double ALPHA = 5.0; - private const double BETA = 15.0; - private const double CONSTANT = 0.341344210715475; - - private static readonly double GAMMA_ALPHA; - private static readonly double BETA_TO_THE_ALPHA; - - static GammaA5B15() - { - GAMMA_ALPHA = MathTools.Gamma(ALPHA); - BETA_TO_THE_ALPHA = Math.Pow(BETA, ALPHA); - } - - public GammaA5B15(IRandom rng) : base(rng) - { - } - - private protected override double ShapeFunction(double x) => CONSTANT * ((BETA_TO_THE_ALPHA * Math.Pow(x, ALPHA - 1.0d) * Math.Exp(-BETA * x)) / GAMMA_ALPHA); - } -} \ No newline at end of file diff --git a/FastRng/Double/Distributions/IDistribution.cs b/FastRng/Double/Distributions/IDistribution.cs deleted file mode 100644 index 7338e00..0000000 --- a/FastRng/Double/Distributions/IDistribution.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.Threading; -using System.Threading.Tasks; - -namespace FastRng.Double.Distributions -{ - public interface IDistribution - { - public ValueTask GetDistributedValue(CancellationToken token); - - public ValueTask NextNumber(uint rangeStart, uint rangeEnd, CancellationToken cancel = default); - - public ValueTask NextNumber(ulong rangeStart, ulong rangeEnd, CancellationToken cancel = default); - - 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/InverseExponentialLa10.cs b/FastRng/Double/Distributions/InverseExponentialLa10.cs deleted file mode 100644 index f32e45a..0000000 --- a/FastRng/Double/Distributions/InverseExponentialLa10.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace FastRng.Double.Distributions -{ - public sealed class InverseExponentialLa10 : Distribution - { - private const double LAMBDA = 10.0; - private const double CONSTANT = 4.539992976248453e-06; - - public InverseExponentialLa10(IRandom rng) : base(rng) - { - } - - private protected override double ShapeFunction(double x) => CONSTANT * LAMBDA * Math.Exp(LAMBDA * x); - } -} \ No newline at end of file diff --git a/FastRng/Double/Distributions/InverseExponentialLa5.cs b/FastRng/Double/Distributions/InverseExponentialLa5.cs deleted file mode 100644 index 526c0e8..0000000 --- a/FastRng/Double/Distributions/InverseExponentialLa5.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace FastRng.Double.Distributions -{ - public sealed class InverseExponentialLa5 : Distribution - { - private const double LAMBDA = 5.0; - private const double CONSTANT = 0.001347589399817; - - public InverseExponentialLa5(IRandom rng) : base(rng) - { - } - - private protected override double ShapeFunction(double x) => CONSTANT * LAMBDA * Math.Exp(LAMBDA * x); - } -} \ No newline at end of file diff --git a/FastRng/Double/Distributions/InverseGammaA3B05.cs b/FastRng/Double/Distributions/InverseGammaA3B05.cs deleted file mode 100644 index d278d57..0000000 --- a/FastRng/Double/Distributions/InverseGammaA3B05.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace FastRng.Double.Distributions -{ - public sealed class InverseGammaA3B05 : Distribution - { - private const double ALPHA = 3.0; - private const double BETA = 0.5; - private const double CONSTANT = 0.213922656884911; - - private static readonly double FACTOR_LEFT; - - static InverseGammaA3B05() - { - var gammaAlpha = MathTools.Gamma(ALPHA); - var betaToTheAlpha = Math.Pow(BETA, ALPHA); - - FACTOR_LEFT = CONSTANT * (betaToTheAlpha / gammaAlpha); - } - - public InverseGammaA3B05(IRandom rng) : base(rng) - { - } - - private protected override double ShapeFunction(double x) => FACTOR_LEFT * Math.Pow(x, -ALPHA - 1.0d) * Math.Exp(-BETA / x); - } -} \ No newline at end of file diff --git a/FastRng/Double/Distributions/LaplaceB01M0.cs b/FastRng/Double/Distributions/LaplaceB01M0.cs deleted file mode 100644 index 2c37119..0000000 --- a/FastRng/Double/Distributions/LaplaceB01M0.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace FastRng.Double.Distributions -{ - public sealed class LaplaceB01M0 : Distribution - { - private const double B = 0.1; - private const double MU = 0.0; - private const double CONSTANT = 0.221034183615129; - - private static readonly double FACTOR_LEFT; - - static LaplaceB01M0() - { - FACTOR_LEFT = CONSTANT / (2.0d * B); - } - - public LaplaceB01M0(IRandom rng) : base(rng) - { - } - - private protected override double ShapeFunction(double x) => FACTOR_LEFT * Math.Exp(-Math.Abs(x - MU) / B); - } -} \ No newline at end of file diff --git a/FastRng/Double/Distributions/LaplaceB01M05.cs b/FastRng/Double/Distributions/LaplaceB01M05.cs deleted file mode 100644 index 4cb55d6..0000000 --- a/FastRng/Double/Distributions/LaplaceB01M05.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace FastRng.Double.Distributions -{ - public sealed class LaplaceB01M05 : Distribution - { - private const double B = 0.1; - private const double MU = 0.5; - private const double CONSTANT = 0.2; - - private static readonly double FACTOR_LEFT; - - static LaplaceB01M05() - { - FACTOR_LEFT = CONSTANT / (2.0d * B); - } - - public LaplaceB01M05(IRandom rng) : base(rng) - { - } - - private protected override double ShapeFunction(double x) => FACTOR_LEFT * Math.Exp(-Math.Abs(x - MU) / B); - } -} \ No newline at end of file diff --git a/FastRng/Double/Distributions/LogNormalS1M0.cs b/FastRng/Double/Distributions/LogNormalS1M0.cs deleted file mode 100644 index e25dfe4..0000000 --- a/FastRng/Double/Distributions/LogNormalS1M0.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace FastRng.Double.Distributions -{ - public sealed class LogNormalS1M0 : Distribution - { - private const double SIGMA = 1.0; - private const double MU = 0.0; - private const double CONSTANT = 1.51998658387455; - - private static readonly double FACTOR; - - static LogNormalS1M0() - { - FACTOR = SIGMA * Math.Sqrt(2 * Math.PI); - } - - public LogNormalS1M0(IRandom rng) : base(rng) - { - } - - private protected override double ShapeFunction(double x) => (CONSTANT / (x * FACTOR)) * Math.Exp( -(Math.Pow(Math.Log(x) - MU, 2) / (2 * Math.Pow(SIGMA, 2)))); - } -} \ No newline at end of file diff --git a/FastRng/Double/Distributions/NormalS02M05.cs b/FastRng/Double/Distributions/NormalS02M05.cs deleted file mode 100644 index 6e0386b..0000000 --- a/FastRng/Double/Distributions/NormalS02M05.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using System.Runtime.CompilerServices; -using System.Threading; -using System.Threading.Tasks; - -namespace FastRng.Double.Distributions -{ - public sealed class NormalS02M05 : Distribution - { - private const double SQRT_2_PI = 2.506628275; - private const double STDDEV = 0.2; - private const double MEAN = 0.5; - - public NormalS02M05(IRandom rng) : base(rng) - { - } - - private protected override double ShapeFunction(double x) => 1.0 / (STDDEV * SQRT_2_PI) * Math.Exp(-0.5 * Math.Pow((x - MEAN) / STDDEV, 2.0)); - } -} \ No newline at end of file diff --git a/FastRng/Double/Distributions/StudentTNu1.cs b/FastRng/Double/Distributions/StudentTNu1.cs deleted file mode 100644 index e490618..0000000 --- a/FastRng/Double/Distributions/StudentTNu1.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace FastRng.Double.Distributions -{ - public sealed class StudentTNu1 : Distribution - { - private const double NU = 1.0; - private const double START = 0.0; - private const double COMPRESS = 1.0; - private const double CONSTANT = 3.14190548592729; - - private static readonly double DIVIDEND; - private static readonly double DIVISOR; - private static readonly double EXPONENT; - - static StudentTNu1() - { - DIVIDEND = MathTools.Gamma((NU + 1.0d) * 0.5d); - DIVISOR = Math.Sqrt(NU * Math.PI) * MathTools.Gamma(NU * 0.5d); - EXPONENT = -((NU + 1.0d) * 0.5d); - } - - public StudentTNu1(IRandom rng) : base(rng) - { - } - - private protected override double ShapeFunction(double x) => CONSTANT * Math.Pow((DIVIDEND / DIVISOR) * Math.Pow(1.0d + Math.Pow(START + x * COMPRESS, 2) / NU, EXPONENT), COMPRESS); - } -} \ No newline at end of file diff --git a/FastRng/Double/Distributions/Uniform.cs b/FastRng/Double/Distributions/Uniform.cs deleted file mode 100644 index 31259f7..0000000 --- a/FastRng/Double/Distributions/Uniform.cs +++ /dev/null @@ -1,71 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace FastRng.Double.Distributions -{ - public sealed class Uniform : IDistribution - { - private readonly IRandom rng; - - public Uniform(IRandom rng) - { - if (rng == null) - throw new ArgumentNullException(nameof(rng), "An IRandom implementation is needed."); - - this.rng = rng; - } - - public async ValueTask GetDistributedValue(CancellationToken token = default) => await this.rng.GetUniform(token); - - public async ValueTask NextNumber(uint rangeStart, uint rangeEnd, CancellationToken cancel = default) - { - if (rangeStart > rangeEnd) - { - var tmp = rangeStart; - rangeStart = rangeEnd; - rangeEnd = tmp; - } - - var range = rangeEnd - rangeStart; - var distributedValue = await this.GetDistributedValue(cancel); - return (uint) ((distributedValue * range) + rangeStart); - } - - public async ValueTask NextNumber(ulong rangeStart, ulong rangeEnd, CancellationToken cancel = default(CancellationToken)) - { - if (rangeStart > rangeEnd) - { - var tmp = rangeStart; - rangeStart = rangeEnd; - rangeEnd = tmp; - } - - var range = rangeEnd - rangeStart; - var distributedValue = await this.GetDistributedValue(cancel); - return (ulong) ((distributedValue * range) + rangeStart); - } - - public async ValueTask NextNumber(double rangeStart, double rangeEnd, CancellationToken cancel = default(CancellationToken)) - { - if (rangeStart > rangeEnd) - { - var tmp = rangeStart; - rangeStart = rangeEnd; - rangeEnd = tmp; - } - - var range = rangeEnd - rangeStart; - var distributedValue = await this.GetDistributedValue(cancel); - return (distributedValue * range) + rangeStart; - } - - 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/WeibullK05La1.cs b/FastRng/Double/Distributions/WeibullK05La1.cs deleted file mode 100644 index c68a706..0000000 --- a/FastRng/Double/Distributions/WeibullK05La1.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace FastRng.Double.Distributions -{ - public sealed class WeibullK05La1 : Distribution - { - private const double K = 0.5; - private const double LAMBDA = 1.0; - private const double CONSTANT = 0.221034183615129; - - public WeibullK05La1(IRandom rng) : base(rng) - { - } - - private protected override double ShapeFunction(double x) => CONSTANT * ( (K / LAMBDA) * Math.Pow(x / LAMBDA, K - 1.0d) * Math.Exp(-Math.Pow(x/LAMBDA, K))); - } -} \ No newline at end of file diff --git a/FastRng/Double/IRandom.cs b/FastRng/Double/IRandom.cs deleted file mode 100644 index dd6f2d9..0000000 --- a/FastRng/Double/IRandom.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; -using FastRng.Double.Distributions; - -namespace FastRng.Double -{ - /// - /// Interface for random number generators. - /// - public interface IRandom : IDisposable - { - /// - /// Returns a uniform distributed pseudo-random number from the interval (0,1]. - /// This means, the result 0 is impossible, whereas 1 is possible. - /// - /// - /// This method is thread-safe. You can consume numbers from the same generator - /// by using multiple threads at the same time. - /// - /// An optional cancellation token. - public ValueTask GetUniform(CancellationToken cancel = default); - } -} \ No newline at end of file diff --git a/FastRng/Double/MathTools.cs b/FastRng/Double/MathTools.cs deleted file mode 100644 index e833a7f..0000000 --- a/FastRng/Double/MathTools.cs +++ /dev/null @@ -1,83 +0,0 @@ -using System; - -namespace FastRng.Double -{ - /// - /// Provides some mathematical function, which are not available within in the .NET framework. - /// - public static class MathTools - { - private static readonly double SQRT_2 = Math.Sqrt(2.0); - private static readonly double SQRT_PI = Math.Sqrt(Math.PI); - - /// - /// The mathematical gamma function. - /// - /// The value for which you want calculate gamma. - public static double Gamma(double z) - { - // Source: http://rosettacode.org/wiki/Gamma_function#Go - - const double F1 = 6.5; - const double A1 = .99999999999980993; - const double A2 = 676.5203681218851; - const double A3 = 1259.1392167224028; - const double A4 = 771.32342877765313; - const double A5 = 176.61502916214059; - const double A6 = 12.507343278686905; - const double A7 = .13857109526572012; - const double A8 = 9.9843695780195716e-6; - const double A9 = 1.5056327351493116e-7; - - var t = z + F1; - var x = A1 + - A2 / z - - A3 / (z + 1) + - A4 / (z + 2) - - A5 / (z + 3) + - A6 / (z + 4) - - A7 / (z + 5) + - A8 / (z + 6) + - A9 / (z + 7); - - return MathTools.SQRT_2 * MathTools.SQRT_PI * Math.Pow(t, z - 0.5) * Math.Exp(-t) * x; - } - - /// - /// The mathematical factorial function for floating-point numbers. - /// - /// The value, for which you want to know the factorial. - public static double Factorial(double x) => MathTools.Gamma(x + 1.0); - - /// - /// The mathematical factorial function for integer numbers. - /// - /// The value, for which you want to know the factorial. - /// Throws, when x is greater than 20. Due to limitations of 64bit ulong type. - public static ulong Factorial(uint x) - { - if (x > 20) - throw new ArgumentOutOfRangeException(nameof(x), $"Cannot compute {x}!, since ulong.max is 18_446_744_073_709_551_615."); - - ulong accumulator = 1; - for (uint factor = 1; factor <= x; factor++) - accumulator *= factor; - - return accumulator; - } - - /// - /// The mathematical factorial function for integer numbers. - /// - /// The value, for which you want to know the factorial. - /// Throws, when x is greater than 20. Due to limitations - /// of 64bit ulong type. Throws also, when x is less than 0. - public static ulong Factorial(int x) - { - if(x < 0) - throw new ArgumentOutOfRangeException(nameof(x), "Given value must be greater as zero."); - - return MathTools.Factorial((uint) x); - } - } -} \ No newline at end of file diff --git a/FastRng/Double/MultiThreadedRng.cs b/FastRng/Double/MultiThreadedRng.cs deleted file mode 100644 index 6b35aca..0000000 --- a/FastRng/Double/MultiThreadedRng.cs +++ /dev/null @@ -1,358 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Diagnostics.CodeAnalysis; -using System.Threading; -using System.Threading.Tasks; -using FastRng.Double.Distributions; - -namespace FastRng.Double -{ - /// - /// A fast multi-threaded pseudo random number generator. - /// - /// - /// Please note, that Math.NET's (https://www.mathdotnet.com/) random number generator is in some situations faster. - /// Unlike Math.NET, MultiThreadedRng is multi-threaded and async. Consumers can await the next number without - /// blocking resources. Additionally, consumers can use a token to cancel e.g. timeout an operation as well.

- /// - /// MultiThreadedRng using a shape fitter (a rejection sampler) to enforce arbitrary shapes of probabilities for - /// desired distributions. By using the shape fitter, it is even easy to define discontinuous, arbitrary functions - /// as shapes. Any consumer can define and use own distributions.

- /// - /// This class uses the George Marsaglia's MWC algorithm. The algorithm's implementation based loosely on John D. - /// Cook's (johndcook.com) implementation (https://www.codeproject.com/Articles/25172/Simple-Random-Number-Generation). - /// Thanks John for the inspiration.

- /// - /// Please notice: When using the debug environment, MultiThreadedRng uses a smaller buffer size. Please ensure, - /// that the production environment uses a release build, though. - ///
- public sealed class MultiThreadedRng : IRandom, IDisposable - { - #if DEBUG - private const int BUFFER_SIZE = 10_000; - #else - private const int BUFFER_SIZE = 1_000_000; - #endif - - // The queue size means, how many buffer we store in a queue at the same time: - private const int QUEUE_SIZE = 2; - - // Gets used to stop the producer threads: - private readonly CancellationTokenSource producerTokenSource = new CancellationTokenSource(); - - // The time a thread waits e.g. to check if the queue needs a new buffer: - private readonly TimeSpan waiter = TimeSpan.FromMilliseconds(10); - - // The first queue, where to store buffers of random uint numbers: - private readonly ConcurrentQueue queueIntegers = new ConcurrentQueue(); - - // The second queue, where to store buffers of uniform random double numbers: - private readonly ConcurrentQueue queueDoubles = new ConcurrentQueue(); - - // The uint producer thread: - private Thread producerRandomUint; - - // The uniform double producer thread: - private Thread producerRandomUniformDistributedDouble; - - // Variable w and z for the uint generator. Both get used - // as seeding variable as well (cf. constructors) - private uint mW; - private uint mZ; - - // This is the current buffer for the consumer side i.e. the public interfaces: - private double[] currentBuffer = Array.Empty(); - - // The current pointer to the next current buffer's address to read from: - private int currentBufferPointer = BUFFER_SIZE; - - #region Constructors - - /// - /// Creates a multi-threaded random number generator. - /// - /// - /// This constructor uses the user's current local time - /// to derive necessary parameters for the generator. - /// Thus, the results are depending on the time, where - /// the generator was created. - /// - public MultiThreadedRng() - { - // - // Initialize the mW and mZ by using - // the system's time. - // - var now = DateTime.Now; - var ticks = now.Ticks; - this.mW = (uint) (ticks >> 16); - this.mZ = (uint) (ticks % 4_294_967_296); - this.StartProducerThreads(); - } - - /// - /// Creates a multi-threaded random number generator. - /// - /// - /// A multi-threaded random number generator created by this constructor is - /// deterministic. It's behaviour is not depending on the time of its creation.

- /// - /// Please note: Although the number generator and all distributions are deterministic, - /// the behavior of the consuming application might be non-deterministic. This is possible if - /// the application with multiple threads consumes the numbers. The scheduling of the threads - /// is up to the operating system and might not be predictable. - ///
- /// A seed value to generate a deterministic generator. - public MultiThreadedRng(uint seedU) - { - this.mW = seedU; - this.mZ = 362_436_069; - this.StartProducerThreads(); - } - - /// - /// Creates a multi-threaded random number generator. - /// - /// - /// A multi-threaded random number generator created by this constructor is - /// deterministic. It's behaviour is not depending on the time of its creation.

- /// - /// Please note: Although the number generator and all distributions are deterministic, - /// the behavior of the consuming application might be non-deterministic. This is possible if - /// the application with multiple threads consumes the numbers. The scheduling of the threads - /// is up to the operating system and might not be predictable. - ///
- /// The first seed value. - /// The second seed value. - public MultiThreadedRng(uint seedU, uint seedV) - { - this.mW = seedU; - this.mZ = seedV; - this.StartProducerThreads(); - } - - private void StartProducerThreads() - { - this.producerRandomUint = new Thread(() => this.RandomProducerUint(this.producerTokenSource.Token)) {IsBackground = true}; - this.producerRandomUint.Start(); - this.producerRandomUniformDistributedDouble = new Thread(() => this.RandomProducerUniformDistributedDouble(this.producerTokenSource.Token)) {IsBackground = true}; - this.producerRandomUniformDistributedDouble.Start(); - } - - #endregion - - #region Producers - - [ExcludeFromCodeCoverage] - private async void RandomProducerUint(CancellationToken cancellationToken) - { - try - { - while (!cancellationToken.IsCancellationRequested) - { - // A local next buffer, which gets filled next: - var nextBuffer = new uint[BUFFER_SIZE]; - - // Produce the necessary number of random uints: - for (var n = 0; n < nextBuffer.Length && !cancellationToken.IsCancellationRequested; n++) - { - this.mZ = 36_969 * (this.mZ & 65_535) + (this.mZ >> 16); - this.mW = 18_000 * (this.mW & 65_535) + (this.mW >> 16); - nextBuffer[n] = (this.mZ << 16) + this.mW; - } - - // Inside this loop, we try to enqueue the produced buffer: - while (!cancellationToken.IsCancellationRequested) - { - try - { - // Ensure, that we do not produce more buffers, as configured: - if (this.queueIntegers.Count < QUEUE_SIZE) - { - this.queueIntegers.Enqueue(nextBuffer); - break; - } - - // The queue was full. Wait a moment and try it again: - await Task.Delay(this.waiter, cancellationToken); - } - catch (TaskCanceledException) - { - // The producers should be stopped: - return; - } - } - } - } - catch (OperationCanceledException) - { - } - } - - [ExcludeFromCodeCoverage] - private async void RandomProducerUniformDistributedDouble(CancellationToken cancellationToken) - { - try - { - while (!cancellationToken.IsCancellationRequested) - { - // A local source buffer of uints: - uint[] bufferSource = null; - - // Try to get the next source buffer: - while (!this.queueIntegers.TryDequeue(out bufferSource) && !cancellationToken.IsCancellationRequested) - await Task.Delay(this.waiter, cancellationToken); - - // Case: The producers should be stopped: - if(bufferSource == null) - return; - - // A local buffer to fill with uniform doubles: - var nextBuffer = new double[BUFFER_SIZE]; - - // Generate the necessary number of doubles: - for (var n = 0; n < nextBuffer.Length && !cancellationToken.IsCancellationRequested; n++) - nextBuffer[n] = (bufferSource[n] + 1.0) * 2.328306435454494e-10; - - // Inside this loop, we try to enqueue the generated buffer: - while (!cancellationToken.IsCancellationRequested) - { - try - { - // Ensure, that the queue contains only the configured number of buffers: - if (this.queueDoubles.Count < QUEUE_SIZE) - { - this.queueDoubles.Enqueue(nextBuffer); - break; - } - - // The queue was full. Wait a moment and try it again: - await Task.Delay(this.waiter, cancellationToken); - } - catch (TaskCanceledException) - { - return; - } - } - } - } - catch (OperationCanceledException) - { - } - } - - #endregion - - #region Implementing interface - - /// - /// Returns a uniform distributed pseudo-random number from the interval (0,1]. - /// This means, the result 0 is impossible, whereas 1 is possible. - /// - /// - /// This method is thread-safe. You can consume numbers from the same generator - /// by using multiple threads at the same time. - /// - /// An optional cancellation token. - public async ValueTask GetUniform(CancellationToken cancel = default) - { - while (!cancel.IsCancellationRequested) - { - // Check, if we need a new buffer to read from: - if (this.currentBufferPointer >= BUFFER_SIZE) - { - // Create a local copy of the current buffer's pointer: - var currentBufferReference = this.currentBuffer; - - // Here, we store the next buffer until we implement it: - var nextBuffer = Array.Empty(); - - // Try to get the next buffer from the queue: - while (this.currentBufferPointer >= BUFFER_SIZE && currentBufferReference == this.currentBuffer && !this.queueDoubles.TryDequeue(out nextBuffer)) - { - // - // Case: There is no next buffer available. - // Must wait for producer(s) to provide next. - // - try - { - await Task.Delay(this.waiter, cancel); - } - catch (TaskCanceledException) - { - // - // Case: The consumer cancelled the request. - // - return double.NaN; - } - } - - // - // Note: In general, it does not matter if the following compare-exchange is successful. - // 1st case: It was successful -- everything is fine. But we are responsible to re-set the currentBufferPointer. - // 2nd case: It was not successful. This means, that another thread was successful, though. - // That case is fine as well. But we would loose one buffer of work. Thus, we - // check for this case and preserve the buffer full of work. - // - - // Try to implement the dequeued buffer without locking other threads: - if (Interlocked.CompareExchange(ref this.currentBuffer, nextBuffer, currentBufferReference) != currentBufferReference) - { - // - // Case: Another thread updated the buffer already. - // Thus, we enqueue our copy of the next buffer to preserve it. - // - this.queueDoubles.Enqueue(nextBuffer); - - // Next? We can go ahead and yield a random number... - } - else - { - // - // Case: We updated the buffer. - // - this.currentBufferPointer = 0; - - // Next? We can go ahead and yield a random number... - } - } - - // Made a local copy of the current pointer: - var myPointer = this.currentBufferPointer; - - // Increment the pointer for the next thread or call: - var nextPointer = myPointer + 1; - - // Try to update the pointer without locking other threads: - if (Interlocked.CompareExchange(ref this.currentBufferPointer, nextPointer, myPointer) == myPointer) - { - // - // Case: Success. We updated the pointer and, thus, can use the pointer to read a number. - // - return this.currentBuffer[myPointer]; - } - - // - // Case: Another thread updated the pointer already. Must restart the process - // to get a random number. - // - } - - // - // Case: The consumer cancelled the request. - // - return double.NaN; - } - - private void StopProducer() => this.producerTokenSource.Cancel(); - - /// - /// Disposes this generator. It is important to dispose a generator, - /// when it is no longer needed. Otherwise, the background threads - /// are still running. - /// - public void Dispose() => this.StopProducer(); - - #endregion - } -} \ No newline at end of file diff --git a/FastRng/Double/ShapeFitter.cs b/FastRng/Double/ShapeFitter.cs deleted file mode 100644 index 508b4ef..0000000 --- a/FastRng/Double/ShapeFitter.cs +++ /dev/null @@ -1,79 +0,0 @@ -using System; -using System.Runtime.CompilerServices; -using System.Threading; -using System.Threading.Tasks; -using FastRng.Double.Distributions; - -namespace FastRng.Double -{ - /// - /// ShapeFitter is a rejection sampler, cf. https://en.wikipedia.org/wiki/Rejection_sampling - /// - public sealed class ShapeFitter - { - private readonly double[] probabilities; - private readonly IRandom rng; - private readonly double max; - private readonly double sampleSize; - private readonly IDistribution uniform; - - /// - /// Creates a shape fitter instance. - /// - /// The function which describes the desired shape. - /// The random number generator instance to use. - /// The number of sampling steps to sample the given function. - public ShapeFitter(Func shapeFunction, IRandom rng, ushort sampleSize = 50) - { - this.rng = rng; - this.uniform = new Uniform(rng); - this.sampleSize = sampleSize; - this.probabilities = new double[sampleSize]; - - var sampleStepSize = 1.0d / sampleSize; - var nextStep = 0.0 + sampleStepSize; - var maxValue = 0.0d; - for (var n = 0; n < sampleSize; n++) - { - this.probabilities[n] = shapeFunction(nextStep); - if (this.probabilities[n] > maxValue) - maxValue = this.probabilities[n]; - - nextStep += sampleStepSize; - } - - this.max = maxValue; - } - - /// - /// Returns a random number regarding the given shape. - /// - /// An optional cancellation token. - /// The next value regarding the given shape. - public async ValueTask NextNumber(CancellationToken token = default) - { - while (!token.IsCancellationRequested) - { - var x = await this.rng.GetUniform(token); - if (double.IsNaN(x)) - return x; - - var nextBucket = (int)Math.Floor(x * this.sampleSize); - if (nextBucket >= this.probabilities.Length) - nextBucket = this.probabilities.Length - 1; - - var threshold = this.probabilities[nextBucket]; - var y = await this.uniform.NextNumber(0.0d, this.max, token); - if (double.IsNaN(y)) - return y; - - if(y > threshold) - continue; - - return x; - } - - return double.NaN; - } - } -} \ No newline at end of file diff --git a/FastRng/FastRng.csproj b/FastRng/FastRng.csproj index 50e29eb..e56f403 100644 --- a/FastRng/FastRng.csproj +++ b/FastRng/FastRng.csproj @@ -1,23 +1,25 @@ - net5.0 + net7.0 true - 1.0.1 - 1.0.1 + 1.1.0 + 1.1.0 + 1.1.0 Thorsten Sommer - https://github.com/SommerEngineering/FastRng - https://code.tsommer.org/thorsten/FastRng + https://devops.tsommer.org/open-source/dotnet/FastRng + https://devops.tsommer.org/open-source/dotnet/FastRng BSD-3-Clause - 1.0.1 + latest - bin\Debug\ExaArray.xml + bin\Debug\FastRng.xml - bin\Release\ExaArray.xml + bin\Release\FastRng.xml + diff --git a/FastRng/Float/Distributions/BetaA2B2.cs b/FastRng/Float/Distributions/BetaA2B2.cs deleted file mode 100644 index 4b32c56..0000000 --- a/FastRng/Float/Distributions/BetaA2B2.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; - -namespace FastRng.Float.Distributions -{ - public sealed class BetaA2B2 : Distribution - { - private const float ALPHA = 2f; - private const float BETA = 2f; - private const float CONSTANT = 4f; - - public BetaA2B2(IRandom rng) : base(rng) - { - } - - private protected override float ShapeFunction(float x) => CONSTANT * MathF.Pow(x, ALPHA - 1f) * MathF.Pow(1f - x, BETA - 1f); - } -} \ No newline at end of file diff --git a/FastRng/Float/Distributions/BetaA2B5.cs b/FastRng/Float/Distributions/BetaA2B5.cs deleted file mode 100644 index d3a2e5e..0000000 --- a/FastRng/Float/Distributions/BetaA2B5.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; - -namespace FastRng.Float.Distributions -{ - public sealed class BetaA2B5 : Distribution - { - private const float ALPHA = 2f; - private const float BETA = 5f; - private const float CONSTANT = 12.2f; - - public BetaA2B5(IRandom rng) : base(rng) - { - } - - private protected override float ShapeFunction(float x) => CONSTANT * MathF.Pow(x, ALPHA - 1f) * MathF.Pow(1f - x, BETA - 1f); - } -} \ No newline at end of file diff --git a/FastRng/Float/Distributions/BetaA5B2.cs b/FastRng/Float/Distributions/BetaA5B2.cs deleted file mode 100644 index e0ce271..0000000 --- a/FastRng/Float/Distributions/BetaA5B2.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; - -namespace FastRng.Float.Distributions -{ - public sealed class BetaA5B2 : Distribution - { - private const float ALPHA = 5f; - private const float BETA = 2f; - private const float CONSTANT = 12.2f; - - public BetaA5B2(IRandom rng) : base(rng) - { - } - - private protected override float ShapeFunction(float x) => CONSTANT * MathF.Pow(x, ALPHA - 1f) * MathF.Pow(1f - x, BETA - 1f); - } -} \ No newline at end of file diff --git a/FastRng/Float/Distributions/CauchyLorentzX0.cs b/FastRng/Float/Distributions/CauchyLorentzX0.cs deleted file mode 100644 index 9eb5a56..0000000 --- a/FastRng/Float/Distributions/CauchyLorentzX0.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; - -namespace FastRng.Float.Distributions -{ - public sealed class CauchyLorentzX0 : Distribution - { - private const float CONSTANT = 0.31f; - private const float SCALE = 0.1f; - private const float MEDIAN = 0.0f; - - public CauchyLorentzX0(IRandom rng) : base(rng) - { - } - - private protected override float ShapeFunction(float x) => CONSTANT * (1.0f / (MathF.PI * SCALE)) * ((SCALE * SCALE) / (MathF.Pow(x - MEDIAN, 2f) + (SCALE * SCALE))); - } -} \ No newline at end of file diff --git a/FastRng/Float/Distributions/CauchyLorentzX1.cs b/FastRng/Float/Distributions/CauchyLorentzX1.cs deleted file mode 100644 index 12e2467..0000000 --- a/FastRng/Float/Distributions/CauchyLorentzX1.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; - -namespace FastRng.Float.Distributions -{ - public sealed class CauchyLorentzX1 : Distribution - { - private const float CONSTANT = 0.31f; - private const float SCALE = 0.1f; - private const float MEDIAN = 1.0f; - - public CauchyLorentzX1(IRandom rng) : base(rng) - { - } - - private protected override float ShapeFunction(float x) => CONSTANT * (1.0f / (MathF.PI * SCALE)) * ((SCALE * SCALE) / (MathF.Pow(x - MEDIAN, 2f) + (SCALE * SCALE))); - } -} \ No newline at end of file diff --git a/FastRng/Float/Distributions/ChiSquareK1.cs b/FastRng/Float/Distributions/ChiSquareK1.cs deleted file mode 100644 index dc013e2..0000000 --- a/FastRng/Float/Distributions/ChiSquareK1.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; - -namespace FastRng.Float.Distributions -{ - public sealed class ChiSquareK1 : Distribution - { - private const float K = 1.0f; - private const float K_HALF = K * 0.5f; - private const float K_HALF_MINUS_ONE = K_HALF - 1.0f; - private const float CONSTANT = 0.252f; - - private static readonly float DIVISOR; - - static ChiSquareK1() - { - var twoToTheKHalf = MathF.Pow(2f, K_HALF); - var gammaKHalf = MathTools.Gamma(K_HALF); - DIVISOR = twoToTheKHalf * gammaKHalf; - } - - public ChiSquareK1(IRandom rng) : base(rng) - { - } - - private protected override float ShapeFunction(float x) => CONSTANT * ((MathF.Pow(x, K_HALF_MINUS_ONE) * MathF.Exp(-x * 0.5f)) / DIVISOR); - } -} \ No newline at end of file diff --git a/FastRng/Float/Distributions/ChiSquareK10.cs b/FastRng/Float/Distributions/ChiSquareK10.cs deleted file mode 100644 index 77e1d83..0000000 --- a/FastRng/Float/Distributions/ChiSquareK10.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; - -namespace FastRng.Float.Distributions -{ - public sealed class ChiSquareK10 : Distribution - { - private const float K = 10.0f; - private const float K_HALF = K * 0.5f; - private const float K_HALF_MINUS_ONE = K_HALF - 1.0f; - private const float CONSTANT = 0.252f; - - private static readonly float DIVISOR; - - static ChiSquareK10() - { - var twoToTheKHalf = MathF.Pow(2f, K_HALF); - var gammaKHalf = MathTools.Gamma(K_HALF); - DIVISOR = twoToTheKHalf * gammaKHalf; - } - - public ChiSquareK10(IRandom rng) : base(rng) - { - } - - private protected override float ShapeFunction(float x) => CONSTANT * ((MathF.Pow(x, K_HALF_MINUS_ONE) * MathF.Exp(-x * 0.5f)) / DIVISOR); - } -} \ No newline at end of file diff --git a/FastRng/Float/Distributions/ChiSquareK4.cs b/FastRng/Float/Distributions/ChiSquareK4.cs deleted file mode 100644 index 5d4142d..0000000 --- a/FastRng/Float/Distributions/ChiSquareK4.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; - -namespace FastRng.Float.Distributions -{ - public sealed class ChiSquareK4 : Distribution - { - private const float K = 4.0f; - private const float K_HALF = K * 0.5f; - private const float K_HALF_MINUS_ONE = K_HALF - 1.0f; - private const float CONSTANT = 0.252f; - - private static readonly float DIVISOR; - - static ChiSquareK4() - { - var twoToTheKHalf = MathF.Pow(2, K_HALF); - var gammaKHalf = MathTools.Gamma(K_HALF); - DIVISOR = twoToTheKHalf * gammaKHalf; - } - - public ChiSquareK4(IRandom rng) : base(rng) - { - } - - private protected override float ShapeFunction(float x) => CONSTANT * ((MathF.Pow(x, K_HALF_MINUS_ONE) * MathF.Exp(-x * 0.5f)) / DIVISOR); - } -} \ No newline at end of file diff --git a/FastRng/Float/Distributions/Distribution.cs b/FastRng/Float/Distributions/Distribution.cs deleted file mode 100644 index 70b2a0e..0000000 --- a/FastRng/Float/Distributions/Distribution.cs +++ /dev/null @@ -1,75 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace FastRng.Float.Distributions -{ - public abstract class Distribution : IDistribution - { - private readonly ShapeFitter fitter; - private readonly IRandom random; - - protected Distribution(IRandom rng) - { - if (rng == null) - throw new ArgumentNullException(nameof(rng), "An IRandom implementation is needed."); - - this.random = rng; - this.fitter = new ShapeFitter(this.ShapeFunction, this.random, 100); - } - - private protected abstract float ShapeFunction(float x); - - public async ValueTask GetDistributedValue(CancellationToken token = default) => await this.fitter.NextNumber(token); - - public async ValueTask NextNumber(uint rangeStart, uint rangeEnd, CancellationToken cancel = default) - { - if (rangeStart > rangeEnd) - { - var tmp = rangeStart; - rangeStart = rangeEnd; - rangeEnd = tmp; - } - - var range = rangeEnd - rangeStart; - var distributedValue = await this.GetDistributedValue(cancel); - return (uint) ((distributedValue * range) + rangeStart); - } - - public async ValueTask NextNumber(ulong rangeStart, ulong rangeEnd, CancellationToken cancel = default(CancellationToken)) - { - if (rangeStart > rangeEnd) - { - var tmp = rangeStart; - rangeStart = rangeEnd; - rangeEnd = tmp; - } - - var range = rangeEnd - rangeStart; - var distributedValue = await this.GetDistributedValue(cancel); - return (ulong) ((distributedValue * range) + rangeStart); - } - - public async ValueTask NextNumber(float rangeStart, float rangeEnd, CancellationToken cancel = default(CancellationToken)) - { - if (rangeStart > rangeEnd) - { - var tmp = rangeStart; - rangeStart = rangeEnd; - rangeEnd = tmp; - } - - var range = rangeEnd - rangeStart; - var distributedValue = await this.GetDistributedValue(cancel); - return (distributedValue * range) + rangeStart; - } - - 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/ExponentialLa10.cs b/FastRng/Float/Distributions/ExponentialLa10.cs deleted file mode 100644 index ae9a4de..0000000 --- a/FastRng/Float/Distributions/ExponentialLa10.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; - -namespace FastRng.Float.Distributions -{ - public sealed class ExponentialLa10 : Distribution - { - private const float LAMBDA = 10.0f; - private const float CONSTANT = 0.1106f; - - public ExponentialLa10(IRandom rng) : base(rng) - { - } - - private protected override float ShapeFunction(float x) => CONSTANT * LAMBDA * MathF.Exp(-LAMBDA * x); - } -} \ No newline at end of file diff --git a/FastRng/Float/Distributions/ExponentialLa5.cs b/FastRng/Float/Distributions/ExponentialLa5.cs deleted file mode 100644 index c289f35..0000000 --- a/FastRng/Float/Distributions/ExponentialLa5.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; - -namespace FastRng.Float.Distributions -{ - public sealed class ExponentialLa5 : Distribution - { - private const float LAMBDA = 5.0f; - private const float CONSTANT = 0.2103f; - - public ExponentialLa5(IRandom rng) : base(rng) - { - } - - private protected override float ShapeFunction(float x) => CONSTANT * LAMBDA * MathF.Exp(-LAMBDA * x); - } -} \ No newline at end of file diff --git a/FastRng/Float/Distributions/GammaA5B15.cs b/FastRng/Float/Distributions/GammaA5B15.cs deleted file mode 100644 index e0667e2..0000000 --- a/FastRng/Float/Distributions/GammaA5B15.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; - -namespace FastRng.Float.Distributions -{ - public sealed class GammaA5B15 : Distribution - { - private const float ALPHA = 5.0f; - private const float BETA = 15.0f; - private const float CONSTANT = 0.341344210715475f; - - private static readonly float GAMMA_ALPHA; - private static readonly float BETA_TO_THE_ALPHA; - - static GammaA5B15() - { - GAMMA_ALPHA = MathTools.Gamma(ALPHA); - BETA_TO_THE_ALPHA = MathF.Pow(BETA, ALPHA); - } - - public GammaA5B15(IRandom rng) : base(rng) - { - } - - private protected override float ShapeFunction(float x) => CONSTANT * ((BETA_TO_THE_ALPHA * MathF.Pow(x, ALPHA - 1.0f) * MathF.Exp(-BETA * x)) / GAMMA_ALPHA); - } -} \ No newline at end of file diff --git a/FastRng/Float/Distributions/IDistribution.cs b/FastRng/Float/Distributions/IDistribution.cs deleted file mode 100644 index 150080e..0000000 --- a/FastRng/Float/Distributions/IDistribution.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.Threading; -using System.Threading.Tasks; - -namespace FastRng.Float.Distributions -{ - public interface IDistribution - { - public ValueTask GetDistributedValue(CancellationToken token); - - public ValueTask NextNumber(uint rangeStart, uint rangeEnd, CancellationToken cancel = default); - - public ValueTask NextNumber(ulong rangeStart, ulong rangeEnd, CancellationToken cancel = default); - - 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/InverseExponentialLa10.cs b/FastRng/Float/Distributions/InverseExponentialLa10.cs deleted file mode 100644 index 51a2785..0000000 --- a/FastRng/Float/Distributions/InverseExponentialLa10.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; - -namespace FastRng.Float.Distributions -{ - public sealed class InverseExponentialLa10 : Distribution - { - private const float LAMBDA = 10.0f; - private const float CONSTANT = 4.539992976248453e-06f; - - public InverseExponentialLa10(IRandom rng) : base(rng) - { - } - - private protected override float ShapeFunction(float x) => CONSTANT * LAMBDA * MathF.Exp(LAMBDA * x); - } -} \ No newline at end of file diff --git a/FastRng/Float/Distributions/InverseExponentialLa5.cs b/FastRng/Float/Distributions/InverseExponentialLa5.cs deleted file mode 100644 index 1a988b2..0000000 --- a/FastRng/Float/Distributions/InverseExponentialLa5.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; - -namespace FastRng.Float.Distributions -{ - public sealed class InverseExponentialLa5 : Distribution - { - private const float LAMBDA = 5.0f; - private const float CONSTANT = 0.001347589399817f; - - public InverseExponentialLa5(IRandom rng) : base(rng) - { - } - - private protected override float ShapeFunction(float x) => CONSTANT * LAMBDA * MathF.Exp(LAMBDA * x); - } -} \ No newline at end of file diff --git a/FastRng/Float/Distributions/InverseGammaA3B05.cs b/FastRng/Float/Distributions/InverseGammaA3B05.cs deleted file mode 100644 index 50fe1cd..0000000 --- a/FastRng/Float/Distributions/InverseGammaA3B05.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; - -namespace FastRng.Float.Distributions -{ - public sealed class InverseGammaA3B05 : Distribution - { - private const float ALPHA = 3.0f; - private const float BETA = 0.5f; - private const float CONSTANT = 0.213922656884911f; - - private static readonly float FACTOR_LEFT; - - static InverseGammaA3B05() - { - var gammaAlpha = MathTools.Gamma(ALPHA); - var betaToTheAlpha = MathF.Pow(BETA, ALPHA); - - FACTOR_LEFT = CONSTANT * (betaToTheAlpha / gammaAlpha); - } - - public InverseGammaA3B05(IRandom rng) : base(rng) - { - } - - private protected override float ShapeFunction(float x) => FACTOR_LEFT * MathF.Pow(x, -ALPHA - 1.0f) * MathF.Exp(-BETA / x); - } -} \ No newline at end of file diff --git a/FastRng/Float/Distributions/LaplaceB01M0.cs b/FastRng/Float/Distributions/LaplaceB01M0.cs deleted file mode 100644 index bdecca0..0000000 --- a/FastRng/Float/Distributions/LaplaceB01M0.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; - -namespace FastRng.Float.Distributions -{ - public sealed class LaplaceB01M0 : Distribution - { - private const float B = 0.1f; - private const float MU = 0.0f; - private const float CONSTANT = 0.221034183615129f; - - private static readonly float FACTOR_LEFT; - - static LaplaceB01M0() - { - FACTOR_LEFT = CONSTANT / (2.0f * B); - } - - public LaplaceB01M0(IRandom rng) : base(rng) - { - } - - private protected override float ShapeFunction(float x) => FACTOR_LEFT * MathF.Exp(-MathF.Abs(x - MU) / B); - } -} \ No newline at end of file diff --git a/FastRng/Float/Distributions/LaplaceB01M05.cs b/FastRng/Float/Distributions/LaplaceB01M05.cs deleted file mode 100644 index 505a2ee..0000000 --- a/FastRng/Float/Distributions/LaplaceB01M05.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; - -namespace FastRng.Float.Distributions -{ - public sealed class LaplaceB01M05 : Distribution - { - private const float B = 0.1f; - private const float MU = 0.5f; - private const float CONSTANT = 0.2f; - - private static readonly float FACTOR_LEFT; - - static LaplaceB01M05() - { - FACTOR_LEFT = CONSTANT / (2.0f * B); - } - - public LaplaceB01M05(IRandom rng) : base(rng) - { - } - - private protected override float ShapeFunction(float x) => FACTOR_LEFT * MathF.Exp(-MathF.Abs(x - MU) / B); - } -} \ No newline at end of file diff --git a/FastRng/Float/Distributions/LogNormalS1M0.cs b/FastRng/Float/Distributions/LogNormalS1M0.cs deleted file mode 100644 index b6c1cb8..0000000 --- a/FastRng/Float/Distributions/LogNormalS1M0.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; - -namespace FastRng.Float.Distributions -{ - public sealed class LogNormalS1M0 : Distribution - { - private const float SIGMA = 1.0f; - private const float MU = 0.0f; - private const float CONSTANT = 1.51998658387455f; - - private static readonly float FACTOR; - - static LogNormalS1M0() - { - FACTOR = SIGMA * MathF.Sqrt(2f * MathF.PI); - } - - public LogNormalS1M0(IRandom rng) : base(rng) - { - } - - private protected override float ShapeFunction(float x) => (CONSTANT / (x * FACTOR)) * MathF.Exp( -(MathF.Pow(MathF.Log(x) - MU, 2f) / (2f * MathF.Pow(SIGMA, 2f)))); - } -} \ No newline at end of file diff --git a/FastRng/Float/Distributions/NormalS02M05.cs b/FastRng/Float/Distributions/NormalS02M05.cs deleted file mode 100644 index b1f52a4..0000000 --- a/FastRng/Float/Distributions/NormalS02M05.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; - -namespace FastRng.Float.Distributions -{ - public sealed class NormalS02M05 : Distribution - { - private const float SQRT_2_PI = 2.506628275f; - private const float STDDEV = 0.2f; - private const float MEAN = 0.5f; - - public NormalS02M05(IRandom rng) : base(rng) - { - } - - private protected override float ShapeFunction(float x) => 1.0f / (STDDEV * SQRT_2_PI) * MathF.Exp(-0.5f * MathF.Pow((x - MEAN) / STDDEV, 2.0f)); - } -} \ No newline at end of file diff --git a/FastRng/Float/Distributions/StudentTNu1.cs b/FastRng/Float/Distributions/StudentTNu1.cs deleted file mode 100644 index 6e4e38f..0000000 --- a/FastRng/Float/Distributions/StudentTNu1.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System; - -namespace FastRng.Float.Distributions -{ - public sealed class StudentTNu1 : Distribution - { - private const float NU = 1.0f; - private const float START = 0.0f; - private const float COMPRESS = 1.0f; - private const float CONSTANT = 3.14190548592729f; - - private static readonly float DIVIDEND; - private static readonly float DIVISOR; - private static readonly float EXPONENT; - - static StudentTNu1() - { - DIVIDEND = MathTools.Gamma((NU + 1.0f) * 0.5f); - DIVISOR = MathF.Sqrt(NU * MathF.PI) * MathTools.Gamma(NU * 0.5f); - EXPONENT = -((NU + 1.0f) * 0.5f); - } - - public StudentTNu1(IRandom rng) : base(rng) - { - } - - private protected override float ShapeFunction(float x) => CONSTANT * MathF.Pow((DIVIDEND / DIVISOR) * MathF.Pow(1.0f + MathF.Pow(START + x * COMPRESS, 2f) / NU, EXPONENT), COMPRESS); - } -} \ No newline at end of file diff --git a/FastRng/Float/Distributions/Uniform.cs b/FastRng/Float/Distributions/Uniform.cs deleted file mode 100644 index 8149f6e..0000000 --- a/FastRng/Float/Distributions/Uniform.cs +++ /dev/null @@ -1,71 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace FastRng.Float.Distributions -{ - public sealed class Uniform : IDistribution - { - private readonly IRandom rng; - - public Uniform(IRandom rng) - { - if (rng == null) - throw new ArgumentNullException(nameof(rng), "An IRandom implementation is needed."); - - this.rng = rng; - } - - public async ValueTask GetDistributedValue(CancellationToken token = default) => await this.rng.GetUniform(token); - - public async ValueTask NextNumber(uint rangeStart, uint rangeEnd, CancellationToken cancel = default) - { - if (rangeStart > rangeEnd) - { - var tmp = rangeStart; - rangeStart = rangeEnd; - rangeEnd = tmp; - } - - var range = rangeEnd - rangeStart; - var distributedValue = await this.GetDistributedValue(cancel); - return (uint) ((distributedValue * range) + rangeStart); - } - - public async ValueTask NextNumber(ulong rangeStart, ulong rangeEnd, CancellationToken cancel = default(CancellationToken)) - { - if (rangeStart > rangeEnd) - { - var tmp = rangeStart; - rangeStart = rangeEnd; - rangeEnd = tmp; - } - - var range = rangeEnd - rangeStart; - var distributedValue = await this.GetDistributedValue(cancel); - return (ulong) ((distributedValue * range) + rangeStart); - } - - public async ValueTask NextNumber(float rangeStart, float rangeEnd, CancellationToken cancel = default(CancellationToken)) - { - if (rangeStart > rangeEnd) - { - var tmp = rangeStart; - rangeStart = rangeEnd; - rangeEnd = tmp; - } - - var range = rangeEnd - rangeStart; - var distributedValue = await this.GetDistributedValue(cancel); - return (distributedValue * range) + rangeStart; - } - - 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/WeibullK05La1.cs b/FastRng/Float/Distributions/WeibullK05La1.cs deleted file mode 100644 index 612e5f5..0000000 --- a/FastRng/Float/Distributions/WeibullK05La1.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; - -namespace FastRng.Float.Distributions -{ - public sealed class WeibullK05La1 : Distribution - { - private const float K = 0.5f; - private const float LAMBDA = 1.0f; - private const float CONSTANT = 0.221034183615129f; - - public WeibullK05La1(IRandom rng) : base(rng) - { - } - - private protected override float ShapeFunction(float x) => CONSTANT * ( (K / LAMBDA) * MathF.Pow(x / LAMBDA, K - 1.0f) * MathF.Exp(-MathF.Pow(x/LAMBDA, K))); - } -} \ No newline at end of file diff --git a/FastRng/Float/IRandom.cs b/FastRng/Float/IRandom.cs deleted file mode 100644 index 893f170..0000000 --- a/FastRng/Float/IRandom.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; -using FastRng.Float.Distributions; - -namespace FastRng.Float -{ - /// - /// Interface for random number generators. - /// - public interface IRandom : IDisposable - { - /// - /// Returns a uniform distributed pseudo-random number from the interval (0,1]. - /// This means, the result 0 is impossible, whereas 1 is possible. - /// - /// - /// This method is thread-safe. You can consume numbers from the same generator - /// by using multiple threads at the same time. - /// - /// An optional cancellation token. - public ValueTask GetUniform(CancellationToken cancel = default); - } -} \ No newline at end of file diff --git a/FastRng/Float/MathTools.cs b/FastRng/Float/MathTools.cs deleted file mode 100644 index eb3e5ae..0000000 --- a/FastRng/Float/MathTools.cs +++ /dev/null @@ -1,83 +0,0 @@ -using System; - -namespace FastRng.Float -{ - /// - /// Provides some mathematical function, which are not available within in the .NET framework. - /// - public static class MathTools - { - private static readonly float SQRT_2 = MathF.Sqrt(2.0f); - private static readonly float SQRT_PI = MathF.Sqrt(MathF.PI); - - /// - /// The mathematical gamma function. - /// - /// The value for which you want calculate gamma. - public static float Gamma(float z) - { - // Source: http://rosettacode.org/wiki/Gamma_function#Go - - const float F1 = 6.5f; - const float A1 = .99999999999980993f; - const float A2 = 676.5203681218851f; - const float A3 = 1259.1392167224028f; - const float A4 = 771.32342877765313f; - const float A5 = 176.61502916214059f; - const float A6 = 12.507343278686905f; - const float A7 = .13857109526572012f; - const float A8 = 9.9843695780195716e-6f; - const float A9 = 1.5056327351493116e-7f; - - var t = z + F1; - var x = A1 + - A2 / z - - A3 / (z + 1) + - A4 / (z + 2) - - A5 / (z + 3) + - A6 / (z + 4) - - A7 / (z + 5) + - A8 / (z + 6) + - A9 / (z + 7); - - return MathTools.SQRT_2 * MathTools.SQRT_PI * MathF.Pow(t, z - 0.5f) * MathF.Exp(-t) * x; - } - - /// - /// The mathematical factorial function for floating-point numbers. - /// - /// The value, for which you want to know the factorial. - public static float Factorial(float x) => MathTools.Gamma(x + 1.0f); - - /// - /// The mathematical factorial function for integer numbers. - /// - /// The value, for which you want to know the factorial. - /// Throws, when x is greater than 20. Due to limitations of 64bit ulong type. - public static ulong Factorial(uint x) - { - if (x > 20) - throw new ArgumentOutOfRangeException(nameof(x), $"Cannot compute {x}!, since ulong.max is 18_446_744_073_709_551_615."); - - ulong accumulator = 1; - for (uint factor = 1; factor <= x; factor++) - accumulator *= factor; - - return accumulator; - } - - /// - /// The mathematical factorial function for integer numbers. - /// - /// The value, for which you want to know the factorial. - /// Throws, when x is greater than 20. Due to limitations - /// of 64bit ulong type. Throws also, when x is less than 0. - public static ulong Factorial(int x) - { - if(x < 0) - throw new ArgumentOutOfRangeException(nameof(x), "Given value must be greater as zero."); - - return MathTools.Factorial((uint) x); - } - } -} \ No newline at end of file diff --git a/FastRng/Float/MultiThreadedRng.cs b/FastRng/Float/MultiThreadedRng.cs deleted file mode 100644 index b6e9b1e..0000000 --- a/FastRng/Float/MultiThreadedRng.cs +++ /dev/null @@ -1,358 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Diagnostics.CodeAnalysis; -using System.Threading; -using System.Threading.Tasks; -using FastRng.Float.Distributions; - -namespace FastRng.Float -{ - /// - /// A fast multi-threaded pseudo random number generator. - /// - /// - /// Please note, that Math.NET's (https://www.mathdotnet.com/) random number generator is in some situations faster. - /// Unlike Math.NET, MultiThreadedRng is multi-threaded and async. Consumers can await the next number without - /// blocking resources. Additionally, consumers can use a token to cancel e.g. timeout an operation as well.

- /// - /// MultiThreadedRng using a shape fitter (a rejection sampler) to enforce arbitrary shapes of probabilities for - /// desired distributions. By using the shape fitter, it is even easy to define discontinuous, arbitrary functions - /// as shapes. Any consumer can define and use own distributions.

- /// - /// This class uses the George Marsaglia's MWC algorithm. The algorithm's implementation based loosely on John D. - /// Cook's (johndcook.com) implementation (https://www.codeproject.com/Articles/25172/Simple-Random-Number-Generation). - /// Thanks John for the inspiration.

- /// - /// Please notice: When using the debug environment, MultiThreadedRng uses a smaller buffer size. Please ensure, - /// that the production environment uses a release build, though. - ///
- public sealed class MultiThreadedRng : IRandom, IDisposable - { - #if DEBUG - private const int BUFFER_SIZE = 10_000; - #else - private const int BUFFER_SIZE = 1_000_000; - #endif - - // The queue size means, how many buffer we store in a queue at the same time: - private const int QUEUE_SIZE = 2; - - // Gets used to stop the producer threads: - private readonly CancellationTokenSource producerTokenSource = new CancellationTokenSource(); - - // The time a thread waits e.g. to check if the queue needs a new buffer: - private readonly TimeSpan waiter = TimeSpan.FromMilliseconds(10); - - // The first queue, where to store buffers of random uint numbers: - private readonly ConcurrentQueue queueIntegers = new ConcurrentQueue(); - - // The second queue, where to store buffers of uniform random floating point numbers: - private readonly ConcurrentQueue queueFloats = new ConcurrentQueue(); - - // The uint producer thread: - private Thread producerRandomUint; - - // The uniform float producer thread: - private Thread producerRandomUniformDistributedFloat; - - // Variable w and z for the uint generator. Both get used - // as seeding variable as well (cf. constructors) - private uint mW; - private uint mZ; - - // This is the current buffer for the consumer side i.e. the public interfaces: - private float[] currentBuffer = Array.Empty(); - - // The current pointer to the next current buffer's address to read from: - private int currentBufferPointer = BUFFER_SIZE; - - #region Constructors - - /// - /// Creates a multi-threaded random number generator. - /// - /// - /// This constructor uses the user's current local time - /// to derive necessary parameters for the generator. - /// Thus, the results are depending on the time, where - /// the generator was created. - /// - public MultiThreadedRng() - { - // - // Initialize the mW and mZ by using - // the system's time. - // - var now = DateTime.Now; - var ticks = now.Ticks; - this.mW = (uint) (ticks >> 16); - this.mZ = (uint) (ticks % 4_294_967_296); - this.StartProducerThreads(); - } - - /// - /// Creates a multi-threaded random number generator. - /// - /// - /// A multi-threaded random number generator created by this constructor is - /// deterministic. It's behaviour is not depending on the time of its creation.

- /// - /// Please note: Although the number generator and all distributions are deterministic, - /// the behavior of the consuming application might be non-deterministic. This is possible if - /// the application with multiple threads consumes the numbers. The scheduling of the threads - /// is up to the operating system and might not be predictable. - ///
- /// A seed value to generate a deterministic generator. - public MultiThreadedRng(uint seedU) - { - this.mW = seedU; - this.mZ = 362_436_069; - this.StartProducerThreads(); - } - - /// - /// Creates a multi-threaded random number generator. - /// - /// - /// A multi-threaded random number generator created by this constructor is - /// deterministic. It's behaviour is not depending on the time of its creation.

- /// - /// Please note: Although the number generator and all distributions are deterministic, - /// the behavior of the consuming application might be non-deterministic. This is possible if - /// the application with multiple threads consumes the numbers. The scheduling of the threads - /// is up to the operating system and might not be predictable. - ///
- /// The first seed value. - /// The second seed value. - public MultiThreadedRng(uint seedU, uint seedV) - { - this.mW = seedU; - this.mZ = seedV; - this.StartProducerThreads(); - } - - private void StartProducerThreads() - { - this.producerRandomUint = new Thread(() => this.RandomProducerUint(this.producerTokenSource.Token)) {IsBackground = true}; - this.producerRandomUint.Start(); - this.producerRandomUniformDistributedFloat = new Thread(() => this.RandomProducerUniformDistributedFloat(this.producerTokenSource.Token)) {IsBackground = true}; - this.producerRandomUniformDistributedFloat.Start(); - } - - #endregion - - #region Producers - - [ExcludeFromCodeCoverage] - private async void RandomProducerUint(CancellationToken cancellationToken) - { - try - { - while (!cancellationToken.IsCancellationRequested) - { - // A local next buffer, which gets filled next: - var nextBuffer = new uint[BUFFER_SIZE]; - - // Produce the necessary number of random uints: - for (var n = 0; n < nextBuffer.Length && !cancellationToken.IsCancellationRequested; n++) - { - this.mZ = 36_969 * (this.mZ & 65_535) + (this.mZ >> 16); - this.mW = 18_000 * (this.mW & 65_535) + (this.mW >> 16); - nextBuffer[n] = (this.mZ << 16) + this.mW; - } - - // Inside this loop, we try to enqueue the produced buffer: - while (!cancellationToken.IsCancellationRequested) - { - try - { - // Ensure, that we do not produce more buffers, as configured: - if (this.queueIntegers.Count < QUEUE_SIZE) - { - this.queueIntegers.Enqueue(nextBuffer); - break; - } - - // The queue was full. Wait a moment and try it again: - await Task.Delay(this.waiter, cancellationToken); - } - catch (TaskCanceledException) - { - // The producers should be stopped: - return; - } - } - } - } - catch (OperationCanceledException) - { - } - } - - [ExcludeFromCodeCoverage] - private async void RandomProducerUniformDistributedFloat(CancellationToken cancellationToken) - { - try - { - while (!cancellationToken.IsCancellationRequested) - { - // A local source buffer of uints: - uint[] bufferSource = null; - - // Try to get the next source buffer: - while (!this.queueIntegers.TryDequeue(out bufferSource) && !cancellationToken.IsCancellationRequested) - await Task.Delay(this.waiter, cancellationToken); - - // Case: The producers should be stopped: - if(bufferSource == null) - return; - - // A local buffer to fill with uniform floats: - var nextBuffer = new float[BUFFER_SIZE]; - - // Generate the necessary number of floats: - for (var n = 0; n < nextBuffer.Length && !cancellationToken.IsCancellationRequested; n++) - nextBuffer[n] = (bufferSource[n] + 1.0f) * 2.328306435454494e-10f; - - // Inside this loop, we try to enqueue the generated buffer: - while (!cancellationToken.IsCancellationRequested) - { - try - { - // Ensure, that the queue contains only the configured number of buffers: - if (this.queueFloats.Count < QUEUE_SIZE) - { - this.queueFloats.Enqueue(nextBuffer); - break; - } - - // The queue was full. Wait a moment and try it again: - await Task.Delay(this.waiter, cancellationToken); - } - catch (TaskCanceledException) - { - return; - } - } - } - } - catch (OperationCanceledException) - { - } - } - - #endregion - - #region Implementing interface - - /// - /// Returns a uniform distributed pseudo-random number from the interval (0,1]. - /// This means, the result 0 is impossible, whereas 1 is possible. - /// - /// - /// This method is thread-safe. You can consume numbers from the same generator - /// by using multiple threads at the same time. - /// - /// An optional cancellation token. - public async ValueTask GetUniform(CancellationToken cancel = default) - { - while (!cancel.IsCancellationRequested) - { - // Check, if we need a new buffer to read from: - if (this.currentBufferPointer >= BUFFER_SIZE) - { - // Create a local copy of the current buffer's pointer: - var currentBufferReference = this.currentBuffer; - - // Here, we store the next buffer until we implement it: - var nextBuffer = Array.Empty(); - - // Try to get the next buffer from the queue: - while (this.currentBufferPointer >= BUFFER_SIZE && currentBufferReference == this.currentBuffer && !this.queueFloats.TryDequeue(out nextBuffer)) - { - // - // Case: There is no next buffer available. - // Must wait for producer(s) to provide next. - // - try - { - await Task.Delay(this.waiter, cancel); - } - catch (TaskCanceledException) - { - // - // Case: The consumer cancelled the request. - // - return float.NaN; - } - } - - // - // Note: In general, it does not matter if the following compare-exchange is successful. - // 1st case: It was successful -- everything is fine. But we are responsible to re-set the currentBufferPointer. - // 2nd case: It was not successful. This means, that another thread was successful, though. - // That case is fine as well. But we would loose one buffer of work. Thus, we - // check for this case and preserve the buffer full of work. - // - - // Try to implement the dequeued buffer without locking other threads: - if (Interlocked.CompareExchange(ref this.currentBuffer, nextBuffer, currentBufferReference) != currentBufferReference) - { - // - // Case: Another thread updated the buffer already. - // Thus, we enqueue our copy of the next buffer to preserve it. - // - this.queueFloats.Enqueue(nextBuffer); - - // Next? We can go ahead and yield a random number... - } - else - { - // - // Case: We updated the buffer. - // - this.currentBufferPointer = 0; - - // Next? We can go ahead and yield a random number... - } - } - - // Made a local copy of the current pointer: - var myPointer = this.currentBufferPointer; - - // Increment the pointer for the next thread or call: - var nextPointer = myPointer + 1; - - // Try to update the pointer without locking other threads: - if (Interlocked.CompareExchange(ref this.currentBufferPointer, nextPointer, myPointer) == myPointer) - { - // - // Case: Success. We updated the pointer and, thus, can use the pointer to read a number. - // - return this.currentBuffer[myPointer]; - } - - // - // Case: Another thread updated the pointer already. Must restart the process - // to get a random number. - // - } - - // - // Case: The consumer cancelled the request. - // - return float.NaN; - } - - private void StopProducer() => this.producerTokenSource.Cancel(); - - /// - /// Disposes this generator. It is important to dispose a generator, - /// when it is no longer needed. Otherwise, the background threads - /// are still running. - /// - public void Dispose() => this.StopProducer(); - - #endregion - } -} \ No newline at end of file diff --git a/FastRng/Float/ShapeFitter.cs b/FastRng/Float/ShapeFitter.cs deleted file mode 100644 index d17cedd..0000000 --- a/FastRng/Float/ShapeFitter.cs +++ /dev/null @@ -1,78 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; -using FastRng.Float.Distributions; - -namespace FastRng.Float -{ - /// - /// ShapeFitter is a rejection sampler, cf. https://en.wikipedia.org/wiki/Rejection_sampling - /// - public sealed class ShapeFitter - { - private readonly float[] probabilities; - private readonly IRandom rng; - private readonly float max; - private readonly float sampleSize; - private readonly IDistribution uniform; - - /// - /// Creates a shape fitter instance. - /// - /// The function which describes the desired shape. - /// The random number generator instance to use. - /// The number of sampling steps to sample the given function. - public ShapeFitter(Func shapeFunction, IRandom rng, ushort sampleSize = 50) - { - this.rng = rng; - this.uniform = new Uniform(rng); - this.sampleSize = sampleSize; - this.probabilities = new float[sampleSize]; - - var sampleStepSize = 1.0f / sampleSize; - var nextStep = 0.0f + sampleStepSize; - var maxValue = 0.0f; - for (var n = 0; n < sampleSize; n++) - { - this.probabilities[n] = shapeFunction(nextStep); - if (this.probabilities[n] > maxValue) - maxValue = this.probabilities[n]; - - nextStep += sampleStepSize; - } - - this.max = maxValue; - } - - /// - /// Returns a random number regarding the given shape. - /// - /// An optional cancellation token. - /// The next value regarding the given shape. - public async ValueTask NextNumber(CancellationToken token = default) - { - while (!token.IsCancellationRequested) - { - var x = await this.rng.GetUniform(token); - if (float.IsNaN(x)) - return x; - - var nextBucket = (int)MathF.Floor(x * this.sampleSize); - if (nextBucket >= this.probabilities.Length) - nextBucket = this.probabilities.Length - 1; - - var threshold = this.probabilities[nextBucket]; - var y = await this.uniform.NextNumber(0.0f, this.max, token); - if (float.IsNaN(y)) - return y; - - if(y > threshold) - continue; - - return x; - } - - return float.NaN; - } - } -} \ No newline at end of file diff --git a/FastRng/IRandom.cs b/FastRng/IRandom.cs new file mode 100644 index 0000000..a455859 --- /dev/null +++ b/FastRng/IRandom.cs @@ -0,0 +1,21 @@ +using System; +using System.Numerics; +using System.Threading; + +namespace FastRng; + +/// +/// Interface for random number generators. +/// +public interface IRandom : IDisposable where TNum : IFloatingPointIeee754 +{ + /// + /// Returns a uniform distributed pseudo-random number from the interval (0,1]. + /// This means, the result 0 is impossible, whereas 1 is possible. + /// + /// + /// This method is thread-safe. You can consume numbers from the same generator + /// by using multiple threads at the same time. + /// + public TNum GetUniform(CancellationToken cancel = default); +} \ No newline at end of file diff --git a/FastRng/MathToolsFloatingPoint.cs b/FastRng/MathToolsFloatingPoint.cs new file mode 100644 index 0000000..7f2e7bf --- /dev/null +++ b/FastRng/MathToolsFloatingPoint.cs @@ -0,0 +1,62 @@ +using System.Numerics; + +namespace FastRng; + +/// +/// Provides some mathematical function, which are not available within in .NET itself. +/// +public static class MathToolsFloatingPoint where TNum : IFloatingPointIeee754, IAdditionOperators +{ + private static readonly TNum SQRT_2 = TNum.Sqrt(TNum.One + TNum.One); + private static readonly TNum SQRT_PI = TNum.Sqrt(TNum.Pi); + + // Source: http://rosettacode.org/wiki/Gamma_function#Go + private static readonly TNum F1 = TNum.CreateChecked(6.5f); + private static readonly TNum A1 = TNum.CreateChecked(.99999999999980993f); + private static readonly TNum A2 = TNum.CreateChecked(676.5203681218851f); + private static readonly TNum A3 = TNum.CreateChecked(1259.1392167224028f); + private static readonly TNum A4 = TNum.CreateChecked(771.32342877765313f); + private static readonly TNum A5 = TNum.CreateChecked(176.61502916214059f); + private static readonly TNum A6 = TNum.CreateChecked(12.507343278686905f); + private static readonly TNum A7 = TNum.CreateChecked(.13857109526572012f); + private static readonly TNum A8 = TNum.CreateChecked(9.9843695780195716e-6f); + private static readonly TNum A9 = TNum.CreateChecked(1.5056327351493116e-7f); + + private static readonly TNum CONST1 = TNum.One; + private static readonly TNum CONST2 = CONST1 + TNum.One; + private static readonly TNum CONST3 = CONST2 + TNum.One; + private static readonly TNum CONST4 = CONST3 + TNum.One; + private static readonly TNum CONST5 = CONST4 + TNum.One; + private static readonly TNum CONST6 = CONST5 + TNum.One; + private static readonly TNum CONST7 = CONST6 + TNum.One; + + private static readonly TNum CONST_HALF = TNum.CreateChecked(0.5f); + + /// + /// The mathematical gamma function. + /// + /// The value for which you want calculate gamma. + public static TNum Gamma(TNum z) + { + // Source: http://rosettacode.org/wiki/Gamma_function#Go + + var t = z + F1; + var x = A1 + + A2 / z - + A3 / (z + CONST1) + + A4 / (z + CONST2) - + A5 / (z + CONST3) + + A6 / (z + CONST4) - + A7 / (z + CONST5) + + A8 / (z + CONST6) + + A9 / (z + CONST7); + + return SQRT_2 * SQRT_PI * TNum.Pow(t, z - CONST_HALF) * TNum.Exp(-t) * x; + } + + /// + /// The mathematical factorial function for floating-point numbers. + /// + /// The value, for which you want to know the factorial. + public static TNum Factorial(TNum x) => Gamma(x + CONST1); +} \ No newline at end of file diff --git a/FastRng/MathToolsInteger.cs b/FastRng/MathToolsInteger.cs new file mode 100644 index 0000000..d2db474 --- /dev/null +++ b/FastRng/MathToolsInteger.cs @@ -0,0 +1,26 @@ +using System; + +namespace FastRng; + +/// +/// Provides some mathematical function, which are not available within in .NET itself. +/// +public static class MathToolsInteger +{ + /// + /// The mathematical factorial function for integer numbers. + /// + /// The value, for which you want to know the factorial. + /// Throws, when x is greater than 20. Due to limitations of 64bit ulong type. + public static ulong Factorial(uint x) + { + if (x > 20) + throw new ArgumentOutOfRangeException(nameof(x), $"Cannot compute {x}!, since ulong.max is 18_446_744_073_709_551_615."); + + ulong accumulator = 1; + for (uint factor = 1; factor <= x; factor++) + accumulator *= factor; + + return accumulator; + } +} \ No newline at end of file diff --git a/FastRng/MultiChannelRng.cs b/FastRng/MultiChannelRng.cs new file mode 100644 index 0000000..aff1fbc --- /dev/null +++ b/FastRng/MultiChannelRng.cs @@ -0,0 +1,168 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Numerics; +using System.Threading; +using System.Threading.Channels; + +namespace FastRng; + +public sealed class MultiChannelRng : IRandom, IDisposable where TNum : IFloatingPointIeee754, IAdditionOperators +{ +#if DEBUG + private const int BUFFER_SIZE = 1_000_000; +#else + private const int BUFFER_SIZE = 1_000_000; +#endif + + private readonly Channel channelIntegers = Channel.CreateBounded(new BoundedChannelOptions(capacity: BUFFER_SIZE * 2) { FullMode = BoundedChannelFullMode.Wait, SingleWriter = true, SingleReader = true }); + private readonly Channel channelFloats = Channel.CreateBounded(new BoundedChannelOptions(capacity: BUFFER_SIZE) { FullMode = BoundedChannelFullMode.Wait, SingleWriter = true, SingleReader = false }); + + private static readonly TNum CONST_FLOAT_CONVERSION = TNum.CreateChecked(2.328306435454494e-10f); + + // Gets used to stop the producer threads: + private readonly CancellationTokenSource producerTokenSource = new(); + + // The uint producer thread: + private Thread producerRandomUint; + + // The uniform float producer thread: + private Thread producerRandomUniformDistributedFloat; + + // Variable w and z for the uint generator. Both get used + // as seeding variable as well (cf. constructors) + private uint mW; + private uint mZ; + + #region Constructors + + /// + /// Creates a multi-threaded random number generator. + /// + /// + /// This constructor uses the user's current local time + /// to derive necessary parameters for the generator. + /// Thus, the results are depending on the time, where + /// the generator was created. + /// + public MultiChannelRng() + { + // + // Initialize the mW and mZ by using + // the system's time. + // + var now = DateTime.Now; + var ticks = now.Ticks; + this.mW = (uint) (ticks >> 16); + this.mZ = (uint) (ticks % 4_294_967_296); + this.StartProducerThreads(); + } + + /// + /// Creates a multi-threaded random number generator. + /// + /// + /// A multi-threaded random number generator created by this constructor is + /// deterministic. It's behaviour is not depending on the time of its creation.

+ /// + /// Please note: Although the number generator and all distributions are deterministic, + /// the behavior of the consuming application might be non-deterministic. This is possible if + /// the application with multiple threads consumes the numbers. The scheduling of the threads + /// is up to the operating system and might not be predictable. + ///
+ /// A seed value to generate a deterministic generator. + public MultiChannelRng(uint seedU) + { + this.mW = seedU; + this.mZ = 362_436_069; + this.StartProducerThreads(); + } + + /// + /// Creates a multi-threaded random number generator. + /// + /// + /// A multi-threaded random number generator created by this constructor is + /// deterministic. It's behaviour is not depending on the time of its creation.

+ /// + /// Please note: Although the number generator and all distributions are deterministic, + /// the behavior of the consuming application might be non-deterministic. This is possible if + /// the application with multiple threads consumes the numbers. The scheduling of the threads + /// is up to the operating system and might not be predictable. + ///
+ /// The first seed value. + /// The second seed value. + public MultiChannelRng(uint seedU, uint seedV) + { + this.mW = seedU; + this.mZ = seedV; + this.StartProducerThreads(); + } + + private void StartProducerThreads() + { + this.producerRandomUint = new Thread(() => this.RandomProducerUint(this.producerTokenSource.Token)) {IsBackground = true}; + this.producerRandomUint.Start(); + this.producerRandomUniformDistributedFloat = new Thread(() => this.RandomProducerUniformDistributedFloat(this.producerTokenSource.Token)) {IsBackground = true}; + this.producerRandomUniformDistributedFloat.Start(); + } + + #endregion + + #region Producers + + [ExcludeFromCodeCoverage] + private async void RandomProducerUint(CancellationToken cancellationToken) + { + try + { + while (!cancellationToken.IsCancellationRequested) + { + this.mZ = 36_969 * (this.mZ & 65_535) + (this.mZ >> 16); + this.mW = 18_000 * (this.mW & 65_535) + (this.mW >> 16); + await this.channelIntegers.Writer.WriteAsync((this.mZ << 16) + this.mW, cancellationToken); + } + } + catch (OperationCanceledException) + { + } + } + + [ExcludeFromCodeCoverage] + private async void RandomProducerUniformDistributedFloat(CancellationToken cancellationToken) + { + try + { + while (!cancellationToken.IsCancellationRequested) + { + await this.channelFloats.Writer.WriteAsync((TNum.CreateChecked(await this.channelIntegers.Reader.ReadAsync(cancellationToken)) + TNum.One) * CONST_FLOAT_CONVERSION, cancellationToken); + } + } + catch (OperationCanceledException) + { + } + } + + #endregion + + #region Implementing interfaces + + #region Implementation of IDisposable + + private void StopProducer() => this.producerTokenSource.Cancel(); + + public void Dispose() => this.StopProducer(); + + #endregion + + #region Implementation of IRandom + + public TNum GetUniform(CancellationToken cancel = default) + { + var valueTask = this.channelFloats.Reader.ReadAsync(cancel); + return valueTask.AsTask().Result; + } + + #endregion + + #endregion +} \ No newline at end of file diff --git a/FastRng/MultiThreadedRng.cs b/FastRng/MultiThreadedRng.cs new file mode 100644 index 0000000..a965bb8 --- /dev/null +++ b/FastRng/MultiThreadedRng.cs @@ -0,0 +1,321 @@ +using System; +using System.Collections.Concurrent; +using System.Diagnostics.CodeAnalysis; +using System.Numerics; +using System.Threading; +using System.Threading.Tasks; + +namespace FastRng; + +/// +/// A fast multi-threaded pseudo random number generator. +/// +/// +/// Please note, that Math.NET's (https://www.mathdotnet.com/) random number generator is in some situations faster. +/// Unlike Math.NET, MultiThreadedRng is multi-threaded. Consumers can use a token to cancel e.g. timeout an operation.

+/// +/// MultiThreadedRng using a shape fitter (a rejection sampler) to enforce arbitrary shapes of probabilities for +/// desired distributions. By using the shape fitter, it is even easy to define discontinuous, arbitrary functions +/// as shapes. Any consumer can define and use own distributions.

+/// +/// This class uses the George Marsaglia's MWC algorithm. The algorithm's implementation based loosely on John D. +/// Cook's (johndcook.com) implementation (https://www.codeproject.com/Articles/25172/Simple-Random-Number-Generation). +/// Thanks John for the inspiration.

+/// +/// Please notice: When using the debug environment, MultiThreadedRng might uses a smaller buffer size. Please ensure, +/// that the production environment uses a release build, though. +///
+public sealed class MultiThreadedRng : IRandom, IDisposable where TNum : IFloatingPointIeee754, IAdditionOperators +{ +#if DEBUG + private const int BUFFER_SIZE = 1_000_000; +#else + private const int BUFFER_SIZE = 1_000_000; +#endif + + // The queue size means, how many buffer we store in a queue at the same time: + private const int QUEUE_SIZE_FLOAT = 2; + + // The queue size means, how many buffer we store in a queue at the same time: + private const int QUEUE_SIZE_INT = QUEUE_SIZE_FLOAT * 2; + + private static readonly TNum CONST_FLOAT_CONVERSION = TNum.CreateChecked(2.328306435454494e-10f); + private static readonly object LOCKER = new(); + + // Gets used to stop the producer threads: + private readonly CancellationTokenSource producerTokenSource = new(); + + // The time a thread waits e.g. to check if the queue needs a new buffer: + private readonly TimeSpan waiter = TimeSpan.FromMilliseconds(10); + + // The first queue, where to store buffers of random uint numbers: + private readonly ConcurrentQueue queueIntegers = new(); + + // The second queue, where to store buffers of uniform random floating point numbers: + private readonly ConcurrentQueue queueFloats = new(); + + // The uint producer thread: + private Thread producerRandomUint; + + // The uniform float producer thread: + private Thread producerRandomUniformDistributedFloat; + + // Variable w and z for the uint generator. Both get used + // as seeding variable as well (cf. constructors) + private uint mW; + private uint mZ; + + // This is the current buffer for the consumer side i.e. the public interfaces: + private TNum[] currentBuffer = Array.Empty(); + + // The current pointer to the next current buffer's address to read from: + private int currentBufferPointer = BUFFER_SIZE; + + #region Constructors + + /// + /// Creates a multi-threaded random number generator. + /// + /// + /// This constructor uses the user's current local time + /// to derive necessary parameters for the generator. + /// Thus, the results are depending on the time, where + /// the generator was created. + /// + public MultiThreadedRng() + { + // + // Initialize the mW and mZ by using + // the system's time. + // + var now = DateTime.Now; + var ticks = now.Ticks; + this.mW = (uint) (ticks >> 16); + this.mZ = (uint) (ticks % 4_294_967_296); + this.StartProducerThreads(); + } + + /// + /// Creates a multi-threaded random number generator. + /// + /// + /// A multi-threaded random number generator created by this constructor is + /// deterministic. It's behaviour is not depending on the time of its creation.

+ /// + /// Please note: Although the number generator and all distributions are deterministic, + /// the behavior of the consuming application might be non-deterministic. This is possible if + /// the application with multiple threads consumes the numbers. The scheduling of the threads + /// is up to the operating system and might not be predictable. + ///
+ /// A seed value to generate a deterministic generator. + public MultiThreadedRng(uint seedU) + { + this.mW = seedU; + this.mZ = 362_436_069; + this.StartProducerThreads(); + } + + /// + /// Creates a multi-threaded random number generator. + /// + /// + /// A multi-threaded random number generator created by this constructor is + /// deterministic. It's behaviour is not depending on the time of its creation.

+ /// + /// Please note: Although the number generator and all distributions are deterministic, + /// the behavior of the consuming application might be non-deterministic. This is possible if + /// the application with multiple threads consumes the numbers. The scheduling of the threads + /// is up to the operating system and might not be predictable. + ///
+ /// The first seed value. + /// The second seed value. + public MultiThreadedRng(uint seedU, uint seedV) + { + this.mW = seedU; + this.mZ = seedV; + this.StartProducerThreads(); + } + + private void StartProducerThreads() + { + this.producerRandomUint = new Thread(() => this.RandomProducerUint(this.producerTokenSource.Token)) {IsBackground = true}; + this.producerRandomUint.Start(); + this.producerRandomUniformDistributedFloat = new Thread(() => this.RandomProducerUniformDistributedFloat(this.producerTokenSource.Token)) {IsBackground = true}; + this.producerRandomUniformDistributedFloat.Start(); + } + + #endregion + + #region Producers + + [ExcludeFromCodeCoverage] + private async void RandomProducerUint(CancellationToken cancellationToken) + { + try + { + while (!cancellationToken.IsCancellationRequested) + { + // A local next buffer, which gets filled next: + var nextBuffer = new uint[BUFFER_SIZE]; + + // Produce the necessary number of random uints: + for (var n = 0; n < nextBuffer.Length && !cancellationToken.IsCancellationRequested; n++) + { + this.mZ = 36_969 * (this.mZ & 65_535) + (this.mZ >> 16); + this.mW = 18_000 * (this.mW & 65_535) + (this.mW >> 16); + nextBuffer[n] = (this.mZ << 16) + this.mW; + } + + // Inside this loop, we try to enqueue the produced buffer: + while (!cancellationToken.IsCancellationRequested) + { + try + { + // Ensure, that we do not produce more buffers, as configured: + if (this.queueIntegers.Count < QUEUE_SIZE_INT) + { + this.queueIntegers.Enqueue(nextBuffer); + break; + } + + // The queue was full. Wait a moment and try it again: + await Task.Delay(this.waiter, cancellationToken); + } + catch (TaskCanceledException) + { + // The producers should be stopped: + return; + } + } + } + } + catch (OperationCanceledException) + { + } + } + + [ExcludeFromCodeCoverage] + private async void RandomProducerUniformDistributedFloat(CancellationToken cancellationToken) + { + try + { + while (!cancellationToken.IsCancellationRequested) + { + // A local source buffer of uints: + uint[] bufferSource = null; + + // Try to get the next source buffer: + while (!this.queueIntegers.TryDequeue(out bufferSource) && !cancellationToken.IsCancellationRequested) + await Task.Delay(this.waiter, cancellationToken); + + // Case: The producers should be stopped: + if(bufferSource == null) + return; + + // A local buffer to fill with uniform floats: + var nextBuffer = new TNum[BUFFER_SIZE]; + + // Generate the necessary number of floats: + for (var n = 0; n < nextBuffer.Length && !cancellationToken.IsCancellationRequested; n++) + nextBuffer[n] = (TNum.CreateChecked(bufferSource[n]) + TNum.One) * CONST_FLOAT_CONVERSION; + + // Inside this loop, we try to enqueue the generated buffer: + while (!cancellationToken.IsCancellationRequested) + { + try + { + // Ensure, that the queue contains only the configured number of buffers: + if (this.queueFloats.Count < QUEUE_SIZE_FLOAT) + { + this.queueFloats.Enqueue(nextBuffer); + break; + } + + // The queue was full. Wait a moment and try it again: + await Task.Delay(this.waiter, cancellationToken); + } + catch (TaskCanceledException) + { + return; + } + } + } + } + catch (OperationCanceledException) + { + } + } + + #endregion + + #region Implementing interface + + /// + /// Returns a uniform distributed pseudo-random number from the interval (0,1]. + /// This means, the result 0 is impossible, whereas 1 is possible. + /// + /// + /// This method is thread-safe. You can consume numbers from the same generator + /// by using multiple threads at the same time. + /// + public TNum GetUniform(CancellationToken cancel = default) + { + if (cancel.IsCancellationRequested) + return TNum.NaN; + + Start: + + // Check if we have to load the next buffer: + if (this.currentBufferPointer >= BUFFER_SIZE) + { + // We have to get the next buffer from the queue. This is a critical + // section, because we have to ensure, that only one thread at a time + // can get the next buffer: + lock (LOCKER) + { + // We are might not the first thread, which has to get the next buffer. + // When some other thread has already got the next buffer, the pointer + // was already reset to zero. In this case, we start over again: + if(this.currentBufferPointer < BUFFER_SIZE) + goto Start; + + while (!this.queueFloats.TryDequeue(out this.currentBuffer)) + { + if (cancel.IsCancellationRequested) + return TNum.NaN; + + Thread.Sleep(TimeSpan.FromMilliseconds(6)); + } + + // Reset the pointer for the next thread or call: + this.currentBufferPointer = 0; + } + } + + // Made a local copy of the current pointer: + var myPointer = this.currentBufferPointer; + + // Increment the pointer for the next thread or call: + var nextPointer = myPointer + 1; + + // Try to update the pointer without locking other threads: + if (Interlocked.CompareExchange(ref this.currentBufferPointer, nextPointer, myPointer) != myPointer) + goto Start; + + // + // Case: Success. We updated the pointer and, thus, can use the read number. + // + return this.currentBuffer[myPointer]; + } + + private void StopProducer() => this.producerTokenSource.Cancel(); + + /// + /// Disposes this generator. It is important to dispose a generator, + /// when it is no longer needed. Otherwise, the background threads + /// are still running. + /// + public void Dispose() => this.StopProducer(); + + #endregion +} \ No newline at end of file diff --git a/FastRng/ShapeFitter.cs b/FastRng/ShapeFitter.cs new file mode 100644 index 0000000..f7a604d --- /dev/null +++ b/FastRng/ShapeFitter.cs @@ -0,0 +1,77 @@ +using System; +using System.Numerics; +using System.Threading; +using FastRng.Distributions; + +namespace FastRng; + +/// +/// ShapeFitter is a rejection sampler, cf. https://en.wikipedia.org/wiki/Rejection_sampling +/// +public sealed class ShapeFitter where TNum : IFloatingPointIeee754, IDivisionOperators +{ + private readonly TNum[] probabilities; + private readonly IRandom rng; + private readonly TNum max; + private readonly TNum sampleSize; + private readonly IDistribution uniform; + + /// + /// Creates a shape fitter instance. + /// + /// The function which describes the desired shape. + /// The random number generator instance to use. + /// The number of sampling steps to sample the given function. + public ShapeFitter(Func shapeFunction, IRandom rng, ushort sampleSize = 50) + { + this.rng = rng; + this.uniform = new Uniform(rng); + this.sampleSize = TNum.CreateChecked(sampleSize); + this.probabilities = new TNum[sampleSize]; + + var sampleStepSize = TNum.One / TNum.CreateChecked(sampleSize); + var nextStep = TNum.Zero + sampleStepSize; + var maxValue = TNum.Zero; + for (var n = 0; n < sampleSize; n++) + { + this.probabilities[n] = shapeFunction(nextStep); + if (this.probabilities[n] > maxValue) + maxValue = this.probabilities[n]; + + nextStep += sampleStepSize; + } + + this.max = maxValue; + } + + /// + /// Returns a random number regarding the given shape. + /// + /// An optional cancellation token. + /// The next value regarding the given shape. + public TNum NextNumber(CancellationToken token = default) + { + while (!token.IsCancellationRequested) + { + var x = this.rng.GetUniform(token); + if (TNum.IsNaN(x)) + return x; + + var nextBucket = int.CreateChecked(TNum.Floor(x * this.sampleSize)); + if (nextBucket >= this.probabilities.Length) + nextBucket = this.probabilities.Length - 1; + + var threshold = this.probabilities[nextBucket]; + var y = this.uniform.NextNumber(TNum.Zero, this.max, token); + if (TNum.IsNaN(y)) + return y; + + if(y > threshold) + continue; + + return x; + } + + return TNum.NaN; + } +} \ No newline at end of file diff --git a/FastRngTests/DecisionTester.cs b/FastRngTests/DecisionTester.cs new file mode 100644 index 0000000..e584522 --- /dev/null +++ b/FastRngTests/DecisionTester.cs @@ -0,0 +1,60 @@ +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Threading.Tasks; +using FastRng; +using FastRng.Distributions; +using NUnit.Framework; + +namespace FastRngTests; + +[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 (!dist.HasDecisionBeenMade(0.0f, 0.1f)) neededCoinTossesA++; + for(var n = 0; n < 100; n++) while (!dist.HasDecisionBeenMade(0.5f, 0.6f)) neededCoinTossesB++; + for(var n = 0; n < 100; n++) while (!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 WeibullK05La1(rng); + + var neededCoinTossesA = 0; + var neededCoinTossesB = 0; + var neededCoinTossesC = 0; + + for(var n = 0; n < 100; n++) while (!dist.HasDecisionBeenMade(0.0f, 0.1f)) neededCoinTossesA++; + for(var n = 0; n < 100; n++) while (!dist.HasDecisionBeenMade(0.5f, 0.6f)) neededCoinTossesB++; + for(var n = 0; n < 100; n++) while (!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/Distributions/BetaA2B2.cs b/FastRngTests/Distributions/BetaA2B2.cs new file mode 100644 index 0000000..af000c5 --- /dev/null +++ b/FastRngTests/Distributions/BetaA2B2.cs @@ -0,0 +1,82 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using FastRng; +using NUnit.Framework; + +namespace FastRngTests.Distributions; + +[ExcludeFromCodeCoverage] +public class BetaA2B2 +{ + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestBetaDistribution01() + { + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Distributions.BetaA2B2(rng); + var fqa = new FrequencyAnalysis(); + + for (var n = 0; n < 100_000; n++) + fqa.CountThis(dist.NextNumber()); + + var result = fqa.NormalizeAndPlotEvents(TestContext.WriteLine); + + Assert.That(result[0], Is.EqualTo(0.0396f).Within(0.3f)); + Assert.That(result[1], Is.EqualTo(0.0784f).Within(0.3f)); + Assert.That(result[2], Is.EqualTo(0.1164f).Within(0.3f)); + + Assert.That(result[21], Is.EqualTo(0.6864f).Within(0.3f)); + Assert.That(result[22], Is.EqualTo(0.7084f).Within(0.3f)); + Assert.That(result[23], Is.EqualTo(0.7296f).Within(0.3f)); + + Assert.That(result[50], Is.EqualTo(0.9996f).Within(0.3f)); + + Assert.That(result[75], Is.EqualTo(0.7296f).Within(0.3f)); + Assert.That(result[85], Is.EqualTo(0.4816f).Within(0.3f)); + Assert.That(result[90], Is.EqualTo(0.3276f).Within(0.3f)); + + Assert.That(result[97], Is.EqualTo(0.0784f).Within(0.3f)); + Assert.That(result[98], Is.EqualTo(0.0396f).Within(0.3f)); + Assert.That(result[99], Is.EqualTo(0.0000f).Within(0.3f)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestBetaGeneratorWithRange01() + { + using var rng = new MultiThreadedRng(); + var samples = new float[1_000]; + var dist = new FastRng.Distributions.BetaA2B2(rng); + for (var n = 0; n < samples.Length; n++) + samples[n] = dist.NextNumber(-1.0f, 1.0f); + + Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range"); + Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range"); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestBetaGeneratorWithRange02() + { + using var rng = new MultiThreadedRng(); + var samples = new float[1_000]; + var dist = new FastRng.Distributions.BetaA2B2(rng); + for (var n = 0; n < samples.Length; n++) + samples[n] = dist.NextNumber(0.0f, 1.0f); + + Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range"); + Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range"); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void NoRandomNumberGenerator01() + { + Assert.Throws(() => new FastRng.Distributions.BetaA2B2(null)); + } +} \ No newline at end of file diff --git a/FastRngTests/Distributions/BetaA2B5.cs b/FastRngTests/Distributions/BetaA2B5.cs new file mode 100644 index 0000000..ea37a88 --- /dev/null +++ b/FastRngTests/Distributions/BetaA2B5.cs @@ -0,0 +1,82 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using FastRng; +using NUnit.Framework; + +namespace FastRngTests.Distributions; + +[ExcludeFromCodeCoverage] +public class BetaA2B5 +{ + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestBetaDistribution01() + { + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Distributions.BetaA2B5(rng); + var fqa = new FrequencyAnalysis(); + + for (var n = 0; n < 100_000; n++) + fqa.CountThis(dist.NextNumber()); + + var result = fqa.NormalizeAndPlotEvents(TestContext.WriteLine); + + Assert.That(result[0], Is.EqualTo(0.11719271f).Within(0.3f)); + Assert.That(result[1], Is.EqualTo(0.22505783f).Within(0.3f)); + Assert.That(result[2], Is.EqualTo(0.32401717f).Within(0.3f)); + + Assert.That(result[21], Is.EqualTo(0.99348410f).Within(0.3f)); + Assert.That(result[22], Is.EqualTo(0.98639433f).Within(0.3f)); + Assert.That(result[23], Is.EqualTo(0.97684451f).Within(0.3f)); + + Assert.That(result[50], Is.EqualTo(0.35868592f).Within(0.3f)); + + Assert.That(result[75], Is.EqualTo(0.03076227f).Within(0.03f)); + Assert.That(result[85], Is.EqualTo(0.00403061f).Within(0.03f)); + Assert.That(result[90], Is.EqualTo(0.00109800f).Within(0.01f)); + + Assert.That(result[97], Is.EqualTo(0.00000191f).Within(0.000003f)); + Assert.That(result[98], Is.EqualTo(0.00000012f).Within(0.0000003f)); + Assert.That(result[99], Is.EqualTo(0.00000000f).Within(0.0000003f)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestBetaGeneratorWithRange01() + { + using var rng = new MultiThreadedRng(); + var samples = new float[1_000]; + var dist = new FastRng.Distributions.BetaA2B5(rng); + for (var n = 0; n < samples.Length; n++) + samples[n] = dist.NextNumber(-1.0f, 1.0f); + + Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range"); + Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range"); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestBetaGeneratorWithRange02() + { + using var rng = new MultiThreadedRng(); + var samples = new float[1_000]; + var dist = new FastRng.Distributions.BetaA2B5(rng); + for (var n = 0; n < samples.Length; n++) + samples[n] = dist.NextNumber(0.0f, 1.0f); + + Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range"); + Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range"); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void NoRandomNumberGenerator01() + { + Assert.Throws(() => new FastRng.Distributions.BetaA2B5(null)); + } +} \ No newline at end of file diff --git a/FastRngTests/Distributions/BetaA5B2.cs b/FastRngTests/Distributions/BetaA5B2.cs new file mode 100644 index 0000000..10f0012 --- /dev/null +++ b/FastRngTests/Distributions/BetaA5B2.cs @@ -0,0 +1,82 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using FastRng; +using NUnit.Framework; + +namespace FastRngTests.Distributions; + +[ExcludeFromCodeCoverage] +public class BetaA5B2 +{ + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestBetaDistribution01() + { + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Distributions.BetaA5B2(rng); + var fqa = new FrequencyAnalysis(); + + for (var n = 0; n < 100_000; n++) + fqa.CountThis(dist.NextNumber()); + + var result = fqa.NormalizeAndPlotEvents(TestContext.WriteLine); + + Assert.That(result[0], Is.EqualTo(0.0000001f).Within(0.0000003f)); + Assert.That(result[1], Is.EqualTo(0.0000019f).Within(0.00001f)); + Assert.That(result[2], Is.EqualTo(0.0000096f).Within(0.0004f)); + + Assert.That(result[21], Is.EqualTo(0.0222918f).Within(0.03f)); + Assert.That(result[22], Is.EqualTo(0.0262883f).Within(0.03f)); + Assert.That(result[23], Is.EqualTo(0.0307623f).Within(0.03f)); + + Assert.That(result[50], Is.EqualTo(0.4044237f).Within(0.2f)); + + Assert.That(result[75], Is.EqualTo(0.9768445f).Within(0.15f)); + Assert.That(result[85], Is.EqualTo(0.9552714f).Within(0.15f)); + Assert.That(result[90], Is.EqualTo(0.8004420f).Within(0.35f)); + + Assert.That(result[97], Is.EqualTo(0.2250578f).Within(0.03f)); + Assert.That(result[98], Is.EqualTo(0.1171927f).Within(0.03f)); + Assert.That(result[99], Is.EqualTo(0f).Within(0.0004f)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestBetaGeneratorWithRange01() + { + using var rng = new MultiThreadedRng(); + var samples = new float[1_000]; + var dist = new FastRng.Distributions.BetaA5B2(rng); + for (var n = 0; n < samples.Length; n++) + samples[n] = dist.NextNumber(-1.0f, 1.0f); + + Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range"); + Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range"); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestBetaGeneratorWithRange02() + { + using var rng = new MultiThreadedRng(); + var samples = new float[1_000]; + var dist = new FastRng.Distributions.BetaA5B2(rng); + for (var n = 0; n < samples.Length; n++) + samples[n] = dist.NextNumber(0.0f, 1.0f); + + Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range"); + Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range"); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void NoRandomNumberGenerator01() + { + Assert.Throws(() => new FastRng.Distributions.BetaA5B2(null)); + } +} \ No newline at end of file diff --git a/FastRngTests/Distributions/CauchyLorentzX0.cs b/FastRngTests/Distributions/CauchyLorentzX0.cs new file mode 100644 index 0000000..2e5cae9 --- /dev/null +++ b/FastRngTests/Distributions/CauchyLorentzX0.cs @@ -0,0 +1,85 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using FastRng; +using NUnit.Framework; + +namespace FastRngTests.Distributions; + +[ExcludeFromCodeCoverage] +public class CauchyLorentzX0 +{ + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestCauchyDistribution01() + { + // The properties of the cauchy distribution cannot be tested by mean, media or variance, + // cf. https://en.wikipedia.org/wiki/Cauchy_distribution#Explanation_of_undefined_moments + + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Distributions.CauchyLorentzX0(rng); + var fqa = new FrequencyAnalysis(); + + for (var n = 0; n < 100_000; n++) + fqa.CountThis(dist.NextNumber()); + + var result = fqa.NormalizeAndPlotEvents(TestContext.WriteLine); + + Assert.That(result[0], Is.EqualTo(0.976990739772031f).Within(0.06f)); + Assert.That(result[1], Is.EqualTo(0.948808314586299f).Within(0.06f)); + Assert.That(result[2], Is.EqualTo(0.905284997403441f).Within(0.06f)); + + Assert.That(result[21], Is.EqualTo(0.168965864241396f).Within(0.04f)); + Assert.That(result[22], Is.EqualTo(0.156877686354491f).Within(0.04f)); + Assert.That(result[23], Is.EqualTo(0.145970509936354f).Within(0.04f)); + + Assert.That(result[50], Is.EqualTo(0.036533159835978f).Within(0.01f)); + + Assert.That(result[75], Is.EqualTo(0.016793067514802f).Within(0.01f)); + Assert.That(result[85], Is.EqualTo(0.01316382933791f).Within(0.005f)); + Assert.That(result[90], Is.EqualTo(0.011773781734516f).Within(0.005f)); + + Assert.That(result[97], Is.EqualTo(0.010168596941156f).Within(0.005f)); + Assert.That(result[98], Is.EqualTo(0.009966272570142f).Within(0.005f)); + Assert.That(result[99], Is.EqualTo(0.00976990739772f).Within(0.005f)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestCauchyGeneratorWithRange01() + { + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Distributions.CauchyLorentzX0(rng); + var samples = new float[1_000]; + for (var n = 0; n < samples.Length; n++) + samples[n] = dist.NextNumber(-1.0f, 1.0f); + + Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min is out of range"); + Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range"); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestCauchyGeneratorWithRange02() + { + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Distributions.CauchyLorentzX0(rng); + var samples = new float[1_000]; + for (var n = 0; n < samples.Length; n++) + samples[n] = dist.NextNumber(0.0f, 1.0f); + + Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range"); + Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range"); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void NoRandomNumberGenerator01() + { + Assert.Throws(() => new FastRng.Distributions.CauchyLorentzX0(null)); + } +} \ No newline at end of file diff --git a/FastRngTests/Distributions/CauchyLorentzX1.cs b/FastRngTests/Distributions/CauchyLorentzX1.cs new file mode 100644 index 0000000..70c8efc --- /dev/null +++ b/FastRngTests/Distributions/CauchyLorentzX1.cs @@ -0,0 +1,85 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using FastRng; +using NUnit.Framework; + +namespace FastRngTests.Distributions; + +[ExcludeFromCodeCoverage] +public class CauchyLorentzX1 +{ + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestCauchyDistribution01() + { + // The properties of the cauchy distribution cannot be tested by mean, media or variance, + // cf. https://en.wikipedia.org/wiki/Cauchy_distribution#Explanation_of_undefined_moments + + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Distributions.CauchyLorentzX1(rng); + var fqa = new FrequencyAnalysis(); + + for (var n = 0; n < 100_000; n++) + fqa.CountThis(dist.NextNumber()); + + var result = fqa.NormalizeAndPlotEvents(TestContext.WriteLine); + + Assert.That(result[0], Is.EqualTo(0.009966272570142f).Within(0.003f)); + Assert.That(result[1], Is.EqualTo(0.010168596941156f).Within(0.004f)); + Assert.That(result[2], Is.EqualTo(0.010377123221893f).Within(0.005f)); + + Assert.That(result[21], Is.EqualTo(0.015956672819692f).Within(0.005f)); + Assert.That(result[22], Is.EqualTo(0.016366904083094f).Within(0.005f)); + Assert.That(result[23], Is.EqualTo(0.016793067514802f).Within(0.005f)); + + Assert.That(result[50], Is.EqualTo(0.039454644029179f).Within(0.015f)); + + Assert.That(result[75], Is.EqualTo(0.145970509936354f).Within(0.03f)); + Assert.That(result[85], Is.EqualTo(0.333365083503296f).Within(0.1f)); + Assert.That(result[90], Is.EqualTo(0.545171628270584f).Within(0.1f)); + + Assert.That(result[97], Is.EqualTo(0.948808314586302f).Within(0.06f)); + Assert.That(result[98], Is.EqualTo(0.976990739772032f).Within(0.03f)); + Assert.That(result[99], Is.EqualTo(0.986760647169751f).Within(0.02f)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestCauchyGeneratorWithRange01() + { + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Distributions.CauchyLorentzX0(rng); + var samples = new float[1_000]; + for (var n = 0; n < samples.Length; n++) + samples[n] = dist.NextNumber(-1.0f, 1.0f); + + Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min is out of range"); + Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range"); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestCauchyGeneratorWithRange02() + { + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Distributions.CauchyLorentzX0(rng); + var samples = new float[1_000]; + for (var n = 0; n < samples.Length; n++) + samples[n] = dist.NextNumber(0.0f, 1.0f); + + Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range"); + Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range"); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void NoRandomNumberGenerator01() + { + Assert.Throws(() => new FastRng.Distributions.CauchyLorentzX1(null)); + } +} \ No newline at end of file diff --git a/FastRngTests/Distributions/ChiSquareK1.cs b/FastRngTests/Distributions/ChiSquareK1.cs new file mode 100644 index 0000000..631cc0b --- /dev/null +++ b/FastRngTests/Distributions/ChiSquareK1.cs @@ -0,0 +1,85 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using FastRng; +using NUnit.Framework; + +namespace FastRngTests.Distributions; + +[ExcludeFromCodeCoverage] +public class ChiSquareK1 +{ + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestChiSquareDistribution01() + { + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Distributions.ChiSquareK1(rng); + var fqa = new FrequencyAnalysis(); + + for (var n = 0; n < 100_000; n++) + { + var value = dist.NextNumber(); + fqa.CountThis(value); + } + + var result = fqa.NormalizeAndPlotEvents(TestContext.WriteLine); + + Assert.That(result[0], Is.EqualTo(1.00032041964207f).Within(0.004f)); + Assert.That(result[1], Is.EqualTo(0.70380551227703f).Within(0.05f)); + Assert.That(result[2], Is.EqualTo(0.571788691668126f).Within(0.05f)); + + Assert.That(result[21], Is.EqualTo(0.192011337664754f).Within(0.07f)); + Assert.That(result[22], Is.EqualTo(0.186854182385981f).Within(0.07f)); + Assert.That(result[23], Is.EqualTo(0.182007652359976f).Within(0.07f)); + + Assert.That(result[50], Is.EqualTo(0.109088865614875f).Within(0.06f)); + + Assert.That(result[75], Is.EqualTo(0.07886274821701f).Within(0.02f)); + Assert.That(result[85], Is.EqualTo(0.070520397849883f).Within(0.02f)); + Assert.That(result[90], Is.EqualTo(0.066863009640287f).Within(0.02f)); + + Assert.That(result[97], Is.EqualTo(0.062214737436948f).Within(0.02f)); + Assert.That(result[98], Is.EqualTo(0.061590997922187f).Within(0.02f)); + Assert.That(result[99], Is.EqualTo(0.060976622578824f).Within(0.02f)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestChiSquareGeneratorWithRange01() + { + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Distributions.ChiSquareK1(rng); + var samples = new float[1_000]; + for (var n = 0; n < samples.Length; n++) + samples[n] = dist.NextNumber(-1.0f, 1.0f); + + Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range"); + Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range"); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestChiSquareGeneratorWithRange02() + { + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Distributions.ChiSquareK1(rng); + var samples = new float[1_000]; + for (var n = 0; n < samples.Length; n++) + samples[n] = dist.NextNumber(0.0f, 1.0f); + + Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range"); + Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range"); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void NoRandomNumberGenerator01() + { + Assert.Throws(() => new FastRng.Distributions.ChiSquareK1(null)); + } +} \ No newline at end of file diff --git a/FastRngTests/Distributions/ChiSquareK10.cs b/FastRngTests/Distributions/ChiSquareK10.cs new file mode 100644 index 0000000..a011209 --- /dev/null +++ b/FastRngTests/Distributions/ChiSquareK10.cs @@ -0,0 +1,85 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using FastRng; +using NUnit.Framework; + +namespace FastRngTests.Distributions; + +[ExcludeFromCodeCoverage] +public class ChiSquareK10 +{ + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestChiSquareDistribution01() + { + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Distributions.ChiSquareK10(rng); + var fqa = new FrequencyAnalysis(); + + for (var n = 0; n < 100_000; n++) + { + var value = dist.NextNumber(); + fqa.CountThis(value); + } + + var result = fqa.NormalizeAndPlotEvents(TestContext.WriteLine); + + Assert.That(result[0], Is.EqualTo(0.0000000164021588f).Within(0.0000002f)); + Assert.That(result[1], Is.EqualTo(0.0000002611256437f).Within(0.000003f)); + Assert.That(result[2], Is.EqualTo(0.0000013153553250f).Within(0.00002f)); + + Assert.That(result[21], Is.EqualTo(0.003459320622874f).Within(0.005f)); + Assert.That(result[22], Is.EqualTo(0.004111875573379f).Within(0.005f)); + Assert.That(result[23], Is.EqualTo(0.004850674298859f).Within(0.005f)); + + Assert.That(result[50], Is.EqualTo(0.086418773275056f).Within(0.05f)); + + Assert.That(result[75], Is.EqualTo(0.376092741436046f).Within(0.08f)); + Assert.That(result[85], Is.EqualTo(0.586569751611096f).Within(0.08f)); + Assert.That(result[90], Is.EqualTo(0.717189736168766f).Within(0.08f)); + + Assert.That(result[97], Is.EqualTo(0.931477764640217f).Within(0.08f)); + Assert.That(result[98], Is.EqualTo(0.965244855212136f).Within(0.08f)); + Assert.That(result[99], Is.EqualTo(0.999827884370044f).Within(0.08f)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestChiSquareGeneratorWithRange01() + { + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Distributions.ChiSquareK10(rng); + var samples = new float[1_000]; + for (var n = 0; n < samples.Length; n++) + samples[n] = dist.NextNumber(-1.0f, 1.0f); + + Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range"); + Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range"); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestChiSquareGeneratorWithRange02() + { + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Distributions.ChiSquareK10(rng); + var samples = new float[1_000]; + for (var n = 0; n < samples.Length; n++) + samples[n] = dist.NextNumber(0.0f, 1.0f); + + Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range"); + Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range"); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void NoRandomNumberGenerator01() + { + Assert.Throws(() => new FastRng.Distributions.ChiSquareK10(null)); + } +} \ No newline at end of file diff --git a/FastRngTests/Distributions/ChiSquareK4.cs b/FastRngTests/Distributions/ChiSquareK4.cs new file mode 100644 index 0000000..73eee7e --- /dev/null +++ b/FastRngTests/Distributions/ChiSquareK4.cs @@ -0,0 +1,82 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using FastRng; +using NUnit.Framework; + +namespace FastRngTests.Distributions; + +[ExcludeFromCodeCoverage] +public class ChiSquareK4 +{ + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestChiSquareDistribution01() + { + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Distributions.ChiSquareK4(rng); + var fqa = new FrequencyAnalysis(); + + for (var n = 0; n < 100_000; n++) + fqa.CountThis(dist.NextNumber()); + + var result = fqa.NormalizeAndPlotEvents(TestContext.WriteLine); + + Assert.That(result[0], Is.EqualTo(0.016417705906679f).Within(0.02f)); + Assert.That(result[1], Is.EqualTo(0.032671644513723f).Within(0.02f)); + Assert.That(result[2], Is.EqualTo(0.048763041010352f).Within(0.02f)); + + Assert.That(result[21], Is.EqualTo(0.32518779111264f).Within(0.05f)); + Assert.That(result[22], Is.EqualTo(0.338273451612642f).Within(0.05f)); + Assert.That(result[23], Is.EqualTo(0.351220492939994f).Within(0.05f)); + + Assert.That(result[50], Is.EqualTo(0.65209223303425f).Within(0.08f)); + + Assert.That(result[75], Is.EqualTo(0.857562207152294f).Within(0.099f)); + Assert.That(result[85], Is.EqualTo(0.923072405412387f).Within(0.099f)); + Assert.That(result[90], Is.EqualTo(0.952623623874265f).Within(0.099f)); + + Assert.That(result[97], Is.EqualTo(0.990616879396201f).Within(0.099f)); + Assert.That(result[98], Is.EqualTo(0.995734077068522f).Within(0.099f)); + Assert.That(result[99], Is.EqualTo(1.00077558852585f).Within(0.1f)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestChiSquareGeneratorWithRange01() + { + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Distributions.ChiSquareK4(rng); + var samples = new float[1_000]; + for (var n = 0; n < samples.Length; n++) + samples[n] = dist.NextNumber(-1.0f, 1.0f); + + Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range"); + Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range"); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestChiSquareGeneratorWithRange02() + { + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Distributions.ChiSquareK4(rng); + var samples = new float[1_000]; + for (var n = 0; n < samples.Length; n++) + samples[n] = dist.NextNumber(0.0f, 1.0f); + + Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range"); + Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range"); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void NoRandomNumberGenerator01() + { + Assert.Throws(() => new FastRng.Distributions.ChiSquareK4(null)); + } +} \ No newline at end of file diff --git a/FastRngTests/Distributions/ExponentialLa10.cs b/FastRngTests/Distributions/ExponentialLa10.cs new file mode 100644 index 0000000..5cf0033 --- /dev/null +++ b/FastRngTests/Distributions/ExponentialLa10.cs @@ -0,0 +1,82 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using FastRng; +using NUnit.Framework; + +namespace FastRngTests.Distributions; + +[ExcludeFromCodeCoverage] +public class ExponentialLa10 +{ + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestExponentialDistribution01() + { + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Distributions.ExponentialLa10(rng); + var fqa = new FrequencyAnalysis(); + + for (var n = 0; n < 100_000; n++) + fqa.CountThis(dist.NextNumber()); + + var result = fqa.NormalizeAndPlotEvents(TestContext.WriteLine); + + Assert.That(result[0], Is.EqualTo(1.00075018434777f).Within(0.05f)); + Assert.That(result[1], Is.EqualTo(0.905516212904248f).Within(0.05f)); + Assert.That(result[2], Is.EqualTo(0.81934495207398f).Within(0.05f)); + + Assert.That(result[21], Is.EqualTo(0.122548293148741f).Within(0.12f)); + Assert.That(result[22], Is.EqualTo(0.110886281157421f).Within(0.12f)); + Assert.That(result[23], Is.EqualTo(0.10033405633809f).Within(0.12f)); + + Assert.That(result[50], Is.EqualTo(0.00674300170146f).Within(0.005f)); + + Assert.That(result[75], Is.EqualTo(0.000553499285385f).Within(0.001f)); + Assert.That(result[85], Is.EqualTo(0.000203621007796f).Within(0.001f)); + Assert.That(result[90], Is.EqualTo(0.00012350238419f).Within(0.001f)); + + Assert.That(result[97], Is.EqualTo(0.0000613294689720f).Within(0.0008f)); + Assert.That(result[98], Is.EqualTo(0.0000554931983541f).Within(0.0008f)); + Assert.That(result[99], Is.EqualTo(0.0000502123223173f).Within(0.0008f)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestExponentialGeneratorWithRange01() + { + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Distributions.ExponentialLa10(rng); + var samples = new float[1_000]; + for (var n = 0; n < samples.Length; n++) + samples[n] = dist.NextNumber(-1.0f, 1.0f); + + Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range"); + Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range"); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestExponentialGeneratorWithRange02() + { + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Distributions.ExponentialLa10(rng); + var samples = new float[1_000]; + for (var n = 0; n < samples.Length; n++) + samples[n] = dist.NextNumber(0.0f, 1.0f); + + Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range"); + Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range"); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void NoRandomNumberGenerator01() + { + Assert.Throws(() => new FastRng.Distributions.ExponentialLa10(null)); + } +} \ No newline at end of file diff --git a/FastRngTests/Distributions/ExponentialLa5.cs b/FastRngTests/Distributions/ExponentialLa5.cs new file mode 100644 index 0000000..37820f1 --- /dev/null +++ b/FastRngTests/Distributions/ExponentialLa5.cs @@ -0,0 +1,82 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using FastRng; +using NUnit.Framework; + +namespace FastRngTests.Distributions; + +[ExcludeFromCodeCoverage] +public class ExponentialLa5 +{ + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestExponentialDistribution01() + { + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Distributions.ExponentialLa5(rng); + var fqa = new FrequencyAnalysis(); + + for (var n = 0; n < 100_000; n++) + fqa.CountThis(dist.NextNumber()); + + var result = fqa.NormalizeAndPlotEvents(TestContext.WriteLine); + + Assert.That(result[0], Is.EqualTo(1.0002177398625f).Within(0.05f)); + Assert.That(result[1], Is.EqualTo(0.951436545064811f).Within(0.05f)); + Assert.That(result[2], Is.EqualTo(0.905034437210948f).Within(0.05f)); + + Assert.That(result[21], Is.EqualTo(0.35001394450853f).Within(0.05f)); + Assert.That(result[22], Is.EqualTo(0.332943563002074f).Within(0.05f)); + Assert.That(result[23], Is.EqualTo(0.31670571382568f).Within(0.05f)); + + Assert.That(result[50], Is.EqualTo(0.082102871800213f).Within(0.01f)); + + Assert.That(result[75], Is.EqualTo(0.023522866606758f).Within(0.01f)); + Assert.That(result[85], Is.EqualTo(0.014267339801329f).Within(0.01f)); + Assert.That(result[90], Is.EqualTo(0.011111415409621f).Within(0.01f)); + + Assert.That(result[97], Is.EqualTo(0.007830082099077f).Within(0.008f)); + Assert.That(result[98], Is.EqualTo(0.007448204488898f).Within(0.008f)); + Assert.That(result[99], Is.EqualTo(0.007084951269538f).Within(0.008f)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestExponentialGeneratorWithRange01() + { + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Distributions.ExponentialLa5(rng); + var samples = new float[1_000]; + for (var n = 0; n < samples.Length; n++) + samples[n] = dist.NextNumber(-1.0f, 1.0f); + + Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range"); + Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range"); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestExponentialGeneratorWithRange02() + { + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Distributions.ExponentialLa5(rng); + var samples = new float[1_000]; + for (var n = 0; n < samples.Length; n++) + samples[n] = dist.NextNumber(0.0f, 1.0f); + + Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range"); + Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range"); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void NoRandomNumberGenerator01() + { + Assert.Throws(() => new FastRng.Distributions.ExponentialLa5(null)); + } +} \ No newline at end of file diff --git a/FastRngTests/Distributions/GammaA5B15.cs b/FastRngTests/Distributions/GammaA5B15.cs new file mode 100644 index 0000000..405acfe --- /dev/null +++ b/FastRngTests/Distributions/GammaA5B15.cs @@ -0,0 +1,82 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using FastRng; +using NUnit.Framework; + +namespace FastRngTests.Distributions; + +[ExcludeFromCodeCoverage] +public class GammaA5B15 +{ + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestGammaDistribution01() + { + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Distributions.GammaA5B15(rng); + var fra = new FrequencyAnalysis(); + + for (var n = 0; n < 100_000; n++) + fra.CountThis(dist.NextNumber()); + + var result = fra.NormalizeAndPlotEvents(TestContext.WriteLine); + + Assert.That(result[0], Is.EqualTo(0.0000929594237282f).Within(0.0008f)); + Assert.That(result[1], Is.EqualTo(0.0012801746797876f).Within(0.002f)); + Assert.That(result[2], Is.EqualTo(0.0055781488254349f).Within(0.004f)); + + Assert.That(result[21], Is.EqualTo(0.9331608887752720f).Within(0.09f)); + Assert.That(result[22], Is.EqualTo(0.9594734828891280f).Within(0.09f)); + Assert.That(result[23], Is.EqualTo(0.9790895765535350f).Within(0.09f)); + + Assert.That(result[50], Is.EqualTo(0.3478287795336570f).Within(0.06f)); + + Assert.That(result[75], Is.EqualTo(0.0403399049422936f).Within(0.009f)); + Assert.That(result[85], Is.EqualTo(0.0163628388658126f).Within(0.009f)); + Assert.That(result[90], Is.EqualTo(0.0097147611446660f).Within(0.005f)); + + Assert.That(result[97], Is.EqualTo(0.0041135143233153f).Within(0.008f)); + Assert.That(result[98], Is.EqualTo(0.0036872732029996f).Within(0.008f)); + Assert.That(result[99], Is.EqualTo(0.0033038503429554f).Within(0.008f)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestGammaGeneratorWithRange01() + { + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Distributions.GammaA5B15(rng); + var samples = new float[1_000]; + for (var n = 0; n < samples.Length; n++) + samples[n] = dist.NextNumber(-1.0f, 1.0f); + + Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min is out of range"); + Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range"); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestGammaGeneratorWithRange02() + { + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Distributions.GammaA5B15(rng); + var samples = new float[1_000]; + for (var n = 0; n < samples.Length; n++) + samples[n] = dist.NextNumber(0.0f, 1.0f); + + Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range"); + Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range"); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void NoRandomNumberGenerator01() + { + Assert.Throws(() => new FastRng.Distributions.GammaA5B15(null)); + } +} \ No newline at end of file diff --git a/FastRngTests/Distributions/InverseExponentialLa10.cs b/FastRngTests/Distributions/InverseExponentialLa10.cs new file mode 100644 index 0000000..f42b561 --- /dev/null +++ b/FastRngTests/Distributions/InverseExponentialLa10.cs @@ -0,0 +1,82 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using FastRng; +using NUnit.Framework; + +namespace FastRngTests.Distributions; + +[ExcludeFromCodeCoverage] +public class InverseExponentialLa10 +{ + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestExponentialDistribution01() + { + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Distributions.InverseExponentialLa10(rng); + var fqa = new FrequencyAnalysis(); + + for (var n = 0; n < 100_000; n++) + fqa.CountThis(dist.NextNumber()); + + var result = fqa.NormalizeAndPlotEvents(TestContext.WriteLine); + + Assert.That(result[0], Is.EqualTo(0.0000501746820562f).Within(0.0003f)); + Assert.That(result[1], Is.EqualTo(0.0000554515994322f).Within(0.0003f)); + Assert.That(result[2], Is.EqualTo(0.0000612834950532f).Within(0.0003f)); + + Assert.That(result[21], Is.EqualTo(0.00040973497898f).Within(0.00045f)); + Assert.That(result[22], Is.EqualTo(0.000452827182887f).Within(0.00050f)); + Assert.That(result[23], Is.EqualTo(0.000500451433441f).Within(0.0006f)); + + Assert.That(result[50], Is.EqualTo(0.007446583070924f).Within(0.003f)); + + Assert.That(result[75], Is.EqualTo(0.090717953289412f).Within(0.02f)); + Assert.That(result[85], Is.EqualTo(0.246596963941606f).Within(0.05f)); + Assert.That(result[90], Is.EqualTo(0.406569659740598f).Within(0.08f)); + + Assert.That(result[97], Is.EqualTo(0.81873075307798f).Within(0.08f)); + Assert.That(result[98], Is.EqualTo(0.904837418035957f).Within(0.08f)); + Assert.That(result[99], Is.EqualTo(0.999999999999999f).Within(0.08f)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestExponentialGeneratorWithRange01() + { + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Distributions.InverseExponentialLa10(rng); + var samples = new float[1_000]; + for (var n = 0; n < samples.Length; n++) + samples[n] = dist.NextNumber(-1.0f, 1.0f); + + Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range"); + Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range"); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestExponentialGeneratorWithRange02() + { + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Distributions.InverseExponentialLa10(rng); + var samples = new float[1_000]; + for (var n = 0; n < samples.Length; n++) + samples[n] = dist.NextNumber(0.0f, 1.0f); + + Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range"); + Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range"); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void NoRandomNumberGenerator01() + { + Assert.Throws(() => new FastRng.Distributions.InverseExponentialLa10(null)); + } +} \ No newline at end of file diff --git a/FastRngTests/Distributions/InverseExponentialLa5.cs b/FastRngTests/Distributions/InverseExponentialLa5.cs new file mode 100644 index 0000000..35ec819 --- /dev/null +++ b/FastRngTests/Distributions/InverseExponentialLa5.cs @@ -0,0 +1,82 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using FastRng; +using NUnit.Framework; + +namespace FastRngTests.Distributions; + +[ExcludeFromCodeCoverage] +public class InverseExponentialLa5 +{ + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestExponentialDistribution01() + { + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Distributions.InverseExponentialLa5(rng); + var fqa = new FrequencyAnalysis(); + + for (var n = 0; n < 100_000; n++) + fqa.CountThis(dist.NextNumber()); + + var result = fqa.NormalizeAndPlotEvents(TestContext.WriteLine); + + Assert.That(result[0], Is.EqualTo(0.007083408929052f).Within(0.008f)); + Assert.That(result[1], Is.EqualTo(0.007446583070924f).Within(0.008f)); + Assert.That(result[2], Is.EqualTo(0.007828377549226f).Within(0.008f)); + + Assert.That(result[21], Is.EqualTo(0.020241911445804f).Within(0.05f)); + Assert.That(result[22], Is.EqualTo(0.021279736438377f).Within(0.05f)); + Assert.That(result[23], Is.EqualTo(0.022370771856166f).Within(0.05f)); + + Assert.That(result[50], Is.EqualTo(0.08629358649937f).Within(0.02f)); + + Assert.That(result[75], Is.EqualTo(0.301194211912202f).Within(0.03f)); + Assert.That(result[85], Is.EqualTo(0.496585303791409f).Within(0.05f)); + Assert.That(result[90], Is.EqualTo(0.637628151621772f).Within(0.06f)); + + Assert.That(result[97], Is.EqualTo(0.904837418035959f).Within(0.08f)); + Assert.That(result[98], Is.EqualTo(0.951229424500713f).Within(0.08f)); + Assert.That(result[99], Is.EqualTo(1f).Within(0.08f)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestExponentialGeneratorWithRange01() + { + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Distributions.InverseExponentialLa5(rng); + var samples = new float[1_000]; + for (var n = 0; n < samples.Length; n++) + samples[n] = dist.NextNumber(-1.0f, 1.0f); + + Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range"); + Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range"); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestExponentialGeneratorWithRange02() + { + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Distributions.InverseExponentialLa5(rng); + var samples = new float[1_000]; + for (var n = 0; n < samples.Length; n++) + samples[n] = dist.NextNumber(0.0f, 1.0f); + + Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range"); + Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range"); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void NoRandomNumberGenerator01() + { + Assert.Throws(() => new FastRng.Distributions.InverseExponentialLa5(null)); + } +} \ No newline at end of file diff --git a/FastRngTests/Distributions/InverseGammaA3B05.cs b/FastRngTests/Distributions/InverseGammaA3B05.cs new file mode 100644 index 0000000..a79f50f --- /dev/null +++ b/FastRngTests/Distributions/InverseGammaA3B05.cs @@ -0,0 +1,82 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using FastRng; +using NUnit.Framework; + +namespace FastRngTests.Distributions; + +[ExcludeFromCodeCoverage] +public class InverseGammaA3B05 +{ + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestInverseGammaDistribution01() + { + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Distributions.InverseGammaA3B05(rng); + var fra = new FrequencyAnalysis(); + + for (var n = 0; n < 100_000; n++) + fra.CountThis(dist.NextNumber()); + + var result = fra.NormalizeAndPlotEvents(TestContext.WriteLine); + + Assert.That(result[0], Is.EqualTo(0.0000000000000003f).Within(0.0000001f)); + Assert.That(result[1], Is.EqualTo(0.0000011605257228f).Within(0.00001f)); + Assert.That(result[2], Is.EqualTo(0.0009536970016103f).Within(0.0015f)); + + Assert.That(result[21], Is.EqualTo(0.5880485243048120f).Within(0.05f)); + Assert.That(result[22], Is.EqualTo(0.5433842148912880f).Within(0.05f)); + Assert.That(result[23], Is.EqualTo(0.5017780549216030f).Within(0.05f)); + + Assert.That(result[50], Is.EqualTo(0.0741442015957425f).Within(0.009f)); + + Assert.That(result[75], Is.EqualTo(0.0207568945092484f).Within(0.006f)); + Assert.That(result[85], Is.EqualTo(0.0136661506653688f).Within(0.006f)); + Assert.That(result[90], Is.EqualTo(0.0112550619601327f).Within(0.006f)); + + Assert.That(result[97], Is.EqualTo(0.0087026933539773f).Within(0.005f)); + Assert.That(result[98], Is.EqualTo(0.0083995375385004f).Within(0.005f)); + Assert.That(result[99], Is.EqualTo(0.0081094156379928f).Within(0.005f)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestInverseGammaGeneratorWithRange01() + { + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Distributions.InverseGammaA3B05(rng); + var samples = new float[1_000]; + for (var n = 0; n < samples.Length; n++) + samples[n] = dist.NextNumber(-1.0f, 1.0f); + + Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range"); + Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range"); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestInverseGammaGeneratorWithRange02() + { + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Distributions.InverseGammaA3B05(rng); + var samples = new float[1_000]; + for (var n = 0; n < samples.Length; n++) + samples[n] = dist.NextNumber(0.0f, 1.0f); + + Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range"); + Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range"); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void NoRandomNumberGenerator01() + { + Assert.Throws(() => new FastRng.Distributions.InverseGammaA3B05(null)); + } +} \ No newline at end of file diff --git a/FastRngTests/Distributions/LaplaceB01M0.cs b/FastRngTests/Distributions/LaplaceB01M0.cs new file mode 100644 index 0000000..767c071 --- /dev/null +++ b/FastRngTests/Distributions/LaplaceB01M0.cs @@ -0,0 +1,82 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using FastRng; +using NUnit.Framework; + +namespace FastRngTests.Distributions; + +[ExcludeFromCodeCoverage] +public class LaplaceB01M0 +{ + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestLaplaceDistribution01() + { + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Distributions.LaplaceB01M0(rng); + var fra = new FrequencyAnalysis(); + + for (var n = 0; n < 100_000; n++) + fra.CountThis(dist.NextNumber()); + + var result = fra.NormalizeAndPlotEvents(TestContext.WriteLine); + + Assert.That(result[0], Is.EqualTo(1.0000000000000000f).Within(0.05f)); + Assert.That(result[1], Is.EqualTo(0.9048374180359590f).Within(0.05f)); + Assert.That(result[2], Is.EqualTo(0.8187307530779810f).Within(0.05f)); + + Assert.That(result[21], Is.EqualTo(0.1224564282529820f).Within(0.05f)); + Assert.That(result[22], Is.EqualTo(0.1108031583623340f).Within(0.05f)); + Assert.That(result[23], Is.EqualTo(0.1002588437228040f).Within(0.05f)); + + Assert.That(result[50], Is.EqualTo(0.0067379469990855f).Within(0.003f)); + + Assert.That(result[75], Is.EqualTo(0.0005530843701478f).Within(0.0015f)); + Assert.That(result[85], Is.EqualTo(0.0002034683690106f).Within(0.0015f)); + Assert.That(result[90], Is.EqualTo(0.0001234098040867f).Within(0.0015f)); + + Assert.That(result[97], Is.EqualTo(0.0000612834950532f).Within(0.0002f)); + Assert.That(result[98], Is.EqualTo(0.0000554515994322f).Within(0.0002f)); + Assert.That(result[99], Is.EqualTo(0.0000501746820562f).Within(0.0002f)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestLaplaceGeneratorWithRange01() + { + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Distributions.LaplaceB01M0(rng); + var samples = new float[1_000]; + for (var n = 0; n < samples.Length; n++) + samples[n] = dist.NextNumber(-1.0f, 1.0f); + + Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range"); + Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range"); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestLaplaceGeneratorWithRange02() + { + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Distributions.LaplaceB01M0(rng); + var samples = new float[1_000]; + for (var n = 0; n < samples.Length; n++) + samples[n] = dist.NextNumber(0.0f, 1.0f); + + Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range"); + Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range"); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void NoRandomNumberGenerator01() + { + Assert.Throws(() => new FastRng.Distributions.LaplaceB01M0(null)); + } +} \ No newline at end of file diff --git a/FastRngTests/Distributions/LaplaceB01M05.cs b/FastRngTests/Distributions/LaplaceB01M05.cs new file mode 100644 index 0000000..35d6e36 --- /dev/null +++ b/FastRngTests/Distributions/LaplaceB01M05.cs @@ -0,0 +1,82 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using FastRng; +using NUnit.Framework; + +namespace FastRngTests.Distributions; + +[ExcludeFromCodeCoverage] +public class LaplaceB01M05 +{ + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestLaplaceDistribution01() + { + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Distributions.LaplaceB01M05(rng); + var fra = new FrequencyAnalysis(); + + for (var n = 0; n < 100_000; n++) + fra.CountThis(dist.NextNumber()); + + var result = fra.NormalizeAndPlotEvents(TestContext.WriteLine); + + Assert.That(result[0], Is.EqualTo(0.0074465830709244f).Within(0.004f)); + Assert.That(result[1], Is.EqualTo(0.0082297470490200f).Within(0.004f)); + Assert.That(result[2], Is.EqualTo(0.0090952771016958f).Within(0.01f)); + + Assert.That(result[21], Is.EqualTo(0.0608100626252180f).Within(0.02f)); + Assert.That(result[22], Is.EqualTo(0.0672055127397498f).Within(0.02f)); + Assert.That(result[23], Is.EqualTo(0.0742735782143340f).Within(0.02f)); + + Assert.That(result[50], Is.EqualTo(1.0000000000000000f).Within(0.2f)); + + Assert.That(result[75], Is.EqualTo(0.0742735782143335f).Within(0.01f)); + Assert.That(result[85], Is.EqualTo(0.0273237224472924f).Within(0.01f)); + Assert.That(result[90], Is.EqualTo(0.0165726754017612f).Within(0.01f)); + + Assert.That(result[97], Is.EqualTo(0.0082297470490200f).Within(0.004f)); + Assert.That(result[98], Is.EqualTo(0.0074465830709243f).Within(0.004f)); + Assert.That(result[99], Is.EqualTo(0.0067379469990854f).Within(0.004f)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestLaplaceGeneratorWithRange01() + { + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Distributions.LaplaceB01M05(rng); + var samples = new float[1_000]; + for (var n = 0; n < samples.Length; n++) + samples[n] = dist.NextNumber(-1.0f, 1.0f); + + Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range"); + Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range"); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestLaplaceGeneratorWithRange02() + { + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Distributions.LaplaceB01M05(rng); + var samples = new float[1_000]; + for (var n = 0; n < samples.Length; n++) + samples[n] = dist.NextNumber(0.0f, 1.0f); + + Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range"); + Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range"); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void NoRandomNumberGenerator01() + { + Assert.Throws(() => new FastRng.Distributions.LaplaceB01M05(null)); + } +} \ No newline at end of file diff --git a/FastRngTests/Distributions/LogNormalS1M0.cs b/FastRngTests/Distributions/LogNormalS1M0.cs new file mode 100644 index 0000000..a52197c --- /dev/null +++ b/FastRngTests/Distributions/LogNormalS1M0.cs @@ -0,0 +1,82 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using FastRng; +using NUnit.Framework; + +namespace FastRngTests.Distributions; + +[ExcludeFromCodeCoverage] +public class LogNormalS1M0 +{ + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestLogNormalDistribution01() + { + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Distributions.LogNormalS1M0(rng); + var fra = new FrequencyAnalysis(); + + for (var n = 0; n < 100_000; n++) + fra.CountThis(dist.NextNumber()); + + var result = fra.NormalizeAndPlotEvents(TestContext.WriteLine); + + Assert.That(result[0], Is.EqualTo(0.001505531f).Within(0.003f)); + Assert.That(result[1], Is.EqualTo(0.014408709f).Within(0.01f)); + Assert.That(result[2], Is.EqualTo(0.043222256f).Within(0.02f)); + + Assert.That(result[21], Is.EqualTo(0.876212056f).Within(0.15f)); + Assert.That(result[22], Is.EqualTo(0.895582226f).Within(0.15f)); + Assert.That(result[23], Is.EqualTo(0.912837250f).Within(0.15f)); + + Assert.That(result[50], Is.EqualTo(0.948062005f).Within(0.2f)); + + Assert.That(result[75], Is.EqualTo(0.768584762f).Within(0.089f)); + Assert.That(result[85], Is.EqualTo(0.697303612f).Within(0.089f)); + Assert.That(result[90], Is.EqualTo(0.663570581f).Within(0.089f)); + + Assert.That(result[97], Is.EqualTo(0.618792767f).Within(0.089f)); + Assert.That(result[98], Is.EqualTo(0.612636410f).Within(0.089f)); + Assert.That(result[99], Is.EqualTo(0.606540679f).Within(0.089f)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestLogNormalGeneratorWithRange01() + { + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Distributions.LogNormalS1M0(rng); + var samples = new float[1_000]; + for (var n = 0; n < samples.Length; n++) + samples[n] = dist.NextNumber(-1.0f, 1.0f); + + Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range"); + Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range"); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestLogNormalGeneratorWithRange02() + { + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Distributions.LogNormalS1M0(rng); + var samples = new float[1_000]; + for (var n = 0; n < samples.Length; n++) + samples[n] = dist.NextNumber(0.0f, 1.0f); + + Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range"); + Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range"); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void NoRandomNumberGenerator01() + { + Assert.Throws(() => new FastRng.Distributions.LogNormalS1M0(null)); + } +} \ No newline at end of file diff --git a/FastRngTests/Distributions/NormalS02M05.cs b/FastRngTests/Distributions/NormalS02M05.cs new file mode 100644 index 0000000..99200f4 --- /dev/null +++ b/FastRngTests/Distributions/NormalS02M05.cs @@ -0,0 +1,78 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using FastRng; +using NUnit.Framework; + +namespace FastRngTests.Distributions; + +[ExcludeFromCodeCoverage] +public class NormalS02M05 +{ + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestNormalDistribution01() + { + const float MEAN = 0.5f; + const float STANDARD_DEVIATION = 0.2f; + + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Distributions.NormalS02M05(rng); + var stats = new RunningStatistics(); + var fra = new FrequencyAnalysis(); + + for (var n = 0; n < 100_000; n++) + { + var nextNumber = dist.NextNumber(); + stats.Push(nextNumber); + fra.CountThis(nextNumber); + } + + fra.NormalizeAndPlotEvents(TestContext.WriteLine); + + TestContext.WriteLine($"mean={MEAN} vs. {stats.Mean}"); + TestContext.WriteLine($"variance={STANDARD_DEVIATION * STANDARD_DEVIATION} vs {stats.Variance}"); + + Assert.That(stats.Mean, Is.EqualTo(MEAN).Within(0.01f), "Mean is out of range"); + Assert.That(stats.Variance, Is.EqualTo(STANDARD_DEVIATION*STANDARD_DEVIATION).Within(0.01f), "Variance is out of range"); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestNormalGeneratorWithRange01() + { + using var rng = new MultiThreadedRng(); + var samples = new float[1_000]; + var dist = new FastRng.Distributions.NormalS02M05(rng); + for (var n = 0; n < samples.Length; n++) + samples[n] = dist.NextNumber(-1.0f, 1.0f); + + Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min is out of range"); + Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range"); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestNormalGeneratorWithRange02() + { + using var rng = new MultiThreadedRng(); + var samples = new float[1_000]; + var dist = new FastRng.Distributions.NormalS02M05(rng); + for (var n = 0; n < samples.Length; n++) + samples[n] = dist.NextNumber(0.0f, 1.0f); + + Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range"); + Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range"); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void NoRandomNumberGenerator01() + { + Assert.Throws(() => new FastRng.Distributions.NormalS02M05(null)); + } +} \ No newline at end of file diff --git a/FastRngTests/Distributions/StudentTNu1.cs b/FastRngTests/Distributions/StudentTNu1.cs new file mode 100644 index 0000000..9b40384 --- /dev/null +++ b/FastRngTests/Distributions/StudentTNu1.cs @@ -0,0 +1,82 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using FastRng; +using NUnit.Framework; + +namespace FastRngTests.Distributions; + +[ExcludeFromCodeCoverage] +public class StudentTNu1 +{ + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestStudentTDistribution01() + { + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Distributions.StudentTNu1(rng); + var fra = new FrequencyAnalysis(); + + for (var n = 0; n < 100_000; n++) + fra.CountThis(dist.NextNumber()); + + var result = fra.NormalizeAndPlotEvents(TestContext.WriteLine); + + Assert.That(result[0], Is.EqualTo(1.000000000f).Within(0.2f)); + Assert.That(result[1], Is.EqualTo(0.999700120f).Within(0.2f)); + Assert.That(result[2], Is.EqualTo(0.999200719f).Within(0.2f)); + + Assert.That(result[21], Is.EqualTo(0.953929798f).Within(0.2f)); + Assert.That(result[22], Is.EqualTo(0.949852788f).Within(0.2f)); + Assert.That(result[23], Is.EqualTo(0.945631619f).Within(0.2f)); + + Assert.That(result[50], Is.EqualTo(0.793667169f).Within(0.095f)); + + Assert.That(result[75], Is.EqualTo(0.633937627f).Within(0.09f)); + Assert.That(result[85], Is.EqualTo(0.574902276f).Within(0.09f)); + Assert.That(result[90], Is.EqualTo(0.547070729f).Within(0.09f)); + + Assert.That(result[97], Is.EqualTo(0.510150990f).Within(0.09f)); + Assert.That(result[98], Is.EqualTo(0.505075501f).Within(0.09f)); + Assert.That(result[99], Is.EqualTo(0.500050000f).Within(0.09f)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestStudentTGeneratorWithRange01() + { + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Distributions.StudentTNu1(rng); + var samples = new float[1_000]; + for (var n = 0; n < samples.Length; n++) + samples[n] = dist.NextNumber(-1.0f, 1.0f); + + Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range"); + Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range"); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestStudentTGeneratorWithRange02() + { + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Distributions.StudentTNu1(rng); + var samples = new float[1_000]; + for (var n = 0; n < samples.Length; n++) + samples[n] = dist.NextNumber(0.0f, 1.0f); + + Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range"); + Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range"); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void NoRandomNumberGenerator01() + { + Assert.Throws(() => new FastRng.Distributions.StudentTNu1(null)); + } +} \ No newline at end of file diff --git a/FastRngTests/Distributions/Uniform.cs b/FastRngTests/Distributions/Uniform.cs new file mode 100644 index 0000000..42b7b52 --- /dev/null +++ b/FastRngTests/Distributions/Uniform.cs @@ -0,0 +1,296 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Threading.Tasks; +using FastRng; +using NUnit.Framework; + +namespace FastRngTests.Distributions; + +[ExcludeFromCodeCoverage] +public class Uniform +{ + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestUniformDistribution01() + { + const float A = 0.0f; + const float B = 1.0f; + const float MEAN = 0.5f * (A + B); + const float VARIANCE = (1.0f / 12.0f) * (B - A) * (B - A); + + using var rng = new MultiThreadedRng(); + var stats = new RunningStatistics(); + var fra = new FrequencyAnalysis(); + + for (var n = 0; n < 100_000; n++) + { + var value = rng.GetUniform(); + stats.Push(value); + fra.CountThis(value); + } + + fra.NormalizeAndPlotEvents(TestContext.WriteLine); + fra.PlotOccurence(TestContext.WriteLine); + TestContext.WriteLine($"mean={MEAN} vs. {stats.Mean}"); + TestContext.WriteLine($"variance={VARIANCE} vs {stats.Variance}"); + + Assert.That(stats.Mean, Is.EqualTo(MEAN).Within(0.01f), "Mean is out of range"); + Assert.That(stats.Variance, Is.EqualTo(VARIANCE).Within(0.001f), "Variance is out of range"); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public async Task KolmogorovSmirnovTest() + { + // Kolmogorov-Smirnov test for distributions. + // See Knuth volume 2, page 48-51 (third edition). + // This test should *fail* on average one time in 1000 runs. + // That's life with random number generators: if the test passed all the time, + // the source wouldn't be random enough! If the test were to fail more frequently, + // the most likely explanation would be a bug in the code. + + const int NUM_ROUNDS = 10_000; + const float FAILURE_PROBABILITY = 0.001f; // probability of test failing with normal distributed input + const float P_LOW = 0.25f * FAILURE_PROBABILITY; + const float P_HIGH = 1.0f - 0.25f * FAILURE_PROBABILITY; + + var samples = new float[NUM_ROUNDS]; + using var rng = new MultiThreadedRng(); + int n; + + for (n = 0; n != NUM_ROUNDS; ++n) + samples[n] = rng.GetUniform(); + + Array.Sort(samples); + + var jMinus = 0; + var jPlus = 0; + var kPlus = -float.MaxValue; + var kMinus = -float.MaxValue; + + for (n = 0; n != NUM_ROUNDS; ++n) + { + var cdf = samples[n]; + var temp = (n + 1.0f) / NUM_ROUNDS - cdf; + + if (kPlus < temp) + { + kPlus = temp; + jPlus = n; + } + + temp = cdf - (n + 0.0f) / NUM_ROUNDS; + if (kMinus < temp) + { + kMinus = temp; + jMinus = n; + } + } + + var sqrtNumReps = MathF.Sqrt(NUM_ROUNDS); + kPlus *= sqrtNumReps; + kMinus *= sqrtNumReps; + + // We divide the failure probability by four because we have four tests: + // left and right tests for K+ and K-. + var cutoffLow = MathF.Sqrt(0.5f * MathF.Log(1.0f / (1.0f - P_LOW))) - 1.0f / (6.0f * sqrtNumReps); + var cutoffHigh = MathF.Sqrt(0.5f * MathF.Log(1.0f / (1.0f - P_HIGH))) - 1.0f / (6.0f * sqrtNumReps); + + TestContext.WriteLine($"K+ = {kPlus} | K- = {kMinus}"); + TestContext.WriteLine($"K+ max at position {jPlus} = {samples[jPlus]}"); + TestContext.WriteLine($"K- max at position {jMinus} = {samples[jMinus]}"); + TestContext.WriteLine($"Acceptable interval: [{cutoffLow}, {cutoffHigh}]"); + + Assert.That(kPlus, Is.GreaterThanOrEqualTo(cutoffLow), "K+ is lower than low cutoff"); + Assert.That(kPlus, Is.LessThanOrEqualTo(cutoffHigh), "K+ is higher than high cutoff"); + Assert.That(kMinus, Is.GreaterThanOrEqualTo(cutoffLow), "K- is lower than low cutoff"); + Assert.That(kMinus, Is.LessThanOrEqualTo(cutoffHigh), "K- is lower than high cutoff"); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestUniformGeneratorWithRange01() + { + using var rng = new MultiThreadedRng(); + var samples = new float[1_000]; + var dist = new FastRng.Distributions.Uniform(rng); + for (var n = 0; n < samples.Length; n++) + samples[n] = dist.NextNumber(-1.0f, 1.0f); + + Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min is out of range"); + Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range"); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestUniformGeneratorWithRange02() + { + using var rng = new MultiThreadedRng(); + var samples = new float[1_000]; + var dist = new FastRng.Distributions.Uniform(rng); + for (var n = 0; n < samples.Length; n++) + samples[n] = dist.NextNumber(0.0f, 1.0f); + + Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range"); + Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range"); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestUniformGeneratorWithRange04() + { + using var rng = new MultiThreadedRng(); + var samples = new float[1_000]; + for (var n = 0; n < samples.Length; n++) + samples[n] = rng.GetUniform(); + + Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range"); + Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range"); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestRange05Uint() + { + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Distributions.Uniform(rng); + var distribution = new uint[101]; + var runs = 1_000_000; + for (var n = 0; n < runs; n++) + distribution[dist.NextNumber(0, 100)]++; + + for (var n = 0; n < distribution.Length - 1; n++) + Assert.That(distribution[n], Is.GreaterThan(0)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestRange05Ulong() + { + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Distributions.Uniform(rng); + var distribution = new uint[101]; + var runs = 1_000_000; + for (var n = 0; n < runs; n++) + distribution[dist.NextNumber(0UL, 100)]++; + + for (var n = 0; n < distribution.Length - 1; n++) + Assert.That(distribution[n], Is.GreaterThan(0)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestRange05Float() + { + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Distributions.Uniform(rng); + var distribution = new uint[101]; + var runs = 1_000_000; + for (var n = 0; n < runs; n++) + distribution[(uint)MathF.Floor(dist.NextNumber(0.0f, 100.0f))]++; + + for (var n = 0; n < distribution.Length - 1; n++) + Assert.That(distribution[n], Is.GreaterThan(0)); + } + + [Test] + [Category(TestCategories.NORMAL)] + public void TestDistribution001Uint() + { + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Distributions.Uniform(rng); + var distribution = new uint[101]; + var runs = 1_000_000; + for (var n = 0; n < runs; n++) + distribution[dist.NextNumber(0, 100)]++; + + Assert.That(distribution[..^1].Max() - distribution[..^1].Min(), Is.InRange(0, 600)); + } + + [Test] + [Category(TestCategories.NORMAL)] + public void TestDistribution001Ulong() + { + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Distributions.Uniform(rng); + var distribution = new uint[101]; + var runs = 1_000_000; + for (var n = 0; n < runs; n++) + distribution[dist.NextNumber(0UL, 100)]++; + + Assert.That(distribution[..^1].Max() - distribution[..^1].Min(), Is.InRange(0, 600)); + } + + [Test] + [Category(TestCategories.NORMAL)] + public void TestDistribution001Float() + { + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Distributions.Uniform(rng); + var distribution = new uint[101]; + var runs = 1_000_000; + for (var n = 0; n < runs; n++) + distribution[(uint)MathF.Floor(dist.NextNumber(0.0f, 100.0f))]++; + + Assert.That(distribution[..^1].Max() - distribution[..^1].Min(), Is.InRange(0, 600)); + } + + [Test] + [Category(TestCategories.LONG_RUNNING)] + public void TestDistribution002Uint() + { + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Distributions.Uniform(rng); + var distribution = new uint[101]; + var runs = 100_000_000; + for (var n = 0; n < runs; n++) + distribution[dist.NextNumber(0, 100)]++; + + Assert.That(distribution[..^1].Max() - distribution[..^1].Min(), Is.InRange(0, 6_000)); + } + + [Test] + [Category(TestCategories.LONG_RUNNING)] + public void TestDistribution002Ulong() + { + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Distributions.Uniform(rng); + var distribution = new uint[101]; + var runs = 100_000_000; + for (var n = 0; n < runs; n++) + distribution[dist.NextNumber(0UL, 100)]++; + + Assert.That(distribution[..^1].Max() - distribution[..^1].Min(), Is.InRange(0, 6_000)); + } + + [Test] + [Category(TestCategories.LONG_RUNNING)] + public void TestDistribution002Float() + { + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Distributions.Uniform(rng); + var distribution = new uint[101]; + var runs = 100_000_000; + for (var n = 0; n < runs; n++) + distribution[(uint)MathF.Floor(dist.NextNumber(0.0f, 100.0f))]++; + + Assert.That(distribution[..^1].Max() - distribution[..^1].Min(), Is.InRange(0, 6_000)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void NoRandomNumberGenerator01() + { + Assert.Throws(() => new FastRng.Distributions.Uniform(null)); + } +} \ No newline at end of file diff --git a/FastRngTests/Distributions/WeibullK05La1.cs b/FastRngTests/Distributions/WeibullK05La1.cs new file mode 100644 index 0000000..86dca3d --- /dev/null +++ b/FastRngTests/Distributions/WeibullK05La1.cs @@ -0,0 +1,82 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using FastRng; +using NUnit.Framework; + +namespace FastRngTests.Distributions; + +[ExcludeFromCodeCoverage] +public class WeibullK05La1 +{ + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestWeibullDistribution01() + { + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Distributions.WeibullK05La1(rng); + var fra = new FrequencyAnalysis(); + + for (var n = 0; n < 100_000; n++) + fra.CountThis(dist.NextNumber()); + + var result = fra.NormalizeAndPlotEvents(TestContext.WriteLine); + + Assert.That(result[0], Is.EqualTo(1.000000000f).Within(0.2f)); + Assert.That(result[1], Is.EqualTo(0.678415772f).Within(0.09f)); + Assert.That(result[2], Is.EqualTo(0.536595233f).Within(0.09f)); + + Assert.That(result[21], Is.EqualTo(0.147406264f).Within(0.02f)); + Assert.That(result[22], Is.EqualTo(0.142654414f).Within(0.02f)); + Assert.That(result[23], Is.EqualTo(0.138217760f).Within(0.02f)); + + Assert.That(result[50], Is.EqualTo(0.075769787f).Within(0.095f)); + + Assert.That(result[75], Is.EqualTo(0.053016799f).Within(0.05f)); + Assert.That(result[85], Is.EqualTo(0.047144614f).Within(0.05f)); + Assert.That(result[90], Is.EqualTo(0.044629109f).Within(0.05f)); + + Assert.That(result[97], Is.EqualTo(0.041484591f).Within(0.05f)); + Assert.That(result[98], Is.EqualTo(0.041067125f).Within(0.05f)); + Assert.That(result[99], Is.EqualTo(0.040656966f).Within(0.05f)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestWeibullGeneratorWithRange01() + { + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Distributions.WeibullK05La1(rng); + var samples = new float[1_000]; + for (var n = 0; n < samples.Length; n++) + samples[n] = dist.NextNumber(-1.0f, 1.0f); + + Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range"); + Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range"); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestWeibullGeneratorWithRange02() + { + using var rng = new MultiThreadedRng(); + var dist = new FastRng.Distributions.WeibullK05La1(rng); + var samples = new float[1_000]; + for (var n = 0; n < samples.Length; n++) + samples[n] = dist.NextNumber(0.0f, 1.0f); + + Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range"); + Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range"); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void NoRandomNumberGenerator01() + { + Assert.Throws(() => new FastRng.Distributions.WeibullK05La1(null)); + } +} \ No newline at end of file diff --git a/FastRngTests/Double/DecisionTester.cs b/FastRngTests/Double/DecisionTester.cs deleted file mode 100644 index d4a4ef8..0000000 --- a/FastRngTests/Double/DecisionTester.cs +++ /dev/null @@ -1,62 +0,0 @@ -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/Double/Distributions/BetaA2B2.cs b/FastRngTests/Double/Distributions/BetaA2B2.cs deleted file mode 100644 index 5581d01..0000000 --- a/FastRngTests/Double/Distributions/BetaA2B2.cs +++ /dev/null @@ -1,84 +0,0 @@ -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 BetaA2B2 - { - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestBetaDistribution01() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.BetaA2B2(rng); - var fqa = new FrequencyAnalysis(); - - for (var n = 0; n < 100_000; n++) - fqa.CountThis(await dist.NextNumber()); - - var result = fqa.NormalizeAndPlotEvents(TestContext.WriteLine); - - Assert.That(result[0], Is.EqualTo(0.0396).Within(0.3)); - Assert.That(result[1], Is.EqualTo(0.0784).Within(0.3)); - Assert.That(result[2], Is.EqualTo(0.1164).Within(0.3)); - - Assert.That(result[21], Is.EqualTo(0.6864).Within(0.3)); - Assert.That(result[22], Is.EqualTo(0.7084).Within(0.3)); - Assert.That(result[23], Is.EqualTo(0.7296).Within(0.3)); - - Assert.That(result[50], Is.EqualTo(0.9996).Within(0.3)); - - Assert.That(result[75], Is.EqualTo(0.7296).Within(0.3)); - Assert.That(result[85], Is.EqualTo(0.4816).Within(0.3)); - Assert.That(result[90], Is.EqualTo(0.3276).Within(0.3)); - - Assert.That(result[97], Is.EqualTo(0.0784).Within(0.3)); - Assert.That(result[98], Is.EqualTo(0.0396).Within(0.3)); - Assert.That(result[99], Is.EqualTo(0.0000).Within(0.3)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestBetaGeneratorWithRange01() - { - using var rng = new MultiThreadedRng(); - var samples = new double[1_000]; - var dist = new FastRng.Double.Distributions.BetaA2B2(rng); - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(-1.0, 1.0); - - 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 TestBetaGeneratorWithRange02() - { - using var rng = new MultiThreadedRng(); - var samples = new double[1_000]; - var dist = new FastRng.Double.Distributions.BetaA2B2(rng); - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(0.0, 1.0); - - 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 void NoRandomNumberGenerator01() - { - Assert.Throws(() => new FastRng.Double.Distributions.BetaA2B2(null)); - } - } -} \ No newline at end of file diff --git a/FastRngTests/Double/Distributions/BetaA2B5.cs b/FastRngTests/Double/Distributions/BetaA2B5.cs deleted file mode 100644 index 0a64b40..0000000 --- a/FastRngTests/Double/Distributions/BetaA2B5.cs +++ /dev/null @@ -1,84 +0,0 @@ -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() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.BetaA2B5(rng); - var fqa = new FrequencyAnalysis(); - - for (var n = 0; n < 100_000; n++) - fqa.CountThis(await dist.NextNumber()); - - 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)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestBetaGeneratorWithRange01() - { - using var rng = new MultiThreadedRng(); - var samples = new double[1_000]; - var dist = new FastRng.Double.Distributions.BetaA2B5(rng); - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(-1.0, 1.0); - - 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 TestBetaGeneratorWithRange02() - { - using var rng = new MultiThreadedRng(); - var samples = new double[1_000]; - var dist = new FastRng.Double.Distributions.BetaA2B5(rng); - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(0.0, 1.0); - - 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 void NoRandomNumberGenerator01() - { - Assert.Throws(() => new FastRng.Double.Distributions.BetaA2B5(null)); - } - } -} \ No newline at end of file diff --git a/FastRngTests/Double/Distributions/BetaA5B2.cs b/FastRngTests/Double/Distributions/BetaA5B2.cs deleted file mode 100644 index fd31cac..0000000 --- a/FastRngTests/Double/Distributions/BetaA5B2.cs +++ /dev/null @@ -1,84 +0,0 @@ -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() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.BetaA5B2(rng); - var fqa = new FrequencyAnalysis(); - - for (var n = 0; n < 100_000; n++) - fqa.CountThis(await dist.NextNumber()); - - 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.00001)); - Assert.That(result[2], Is.EqualTo(0.0000096).Within(0.0004)); - - 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.15)); - Assert.That(result[85], Is.EqualTo(0.9552714).Within(0.15)); - Assert.That(result[90], Is.EqualTo(0.8004420).Within(0.35)); - - 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)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestBetaGeneratorWithRange01() - { - using var rng = new MultiThreadedRng(); - var samples = new double[1_000]; - var dist = new FastRng.Double.Distributions.BetaA5B2(rng); - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(-1.0, 1.0); - - 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 TestBetaGeneratorWithRange02() - { - using var rng = new MultiThreadedRng(); - var samples = new double[1_000]; - var dist = new FastRng.Double.Distributions.BetaA5B2(rng); - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(0.0, 1.0); - - 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 void NoRandomNumberGenerator01() - { - Assert.Throws(() => new FastRng.Double.Distributions.BetaA5B2(null)); - } - } -} \ No newline at end of file diff --git a/FastRngTests/Double/Distributions/CauchyLorentzX0.cs b/FastRngTests/Double/Distributions/CauchyLorentzX0.cs deleted file mode 100644 index d7460e7..0000000 --- a/FastRngTests/Double/Distributions/CauchyLorentzX0.cs +++ /dev/null @@ -1,87 +0,0 @@ -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 CauchyLorentzX0 - { - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestCauchyDistribution01() - { - // The properties of the cauchy distribution cannot be tested by mean, media or variance, - // cf. https://en.wikipedia.org/wiki/Cauchy_distribution#Explanation_of_undefined_moments - - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.CauchyLorentzX0(rng); - var fqa = new FrequencyAnalysis(); - - for (var n = 0; n < 100_000; n++) - fqa.CountThis(await dist.NextNumber()); - - var result = fqa.NormalizeAndPlotEvents(TestContext.WriteLine); - - Assert.That(result[0], Is.EqualTo(0.976990739772031).Within(0.06)); - Assert.That(result[1], Is.EqualTo(0.948808314586299).Within(0.06)); - Assert.That(result[2], Is.EqualTo(0.905284997403441).Within(0.06)); - - Assert.That(result[21], Is.EqualTo(0.168965864241396).Within(0.04)); - Assert.That(result[22], Is.EqualTo(0.156877686354491).Within(0.04)); - Assert.That(result[23], Is.EqualTo(0.145970509936354).Within(0.04)); - - Assert.That(result[50], Is.EqualTo(0.036533159835978).Within(0.01)); - - Assert.That(result[75], Is.EqualTo(0.016793067514802).Within(0.01)); - Assert.That(result[85], Is.EqualTo(0.01316382933791).Within(0.005)); - Assert.That(result[90], Is.EqualTo(0.011773781734516).Within(0.005)); - - Assert.That(result[97], Is.EqualTo(0.010168596941156).Within(0.005)); - Assert.That(result[98], Is.EqualTo(0.009966272570142).Within(0.005)); - Assert.That(result[99], Is.EqualTo(0.00976990739772).Within(0.005)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestCauchyGeneratorWithRange01() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.CauchyLorentzX0(rng); - var samples = new double[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(-1.0, 1.0); - - Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.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 TestCauchyGeneratorWithRange02() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.CauchyLorentzX0(rng); - var samples = new double[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(0.0, 1.0); - - 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 void NoRandomNumberGenerator01() - { - Assert.Throws(() => new FastRng.Double.Distributions.CauchyLorentzX0(null)); - } - } -} \ No newline at end of file diff --git a/FastRngTests/Double/Distributions/CauchyLorentzX1.cs b/FastRngTests/Double/Distributions/CauchyLorentzX1.cs deleted file mode 100644 index 4bd7974..0000000 --- a/FastRngTests/Double/Distributions/CauchyLorentzX1.cs +++ /dev/null @@ -1,87 +0,0 @@ -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 CauchyLorentzX1 - { - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestCauchyDistribution01() - { - // The properties of the cauchy distribution cannot be tested by mean, media or variance, - // cf. https://en.wikipedia.org/wiki/Cauchy_distribution#Explanation_of_undefined_moments - - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.CauchyLorentzX1(rng); - var fqa = new FrequencyAnalysis(); - - for (var n = 0; n < 100_000; n++) - fqa.CountThis(await dist.NextNumber()); - - var result = fqa.NormalizeAndPlotEvents(TestContext.WriteLine); - - Assert.That(result[0], Is.EqualTo(0.009966272570142).Within(0.003)); - Assert.That(result[1], Is.EqualTo(0.010168596941156).Within(0.004)); - Assert.That(result[2], Is.EqualTo(0.010377123221893).Within(0.005)); - - Assert.That(result[21], Is.EqualTo(0.015956672819692).Within(0.005)); - Assert.That(result[22], Is.EqualTo(0.016366904083094).Within(0.005)); - Assert.That(result[23], Is.EqualTo(0.016793067514802).Within(0.005)); - - Assert.That(result[50], Is.EqualTo(0.039454644029179).Within(0.015)); - - Assert.That(result[75], Is.EqualTo(0.145970509936354).Within(0.03)); - Assert.That(result[85], Is.EqualTo(0.333365083503296).Within(0.1)); - Assert.That(result[90], Is.EqualTo(0.545171628270584).Within(0.1)); - - Assert.That(result[97], Is.EqualTo(0.948808314586302).Within(0.06)); - Assert.That(result[98], Is.EqualTo(0.976990739772032).Within(0.03)); - Assert.That(result[99], Is.EqualTo(0.986760647169751).Within(0.02)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestCauchyGeneratorWithRange01() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.CauchyLorentzX0(rng); - var samples = new double[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(-1.0, 1.0); - - Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.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 TestCauchyGeneratorWithRange02() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.CauchyLorentzX0(rng); - var samples = new double[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(0.0, 1.0); - - 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 void NoRandomNumberGenerator01() - { - Assert.Throws(() => new FastRng.Double.Distributions.CauchyLorentzX1(null)); - } - } -} \ No newline at end of file diff --git a/FastRngTests/Double/Distributions/ChiSquareK1.cs b/FastRngTests/Double/Distributions/ChiSquareK1.cs deleted file mode 100644 index c741c56..0000000 --- a/FastRngTests/Double/Distributions/ChiSquareK1.cs +++ /dev/null @@ -1,87 +0,0 @@ -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 ChiSquareK1 - { - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestChiSquareDistribution01() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.ChiSquareK1(rng); - var fqa = new FrequencyAnalysis(); - - for (var n = 0; n < 100_000; n++) - { - var value = await dist.NextNumber(); - fqa.CountThis(value); - } - - var result = fqa.NormalizeAndPlotEvents(TestContext.WriteLine); - - Assert.That(result[0], Is.EqualTo(1.00032041964207).Within(0.004)); - Assert.That(result[1], Is.EqualTo(0.70380551227703).Within(0.05)); - Assert.That(result[2], Is.EqualTo(0.571788691668126).Within(0.05)); - - Assert.That(result[21], Is.EqualTo(0.192011337664754).Within(0.07)); - Assert.That(result[22], Is.EqualTo(0.186854182385981).Within(0.07)); - Assert.That(result[23], Is.EqualTo(0.182007652359976).Within(0.07)); - - Assert.That(result[50], Is.EqualTo(0.109088865614875).Within(0.06)); - - Assert.That(result[75], Is.EqualTo(0.07886274821701).Within(0.02)); - Assert.That(result[85], Is.EqualTo(0.070520397849883).Within(0.02)); - Assert.That(result[90], Is.EqualTo(0.066863009640287).Within(0.02)); - - Assert.That(result[97], Is.EqualTo(0.062214737436948).Within(0.02)); - Assert.That(result[98], Is.EqualTo(0.061590997922187).Within(0.02)); - Assert.That(result[99], Is.EqualTo(0.060976622578824).Within(0.02)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestChiSquareGeneratorWithRange01() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.ChiSquareK1(rng); - var samples = new double[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(-1.0, 1.0); - - 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 TestChiSquareGeneratorWithRange02() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.ChiSquareK1(rng); - var samples = new double[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(0.0, 1.0); - - 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 void NoRandomNumberGenerator01() - { - Assert.Throws(() => new FastRng.Double.Distributions.ChiSquareK1(null)); - } - } -} \ No newline at end of file diff --git a/FastRngTests/Double/Distributions/ChiSquareK10.cs b/FastRngTests/Double/Distributions/ChiSquareK10.cs deleted file mode 100644 index b7a241c..0000000 --- a/FastRngTests/Double/Distributions/ChiSquareK10.cs +++ /dev/null @@ -1,87 +0,0 @@ -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 ChiSquareK10 - { - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestChiSquareDistribution01() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.ChiSquareK10(rng); - var fqa = new FrequencyAnalysis(); - - for (var n = 0; n < 100_000; n++) - { - var value = await dist.NextNumber(); - fqa.CountThis(value); - } - - var result = fqa.NormalizeAndPlotEvents(TestContext.WriteLine); - - Assert.That(result[0], Is.EqualTo(0.0000000164021588).Within(0.0000002)); - Assert.That(result[1], Is.EqualTo(0.0000002611256437).Within(0.000003)); - Assert.That(result[2], Is.EqualTo(0.0000013153553250).Within(0.00002)); - - Assert.That(result[21], Is.EqualTo(0.003459320622874).Within(0.005)); - Assert.That(result[22], Is.EqualTo(0.004111875573379).Within(0.005)); - Assert.That(result[23], Is.EqualTo(0.004850674298859).Within(0.005)); - - Assert.That(result[50], Is.EqualTo(0.086418773275056).Within(0.05)); - - Assert.That(result[75], Is.EqualTo(0.376092741436046).Within(0.08)); - Assert.That(result[85], Is.EqualTo(0.586569751611096).Within(0.08)); - Assert.That(result[90], Is.EqualTo(0.717189736168766).Within(0.08)); - - Assert.That(result[97], Is.EqualTo(0.931477764640217).Within(0.08)); - Assert.That(result[98], Is.EqualTo(0.965244855212136).Within(0.08)); - Assert.That(result[99], Is.EqualTo(0.999827884370044).Within(0.08)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestChiSquareGeneratorWithRange01() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.ChiSquareK10(rng); - var samples = new double[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(-1.0, 1.0); - - 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 TestChiSquareGeneratorWithRange02() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.ChiSquareK10(rng); - var samples = new double[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(0.0, 1.0); - - 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 void NoRandomNumberGenerator01() - { - Assert.Throws(() => new FastRng.Double.Distributions.ChiSquareK10(null)); - } - } -} \ No newline at end of file diff --git a/FastRngTests/Double/Distributions/ChiSquareK4.cs b/FastRngTests/Double/Distributions/ChiSquareK4.cs deleted file mode 100644 index d35933d..0000000 --- a/FastRngTests/Double/Distributions/ChiSquareK4.cs +++ /dev/null @@ -1,84 +0,0 @@ -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 ChiSquareK4 - { - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestChiSquareDistribution01() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.ChiSquareK4(rng); - var fqa = new FrequencyAnalysis(); - - for (var n = 0; n < 100_000; n++) - fqa.CountThis(await dist.NextNumber()); - - var result = fqa.NormalizeAndPlotEvents(TestContext.WriteLine); - - Assert.That(result[0], Is.EqualTo(0.016417705906679).Within(0.02)); - Assert.That(result[1], Is.EqualTo(0.032671644513723).Within(0.02)); - Assert.That(result[2], Is.EqualTo(0.048763041010352).Within(0.02)); - - Assert.That(result[21], Is.EqualTo(0.32518779111264).Within(0.05)); - Assert.That(result[22], Is.EqualTo(0.338273451612642).Within(0.05)); - Assert.That(result[23], Is.EqualTo(0.351220492939994).Within(0.05)); - - Assert.That(result[50], Is.EqualTo(0.65209223303425).Within(0.08)); - - Assert.That(result[75], Is.EqualTo(0.857562207152294).Within(0.099)); - Assert.That(result[85], Is.EqualTo(0.923072405412387).Within(0.099)); - Assert.That(result[90], Is.EqualTo(0.952623623874265).Within(0.099)); - - Assert.That(result[97], Is.EqualTo(0.990616879396201).Within(0.099)); - Assert.That(result[98], Is.EqualTo(0.995734077068522).Within(0.099)); - Assert.That(result[99], Is.EqualTo(1.00077558852585).Within(0.1)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestChiSquareGeneratorWithRange01() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.ChiSquareK4(rng); - var samples = new double[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(-1.0, 1.0); - - 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 TestChiSquareGeneratorWithRange02() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.ChiSquareK4(rng); - var samples = new double[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(0.0, 1.0); - - 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 void NoRandomNumberGenerator01() - { - Assert.Throws(() => new FastRng.Double.Distributions.ChiSquareK4(null)); - } - } -} \ No newline at end of file diff --git a/FastRngTests/Double/Distributions/ExponentialLa10.cs b/FastRngTests/Double/Distributions/ExponentialLa10.cs deleted file mode 100644 index cf0e380..0000000 --- a/FastRngTests/Double/Distributions/ExponentialLa10.cs +++ /dev/null @@ -1,84 +0,0 @@ -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 ExponentialLa10 - { - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestExponentialDistribution01() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.ExponentialLa10(rng); - var fqa = new FrequencyAnalysis(); - - for (var n = 0; n < 100_000; n++) - fqa.CountThis(await dist.NextNumber()); - - var result = fqa.NormalizeAndPlotEvents(TestContext.WriteLine); - - Assert.That(result[0], Is.EqualTo(1.00075018434777).Within(0.05)); - Assert.That(result[1], Is.EqualTo(0.905516212904248).Within(0.05)); - Assert.That(result[2], Is.EqualTo(0.81934495207398).Within(0.05)); - - Assert.That(result[21], Is.EqualTo(0.122548293148741).Within(0.12)); - Assert.That(result[22], Is.EqualTo(0.110886281157421).Within(0.12)); - Assert.That(result[23], Is.EqualTo(0.10033405633809).Within(0.12)); - - Assert.That(result[50], Is.EqualTo(0.00674300170146).Within(0.005)); - - Assert.That(result[75], Is.EqualTo(0.000553499285385).Within(0.001)); - Assert.That(result[85], Is.EqualTo(0.000203621007796).Within(0.001)); - Assert.That(result[90], Is.EqualTo(0.00012350238419).Within(0.001)); - - Assert.That(result[97], Is.EqualTo(0.0000613294689720).Within(0.0008)); - Assert.That(result[98], Is.EqualTo(0.0000554931983541).Within(0.0008)); - Assert.That(result[99], Is.EqualTo(0.0000502123223173).Within(0.0008)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestExponentialGeneratorWithRange01() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.ExponentialLa10(rng); - var samples = new double[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(-1.0, 1.0); - - 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() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.ExponentialLa10(rng); - var samples = new double[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(0.0, 1.0); - - 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 void NoRandomNumberGenerator01() - { - Assert.Throws(() => new FastRng.Double.Distributions.ExponentialLa10(null)); - } - } -} \ No newline at end of file diff --git a/FastRngTests/Double/Distributions/ExponentialLa5.cs b/FastRngTests/Double/Distributions/ExponentialLa5.cs deleted file mode 100644 index 7be1596..0000000 --- a/FastRngTests/Double/Distributions/ExponentialLa5.cs +++ /dev/null @@ -1,84 +0,0 @@ -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 ExponentialLa5 - { - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestExponentialDistribution01() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.ExponentialLa5(rng); - var fqa = new FrequencyAnalysis(); - - for (var n = 0; n < 100_000; n++) - fqa.CountThis(await dist.NextNumber()); - - var result = fqa.NormalizeAndPlotEvents(TestContext.WriteLine); - - Assert.That(result[0], Is.EqualTo(1.0002177398625).Within(0.05)); - Assert.That(result[1], Is.EqualTo(0.951436545064811).Within(0.05)); - Assert.That(result[2], Is.EqualTo(0.905034437210948).Within(0.05)); - - Assert.That(result[21], Is.EqualTo(0.35001394450853).Within(0.05)); - Assert.That(result[22], Is.EqualTo(0.332943563002074).Within(0.05)); - Assert.That(result[23], Is.EqualTo(0.31670571382568).Within(0.05)); - - Assert.That(result[50], Is.EqualTo(0.082102871800213).Within(0.01)); - - Assert.That(result[75], Is.EqualTo(0.023522866606758).Within(0.01)); - Assert.That(result[85], Is.EqualTo(0.014267339801329).Within(0.01)); - Assert.That(result[90], Is.EqualTo(0.011111415409621).Within(0.01)); - - Assert.That(result[97], Is.EqualTo(0.007830082099077).Within(0.008)); - Assert.That(result[98], Is.EqualTo(0.007448204488898).Within(0.008)); - Assert.That(result[99], Is.EqualTo(0.007084951269538).Within(0.008)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestExponentialGeneratorWithRange01() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.ExponentialLa5(rng); - var samples = new double[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(-1.0, 1.0); - - 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() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.ExponentialLa5(rng); - var samples = new double[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(0.0, 1.0); - - 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 void NoRandomNumberGenerator01() - { - Assert.Throws(() => new FastRng.Double.Distributions.ExponentialLa5(null)); - } - } -} \ No newline at end of file diff --git a/FastRngTests/Double/Distributions/GammaA5B15.cs b/FastRngTests/Double/Distributions/GammaA5B15.cs deleted file mode 100644 index dde9e88..0000000 --- a/FastRngTests/Double/Distributions/GammaA5B15.cs +++ /dev/null @@ -1,84 +0,0 @@ -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 GammaA5B15 - { - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestGammaDistribution01() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.GammaA5B15(rng); - var fra = new FrequencyAnalysis(); - - for (var n = 0; n < 100_000; n++) - fra.CountThis(await dist.NextNumber()); - - var result = fra.NormalizeAndPlotEvents(TestContext.WriteLine); - - Assert.That(result[0], Is.EqualTo(0.0000929594237282).Within(0.0008)); - Assert.That(result[1], Is.EqualTo(0.0012801746797876).Within(0.002)); - Assert.That(result[2], Is.EqualTo(0.0055781488254349).Within(0.004)); - - Assert.That(result[21], Is.EqualTo(0.9331608887752720).Within(0.09)); - Assert.That(result[22], Is.EqualTo(0.9594734828891280).Within(0.09)); - Assert.That(result[23], Is.EqualTo(0.9790895765535350).Within(0.09)); - - Assert.That(result[50], Is.EqualTo(0.3478287795336570).Within(0.06)); - - Assert.That(result[75], Is.EqualTo(0.0403399049422936).Within(0.009)); - Assert.That(result[85], Is.EqualTo(0.0163628388658126).Within(0.009)); - Assert.That(result[90], Is.EqualTo(0.0097147611446660).Within(0.005)); - - Assert.That(result[97], Is.EqualTo(0.0041135143233153).Within(0.008)); - Assert.That(result[98], Is.EqualTo(0.0036872732029996).Within(0.008)); - Assert.That(result[99], Is.EqualTo(0.0033038503429554).Within(0.008)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestGammaGeneratorWithRange01() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.GammaA5B15(rng); - var samples = new double[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(-1.0, 1.0); - - Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.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 TestGammaGeneratorWithRange02() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.GammaA5B15(rng); - var samples = new double[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(0.0, 1.0); - - 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 void NoRandomNumberGenerator01() - { - Assert.Throws(() => new FastRng.Double.Distributions.GammaA5B15(null)); - } - } -} \ No newline at end of file diff --git a/FastRngTests/Double/Distributions/InverseExponentialLa10.cs b/FastRngTests/Double/Distributions/InverseExponentialLa10.cs deleted file mode 100644 index d3b3b47..0000000 --- a/FastRngTests/Double/Distributions/InverseExponentialLa10.cs +++ /dev/null @@ -1,84 +0,0 @@ -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() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.InverseExponentialLa10(rng); - var fqa = new FrequencyAnalysis(); - - for (var n = 0; n < 100_000; n++) - fqa.CountThis(await dist.NextNumber()); - - 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.003)); - - 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() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.InverseExponentialLa10(rng); - var samples = new double[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(-1.0, 1.0); - - 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() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.InverseExponentialLa10(rng); - var samples = new double[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(0.0, 1.0); - - 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 void NoRandomNumberGenerator01() - { - Assert.Throws(() => new FastRng.Double.Distributions.InverseExponentialLa10(null)); - } - } -} \ No newline at end of file diff --git a/FastRngTests/Double/Distributions/InverseExponentialLa5.cs b/FastRngTests/Double/Distributions/InverseExponentialLa5.cs deleted file mode 100644 index 51f74b1..0000000 --- a/FastRngTests/Double/Distributions/InverseExponentialLa5.cs +++ /dev/null @@ -1,84 +0,0 @@ -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() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.InverseExponentialLa5(rng); - var fqa = new FrequencyAnalysis(); - - for (var n = 0; n < 100_000; n++) - fqa.CountThis(await dist.NextNumber()); - - 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() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.InverseExponentialLa5(rng); - var samples = new double[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(-1.0, 1.0); - - 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() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.InverseExponentialLa5(rng); - var samples = new double[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(0.0, 1.0); - - 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 void NoRandomNumberGenerator01() - { - Assert.Throws(() => new FastRng.Double.Distributions.InverseExponentialLa5(null)); - } - } -} \ No newline at end of file diff --git a/FastRngTests/Double/Distributions/InverseGammaA3B05.cs b/FastRngTests/Double/Distributions/InverseGammaA3B05.cs deleted file mode 100644 index c2299e6..0000000 --- a/FastRngTests/Double/Distributions/InverseGammaA3B05.cs +++ /dev/null @@ -1,84 +0,0 @@ -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 InverseGammaA3B05 - { - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestInverseGammaDistribution01() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.InverseGammaA3B05(rng); - var fra = new FrequencyAnalysis(); - - for (var n = 0; n < 100_000; n++) - fra.CountThis(await dist.NextNumber()); - - var result = fra.NormalizeAndPlotEvents(TestContext.WriteLine); - - Assert.That(result[0], Is.EqualTo(0.0000000000000003).Within(0.0000001)); - Assert.That(result[1], Is.EqualTo(0.0000011605257228).Within(0.00001)); - Assert.That(result[2], Is.EqualTo(0.0009536970016103).Within(0.0015)); - - Assert.That(result[21], Is.EqualTo(0.5880485243048120).Within(0.05)); - Assert.That(result[22], Is.EqualTo(0.5433842148912880).Within(0.05)); - Assert.That(result[23], Is.EqualTo(0.5017780549216030).Within(0.05)); - - Assert.That(result[50], Is.EqualTo(0.0741442015957425).Within(0.009)); - - Assert.That(result[75], Is.EqualTo(0.0207568945092484).Within(0.006)); - Assert.That(result[85], Is.EqualTo(0.0136661506653688).Within(0.006)); - Assert.That(result[90], Is.EqualTo(0.0112550619601327).Within(0.006)); - - Assert.That(result[97], Is.EqualTo(0.0087026933539773).Within(0.005)); - Assert.That(result[98], Is.EqualTo(0.0083995375385004).Within(0.005)); - Assert.That(result[99], Is.EqualTo(0.0081094156379928).Within(0.005)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestInverseGammaGeneratorWithRange01() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.InverseGammaA3B05(rng); - var samples = new double[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(-1.0, 1.0); - - 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 TestInverseGammaGeneratorWithRange02() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.InverseGammaA3B05(rng); - var samples = new double[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(0.0, 1.0); - - 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 void NoRandomNumberGenerator01() - { - Assert.Throws(() => new FastRng.Double.Distributions.InverseGammaA3B05(null)); - } - } -} \ No newline at end of file diff --git a/FastRngTests/Double/Distributions/LaplaceB01M0.cs b/FastRngTests/Double/Distributions/LaplaceB01M0.cs deleted file mode 100644 index 5865e83..0000000 --- a/FastRngTests/Double/Distributions/LaplaceB01M0.cs +++ /dev/null @@ -1,84 +0,0 @@ -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 LaplaceB01M0 - { - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestLaplaceDistribution01() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.LaplaceB01M0(rng); - var fra = new FrequencyAnalysis(); - - for (var n = 0; n < 100_000; n++) - fra.CountThis(await dist.NextNumber()); - - var result = fra.NormalizeAndPlotEvents(TestContext.WriteLine); - - Assert.That(result[0], Is.EqualTo(1.0000000000000000).Within(0.05)); - Assert.That(result[1], Is.EqualTo(0.9048374180359590).Within(0.05)); - Assert.That(result[2], Is.EqualTo(0.8187307530779810).Within(0.05)); - - Assert.That(result[21], Is.EqualTo(0.1224564282529820).Within(0.05)); - Assert.That(result[22], Is.EqualTo(0.1108031583623340).Within(0.05)); - Assert.That(result[23], Is.EqualTo(0.1002588437228040).Within(0.05)); - - Assert.That(result[50], Is.EqualTo(0.0067379469990855).Within(0.003)); - - Assert.That(result[75], Is.EqualTo(0.0005530843701478).Within(0.0015)); - Assert.That(result[85], Is.EqualTo(0.0002034683690106).Within(0.0015)); - Assert.That(result[90], Is.EqualTo(0.0001234098040867).Within(0.0015)); - - Assert.That(result[97], Is.EqualTo(0.0000612834950532).Within(0.0002)); - Assert.That(result[98], Is.EqualTo(0.0000554515994322).Within(0.0002)); - Assert.That(result[99], Is.EqualTo(0.0000501746820562).Within(0.0002)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestLaplaceGeneratorWithRange01() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.LaplaceB01M0(rng); - var samples = new double[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(-1.0, 1.0); - - 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 TestLaplaceGeneratorWithRange02() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.LaplaceB01M0(rng); - var samples = new double[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(0.0, 1.0); - - 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 void NoRandomNumberGenerator01() - { - Assert.Throws(() => new FastRng.Double.Distributions.LaplaceB01M0(null)); - } - } -} \ No newline at end of file diff --git a/FastRngTests/Double/Distributions/LaplaceB01M05.cs b/FastRngTests/Double/Distributions/LaplaceB01M05.cs deleted file mode 100644 index 731318b..0000000 --- a/FastRngTests/Double/Distributions/LaplaceB01M05.cs +++ /dev/null @@ -1,84 +0,0 @@ -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 LaplaceB01M05 - { - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestLaplaceDistribution01() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.LaplaceB01M05(rng); - var fra = new FrequencyAnalysis(); - - for (var n = 0; n < 100_000; n++) - fra.CountThis(await dist.NextNumber()); - - var result = fra.NormalizeAndPlotEvents(TestContext.WriteLine); - - Assert.That(result[0], Is.EqualTo(0.0074465830709244).Within(0.004)); - Assert.That(result[1], Is.EqualTo(0.0082297470490200).Within(0.004)); - Assert.That(result[2], Is.EqualTo(0.0090952771016958).Within(0.01)); - - Assert.That(result[21], Is.EqualTo(0.0608100626252180).Within(0.02)); - Assert.That(result[22], Is.EqualTo(0.0672055127397498).Within(0.02)); - Assert.That(result[23], Is.EqualTo(0.0742735782143340).Within(0.02)); - - Assert.That(result[50], Is.EqualTo(1.0000000000000000).Within(0.2)); - - Assert.That(result[75], Is.EqualTo(0.0742735782143335).Within(0.01)); - Assert.That(result[85], Is.EqualTo(0.0273237224472924).Within(0.01)); - Assert.That(result[90], Is.EqualTo(0.0165726754017612).Within(0.01)); - - Assert.That(result[97], Is.EqualTo(0.0082297470490200).Within(0.004)); - Assert.That(result[98], Is.EqualTo(0.0074465830709243).Within(0.004)); - Assert.That(result[99], Is.EqualTo(0.0067379469990854).Within(0.004)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestLaplaceGeneratorWithRange01() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.LaplaceB01M05(rng); - var samples = new double[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(-1.0, 1.0); - - 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 TestLaplaceGeneratorWithRange02() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.LaplaceB01M05(rng); - var samples = new double[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(0.0, 1.0); - - 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 void NoRandomNumberGenerator01() - { - Assert.Throws(() => new FastRng.Double.Distributions.LaplaceB01M05(null)); - } - } -} \ No newline at end of file diff --git a/FastRngTests/Double/Distributions/LogNormalS1M0.cs b/FastRngTests/Double/Distributions/LogNormalS1M0.cs deleted file mode 100644 index bc8fdb9..0000000 --- a/FastRngTests/Double/Distributions/LogNormalS1M0.cs +++ /dev/null @@ -1,84 +0,0 @@ -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 LogNormalS1M0 - { - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestLogNormalDistribution01() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.LogNormalS1M0(rng); - var fra = new FrequencyAnalysis(); - - for (var n = 0; n < 100_000; n++) - fra.CountThis(await dist.NextNumber()); - - var result = fra.NormalizeAndPlotEvents(TestContext.WriteLine); - - Assert.That(result[0], Is.EqualTo(0.001505531).Within(0.003)); - Assert.That(result[1], Is.EqualTo(0.014408709).Within(0.01)); - Assert.That(result[2], Is.EqualTo(0.043222256).Within(0.02)); - - Assert.That(result[21], Is.EqualTo(0.876212056).Within(0.15)); - Assert.That(result[22], Is.EqualTo(0.895582226).Within(0.15)); - Assert.That(result[23], Is.EqualTo(0.912837250).Within(0.15)); - - Assert.That(result[50], Is.EqualTo(0.948062005).Within(0.2)); - - Assert.That(result[75], Is.EqualTo(0.768584762).Within(0.089)); - Assert.That(result[85], Is.EqualTo(0.697303612).Within(0.089)); - Assert.That(result[90], Is.EqualTo(0.663570581).Within(0.089)); - - Assert.That(result[97], Is.EqualTo(0.618792767).Within(0.089)); - Assert.That(result[98], Is.EqualTo(0.612636410).Within(0.089)); - Assert.That(result[99], Is.EqualTo(0.606540679).Within(0.089)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestLogNormalGeneratorWithRange01() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.LogNormalS1M0(rng); - var samples = new double[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(-1.0, 1.0); - - 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 TestLogNormalGeneratorWithRange02() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.LogNormalS1M0(rng); - var samples = new double[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(0.0, 1.0); - - 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 void NoRandomNumberGenerator01() - { - Assert.Throws(() => new FastRng.Double.Distributions.LogNormalS1M0(null)); - } - } -} \ No newline at end of file diff --git a/FastRngTests/Double/Distributions/NormalS02M05.cs b/FastRngTests/Double/Distributions/NormalS02M05.cs deleted file mode 100644 index ae88040..0000000 --- a/FastRngTests/Double/Distributions/NormalS02M05.cs +++ /dev/null @@ -1,80 +0,0 @@ -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 NormalS02M05 - { - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestNormalDistribution01() - { - const double MEAN = 0.5; - const double STANDARD_DEVIATION = 0.2; - - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.NormalS02M05(rng); - var stats = new RunningStatistics(); - var fra = new FrequencyAnalysis(); - - for (var n = 0; n < 100_000; n++) - { - var nextNumber = await dist.NextNumber(); - stats.Push(nextNumber); - fra.CountThis(nextNumber); - } - - fra.NormalizeAndPlotEvents(TestContext.WriteLine); - - TestContext.WriteLine($"mean={MEAN} vs. {stats.Mean}"); - TestContext.WriteLine($"variance={STANDARD_DEVIATION * STANDARD_DEVIATION} vs {stats.Variance}"); - - Assert.That(stats.Mean, Is.EqualTo(MEAN).Within(0.01), "Mean is out of range"); - Assert.That(stats.Variance, Is.EqualTo(STANDARD_DEVIATION*STANDARD_DEVIATION).Within(0.01), "Variance is out of range"); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestNormalGeneratorWithRange01() - { - using var rng = new MultiThreadedRng(); - var samples = new double[1_000]; - var dist = new FastRng.Double.Distributions.NormalS02M05(rng); - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(-1.0, 1.0); - - Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.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 TestNormalGeneratorWithRange02() - { - using var rng = new MultiThreadedRng(); - var samples = new double[1_000]; - var dist = new FastRng.Double.Distributions.NormalS02M05(rng); - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(0.0, 1.0); - - 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 void NoRandomNumberGenerator01() - { - Assert.Throws(() => new FastRng.Double.Distributions.NormalS02M05(null)); - } - } -} \ No newline at end of file diff --git a/FastRngTests/Double/Distributions/StudentTNu1.cs b/FastRngTests/Double/Distributions/StudentTNu1.cs deleted file mode 100644 index d61db7a..0000000 --- a/FastRngTests/Double/Distributions/StudentTNu1.cs +++ /dev/null @@ -1,84 +0,0 @@ -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 StudentTNu1 - { - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestStudentTDistribution01() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.StudentTNu1(rng); - var fra = new FrequencyAnalysis(); - - for (var n = 0; n < 100_000; n++) - fra.CountThis(await dist.NextNumber()); - - var result = fra.NormalizeAndPlotEvents(TestContext.WriteLine); - - Assert.That(result[0], Is.EqualTo(1.000000000).Within(0.2)); - Assert.That(result[1], Is.EqualTo(0.999700120).Within(0.2)); - Assert.That(result[2], Is.EqualTo(0.999200719).Within(0.2)); - - Assert.That(result[21], Is.EqualTo(0.953929798).Within(0.2)); - Assert.That(result[22], Is.EqualTo(0.949852788).Within(0.2)); - Assert.That(result[23], Is.EqualTo(0.945631619).Within(0.2)); - - Assert.That(result[50], Is.EqualTo(0.793667169).Within(0.095)); - - Assert.That(result[75], Is.EqualTo(0.633937627).Within(0.09)); - Assert.That(result[85], Is.EqualTo(0.574902276).Within(0.09)); - Assert.That(result[90], Is.EqualTo(0.547070729).Within(0.09)); - - Assert.That(result[97], Is.EqualTo(0.510150990).Within(0.09)); - Assert.That(result[98], Is.EqualTo(0.505075501).Within(0.09)); - Assert.That(result[99], Is.EqualTo(0.500050000).Within(0.09)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestStudentTGeneratorWithRange01() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.StudentTNu1(rng); - var samples = new double[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(-1.0, 1.0); - - 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 TestStudentTGeneratorWithRange02() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.StudentTNu1(rng); - var samples = new double[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(0.0, 1.0); - - 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 void NoRandomNumberGenerator01() - { - Assert.Throws(() => new FastRng.Double.Distributions.StudentTNu1(null)); - } - } -} \ No newline at end of file diff --git a/FastRngTests/Double/Distributions/Uniform.cs b/FastRngTests/Double/Distributions/Uniform.cs deleted file mode 100644 index facd579..0000000 --- a/FastRngTests/Double/Distributions/Uniform.cs +++ /dev/null @@ -1,297 +0,0 @@ -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 Uniform - { - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestUniformDistribution01() - { - const double A = 0.0; - const double B = 1.0; - const double MEAN = 0.5 * (A + B); - const double VARIANCE = (1.0 / 12.0) * (B - A) * (B - A); - - var stats = new RunningStatistics(); - var fra = new FrequencyAnalysis(); - using var rng = new MultiThreadedRng(); - - for (var n = 0; n < 100_000; n++) - { - var value = await rng.GetUniform(); - stats.Push(value); - fra.CountThis(value); - } - - fra.NormalizeAndPlotEvents(TestContext.WriteLine); - fra.PlotOccurence(TestContext.WriteLine); - TestContext.WriteLine($"mean={MEAN} vs. {stats.Mean}"); - TestContext.WriteLine($"variance={VARIANCE} vs {stats.Variance}"); - - Assert.That(stats.Mean, Is.EqualTo(MEAN).Within(0.01), "Mean is out of range"); - Assert.That(stats.Variance, Is.EqualTo(VARIANCE).Within(0.001), "Variance is out of range"); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task KolmogorovSmirnovTest() - { - // Kolmogorov-Smirnov test for distributions. - // See Knuth volume 2, page 48-51 (third edition). - // This test should *fail* on average one time in 1000 runs. - // That's life with random number generators: if the test passed all the time, - // the source wouldn't be random enough! If the test were to fail more frequently, - // the most likely explanation would be a bug in the code. - - const int NUM_ROUNDS = 10_000; - const double FAILURE_PROBABILITY = 0.001; // probability of test failing with normal distributed input - const double P_LOW = 0.25 * FAILURE_PROBABILITY; - const double P_HIGH = 1.0 - 0.25 * FAILURE_PROBABILITY; - - var samples = new double[NUM_ROUNDS]; - using var rng = new MultiThreadedRng(); - int n; - - for (n = 0; n != NUM_ROUNDS; ++n) - samples[n] = await rng.GetUniform(); - - Array.Sort(samples); - - var jMinus = 0; - var jPlus = 0; - var kPlus = -double.MaxValue; - var kMinus = -double.MaxValue; - - for (n = 0; n != NUM_ROUNDS; ++n) - { - var cdf = samples[n]; - var temp = (n + 1.0) / NUM_ROUNDS - cdf; - - if (kPlus < temp) - { - kPlus = temp; - jPlus = n; - } - - temp = cdf - (n + 0.0) / NUM_ROUNDS; - if (kMinus < temp) - { - kMinus = temp; - jMinus = n; - } - } - - var sqrtNumReps = Math.Sqrt(NUM_ROUNDS); - kPlus *= sqrtNumReps; - kMinus *= sqrtNumReps; - - // We divide the failure probability by four because we have four tests: - // left and right tests for K+ and K-. - var cutoffLow = Math.Sqrt(0.5 * Math.Log(1.0 / (1.0 - P_LOW))) - 1.0 / (6.0 * sqrtNumReps); - var cutoffHigh = Math.Sqrt(0.5 * Math.Log(1.0 / (1.0 - P_HIGH))) - 1.0 / (6.0 * sqrtNumReps); - - TestContext.WriteLine($"K+ = {kPlus} | K- = {kMinus}"); - TestContext.WriteLine($"K+ max at position {jPlus} = {samples[jPlus]}"); - TestContext.WriteLine($"K- max at position {jMinus} = {samples[jMinus]}"); - TestContext.WriteLine($"Acceptable interval: [{cutoffLow}, {cutoffHigh}]"); - - Assert.That(kPlus, Is.GreaterThanOrEqualTo(cutoffLow), "K+ is lower than low cutoff"); - Assert.That(kPlus, Is.LessThanOrEqualTo(cutoffHigh), "K+ is higher than high cutoff"); - Assert.That(kMinus, Is.GreaterThanOrEqualTo(cutoffLow), "K- is lower than low cutoff"); - Assert.That(kMinus, Is.LessThanOrEqualTo(cutoffHigh), "K- is lower than high cutoff"); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestUniformGeneratorWithRange01() - { - var samples = new double[1_000]; - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.Uniform(rng); - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(-1.0, 1.0); - - Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.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 TestUniformGeneratorWithRange02() - { - var samples = new double[1_000]; - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.Uniform(rng); - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(0.0, 1.0); - - 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 TestUniformGeneratorWithRange04() - { - using var rng = new MultiThreadedRng(); - var samples = new double[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await rng.GetUniform(); - - 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 TestRange05Uint() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.Uniform(rng); - var distribution = new uint[101]; - var runs = 1_000_000; - for (var n = 0; n < runs; n++) - distribution[await dist.NextNumber(0, 100)]++; - - for (var n = 0; n < distribution.Length - 1; n++) - Assert.That(distribution[n], Is.GreaterThan(0)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestRange05Ulong() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.Uniform(rng); - var distribution = new uint[101]; - var runs = 1_000_000; - for (var n = 0; n < runs; n++) - distribution[await dist.NextNumber(0UL, 100)]++; - - for (var n = 0; n < distribution.Length - 1; n++) - Assert.That(distribution[n], Is.GreaterThan(0)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestRange05Float() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.Uniform(rng); - var distribution = new uint[101]; - var runs = 1_000_000; - for (var n = 0; n < runs; n++) - distribution[(uint)Math.Floor(await dist.NextNumber(0.0, 100.0))]++; - - for (var n = 0; n < distribution.Length - 1; n++) - Assert.That(distribution[n], Is.GreaterThan(0)); - } - - [Test] - [Category(TestCategories.NORMAL)] - public async Task TestDistribution001Uint() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.Uniform(rng); - var distribution = new uint[101]; - var runs = 1_000_000; - for (var n = 0; n < runs; n++) - distribution[await dist.NextNumber(0, 100)]++; - - Assert.That(distribution[..^1].Max() - distribution[..^1].Min(), Is.InRange(0, 600)); - } - - [Test] - [Category(TestCategories.NORMAL)] - public async Task TestDistribution001Ulong() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.Uniform(rng); - var distribution = new uint[101]; - var runs = 1_000_000; - for (var n = 0; n < runs; n++) - distribution[await dist.NextNumber(0UL, 100)]++; - - Assert.That(distribution[..^1].Max() - distribution[..^1].Min(), Is.InRange(0, 600)); - } - - [Test] - [Category(TestCategories.NORMAL)] - public async Task TestDistribution001Float() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.Uniform(rng); - var distribution = new uint[101]; - var runs = 1_000_000; - for (var n = 0; n < runs; n++) - distribution[(uint)Math.Floor(await dist.NextNumber(0.0, 100.0))]++; - - Assert.That(distribution[..^1].Max() - distribution[..^1].Min(), Is.InRange(0, 600)); - } - - [Test] - [Category(TestCategories.LONG_RUNNING)] - public async Task TestDistribution002Uint() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.Uniform(rng); - var distribution = new uint[101]; - var runs = 100_000_000; - for (var n = 0; n < runs; n++) - distribution[await dist.NextNumber(0, 100)]++; - - Assert.That(distribution[..^1].Max() - distribution[..^1].Min(), Is.InRange(0, 6_000)); - } - - [Test] - [Category(TestCategories.LONG_RUNNING)] - public async Task TestDistribution002Ulong() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.Uniform(rng); - var distribution = new uint[101]; - var runs = 100_000_000; - for (var n = 0; n < runs; n++) - distribution[await dist.NextNumber(0UL, 100)]++; - - Assert.That(distribution[..^1].Max() - distribution[..^1].Min(), Is.InRange(0, 6_000)); - } - - [Test] - [Category(TestCategories.LONG_RUNNING)] - public async Task TestDistribution002Float() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.Uniform(rng); - var distribution = new uint[101]; - var runs = 100_000_000; - for (var n = 0; n < runs; n++) - distribution[(uint)Math.Floor(await dist.NextNumber(0.0, 100.0))]++; - - Assert.That(distribution[..^1].Max() - distribution[..^1].Min(), Is.InRange(0, 6_000)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void NoRandomNumberGenerator01() - { - Assert.Throws(() => new FastRng.Double.Distributions.Uniform(null)); - } - } -} \ No newline at end of file diff --git a/FastRngTests/Double/Distributions/WeibullK05La1.cs b/FastRngTests/Double/Distributions/WeibullK05La1.cs deleted file mode 100644 index 8e7ce9d..0000000 --- a/FastRngTests/Double/Distributions/WeibullK05La1.cs +++ /dev/null @@ -1,84 +0,0 @@ -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 WeibullK05La1 - { - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestWeibullDistribution01() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.WeibullK05La1(rng); - var fra = new FrequencyAnalysis(); - - for (var n = 0; n < 100_000; n++) - fra.CountThis(await dist.NextNumber()); - - var result = fra.NormalizeAndPlotEvents(TestContext.WriteLine); - - Assert.That(result[0], Is.EqualTo(1.000000000).Within(0.2)); - Assert.That(result[1], Is.EqualTo(0.678415772).Within(0.09)); - Assert.That(result[2], Is.EqualTo(0.536595233).Within(0.09)); - - Assert.That(result[21], Is.EqualTo(0.147406264).Within(0.02)); - Assert.That(result[22], Is.EqualTo(0.142654414).Within(0.02)); - Assert.That(result[23], Is.EqualTo(0.138217760).Within(0.02)); - - Assert.That(result[50], Is.EqualTo(0.075769787).Within(0.095)); - - Assert.That(result[75], Is.EqualTo(0.053016799).Within(0.05)); - Assert.That(result[85], Is.EqualTo(0.047144614).Within(0.05)); - Assert.That(result[90], Is.EqualTo(0.044629109).Within(0.05)); - - Assert.That(result[97], Is.EqualTo(0.041484591).Within(0.05)); - Assert.That(result[98], Is.EqualTo(0.041067125).Within(0.05)); - Assert.That(result[99], Is.EqualTo(0.040656966).Within(0.05)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestWeibullGeneratorWithRange01() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.WeibullK05La1(rng); - var samples = new double[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(-1.0, 1.0); - - 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 TestWeibullGeneratorWithRange02() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Double.Distributions.WeibullK05La1(rng); - var samples = new double[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(0.0, 1.0); - - 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 void NoRandomNumberGenerator01() - { - Assert.Throws(() => new FastRng.Double.Distributions.WeibullK05La1(null)); - } - } -} \ No newline at end of file diff --git a/FastRngTests/Double/FrequencyAnalysis.cs b/FastRngTests/Double/FrequencyAnalysis.cs deleted file mode 100644 index 7f161dc..0000000 --- a/FastRngTests/Double/FrequencyAnalysis.cs +++ /dev/null @@ -1,85 +0,0 @@ -using System; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Runtime.CompilerServices; -using System.Text; - -namespace FastRngTests.Double -{ - [ExcludeFromCodeCoverage] - public sealed class FrequencyAnalysis - { - private readonly uint[] data; - - public FrequencyAnalysis(int samples = 100) - { - this.data = new uint[samples]; - } - - public void CountThis(double value) - { - var bucket = (int)Math.Floor(value * this.data.Length); - this.data[bucket]++; - } - - public double[] GetNormalizedEvents() - { - var max = (double) this.data.Max(); - var result = new double[this.data.Length]; - for (var n = 0; n < this.data.Length; n++) - { - result[n] = this.data[n] / max; - } - - return result; - } - - private double[] Normalize() - { - var max = (double)this.data.Max(); - var result = new double[this.data.Length]; - for (var n = 0; n < this.data.Length; n++) - result[n] = this.data[n] / max; - - return result; - } - - public double[] NormalizeAndPlotEvents(Action writer) - { - var result = this.Normalize(); - FrequencyAnalysis.Plot(result, writer, "Event Distribution"); - - return result; - } - - public void PlotOccurence(Action writer) - { - var data = this.data.Select(n => n > 0 ? 1.0 : 0.0).ToArray(); - FrequencyAnalysis.Plot(data, writer, "Occurrence Distribution"); - } - - private static void Plot(double[] data, Action writer, string name) - { - const int HEIGHT = 16; - - var values = new double[data.Length]; - for (var n = 0; n < data.Length; n++) - { - values[n] = data[n] * HEIGHT; - } - - var sb = new StringBuilder(); - for (var line = HEIGHT; line > 0; line--) - { - for (var column = 0; column < data.Length; column++) - sb.Append(values[column] >= line ? '█' : '░'); - - writer.Invoke(sb.ToString()); - sb.Clear(); - } - - writer.Invoke(name); - writer.Invoke(string.Empty); - } - } -} \ No newline at end of file diff --git a/FastRngTests/Double/MathToolsTests.cs b/FastRngTests/Double/MathToolsTests.cs deleted file mode 100644 index 85f7bff..0000000 --- a/FastRngTests/Double/MathToolsTests.cs +++ /dev/null @@ -1,341 +0,0 @@ -using System; -using System.Diagnostics.CodeAnalysis; -using FastRng.Double; -using NUnit.Framework; - -namespace FastRngTests.Double -{ - [ExcludeFromCodeCoverage] - public class MathToolsTests - { - #region Gamma - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void GammaTest01() - { - Assert.That(MathTools.Gamma(-0.5), Is.EqualTo(-3.544907701811087).Within(1e-6)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void GammaTest02() - { - Assert.That(MathTools.Gamma(0.1), Is.EqualTo(9.513507698668752).Within(1e-6)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void GammaTest03() - { - Assert.That(MathTools.Gamma(0.5), Is.EqualTo(1.772453850905517).Within(1e-6)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void GammaTest04() - { - Assert.That(MathTools.Gamma(1.0), Is.EqualTo(1.0).Within(1e-6)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void GammaTest05() - { - Assert.That(MathTools.Gamma(1.5), Is.EqualTo(0.8862269254527587).Within(1e-6)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void GammaTest06() - { - Assert.That(MathTools.Gamma(2.0), Is.EqualTo(1.0).Within(1e-6)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void GammaTest07() - { - Assert.That(MathTools.Gamma(3.0), Is.EqualTo(2.0).Within(1e-6)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void GammaTest08() - { - Assert.That(MathTools.Gamma(10.0), Is.EqualTo(362_880.0000000015).Within(1e-6)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void GammaTest09() - { - Assert.That(MathTools.Gamma(140.0), Is.EqualTo(9.6157231969402357e+238).Within(1e-6)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void GammaTest10() - { - Assert.That(MathTools.Gamma(170.0), Is.EqualTo(double.PositiveInfinity)); - } - - #endregion - - #region Factorial (integer) - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void FactorialInteger01() - { - Assert.That(MathTools.Factorial(0), Is.EqualTo(1)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void FactorialInteger02() - { - Assert.That(MathTools.Factorial(1), Is.EqualTo(1)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void FactorialInteger03() - { - Assert.That(MathTools.Factorial(2), Is.EqualTo(2)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void FactorialInteger04() - { - Assert.That(MathTools.Factorial(3), Is.EqualTo(6)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void FactorialInteger05() - { - Assert.That(MathTools.Factorial(4), Is.EqualTo(24)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void FactorialInteger06() - { - Assert.That(MathTools.Factorial(5), Is.EqualTo(120)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void FactorialInteger07() - { - Assert.That(MathTools.Factorial(6), Is.EqualTo(720)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void FactorialInteger08() - { - Assert.That(MathTools.Factorial(7), Is.EqualTo(5_040)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void FactorialInteger09() - { - Assert.That(MathTools.Factorial(8), Is.EqualTo(40_320)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void FactorialInteger10() - { - Assert.That(MathTools.Factorial(9), Is.EqualTo(362_880)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void FactorialInteger11() - { - Assert.That(MathTools.Factorial(10), Is.EqualTo(3_628_800)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void FactorialInteger12() - { - Assert.That(MathTools.Factorial(11), Is.EqualTo(39_916_800)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void FactorialInteger13() - { - Assert.That(MathTools.Factorial(12), Is.EqualTo(479_001_600)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void FactorialInteger14() - { - Assert.That(MathTools.Factorial(13), Is.EqualTo(6_227_020_800)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void FactorialInteger15() - { - Assert.That(MathTools.Factorial(14), Is.EqualTo(87_178_291_200)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void FactorialInteger16() - { - Assert.That(MathTools.Factorial(15), Is.EqualTo(1_307_674_368_000)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void FactorialInteger17() - { - Assert.That(MathTools.Factorial(16), Is.EqualTo(20_922_789_888_000)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void FactorialInteger18() - { - Assert.That(MathTools.Factorial(17), Is.EqualTo(355_687_428_096_000)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void FactorialInteger19() - { - Assert.That(MathTools.Factorial(18), Is.EqualTo(6_402_373_705_728_000)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void FactorialInteger20() - { - Assert.That(MathTools.Factorial(19), Is.EqualTo(121_645_100_408_832_000)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void FactorialInteger21() - { - Assert.That(MathTools.Factorial(20), Is.EqualTo(2_432_902_008_176_640_000)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void FactorialInteger22() - { - Assert.Throws(() => MathTools.Factorial(21)); - - // Note: 21! is not possible in C# until we got 128 bit integers, since: - // ulong.max == 18_446_744_073_709_551_615 < 51_090_942_171_709_400_000 - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void FactorialInteger23() - { - Assert.Throws(() => MathTools.Factorial(45_646)); - - // Note: 45_646! is not possible in C# since: - // ulong.max == 18_446_744_073_709_551_615 - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void FactorialInteger24() - { - Assert.Throws(() => MathTools.Factorial(-1)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void FactorialInteger25() - { - Assert.Throws(() => MathTools.Factorial(-6_565)); - } - - #endregion - - #region Factorial (floating point) - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void FactorialFloatingPoint01() - { - Assert.That(MathTools.Factorial(0.5), Is.EqualTo(0.886226925).Within(1e6)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void FactorialFloatingPoint02() - { - Assert.That(MathTools.Factorial(1.5), Is.EqualTo(1.329340388).Within(1e6)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void FactorialFloatingPoint03() - { - Assert.That(MathTools.Factorial(-1.5), Is.EqualTo(-1.329340388).Within(1e6)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void FactorialFloatingPoint04() - { - Assert.That(MathTools.Factorial(7.5), Is.EqualTo(14_034.407293483).Within(1e6)); - } - - #endregion - } -} \ No newline at end of file diff --git a/FastRngTests/Double/MultiThreadedRngTests.cs b/FastRngTests/Double/MultiThreadedRngTests.cs deleted file mode 100644 index c7c7c7f..0000000 --- a/FastRngTests/Double/MultiThreadedRngTests.cs +++ /dev/null @@ -1,625 +0,0 @@ -using System; -using System.Diagnostics.CodeAnalysis; -using System.Threading; -using System.Threading.Tasks; -using FastRng.Double; -using FastRng.Double.Distributions; -using NUnit.Framework; - -namespace FastRngTests.Double -{ - [ExcludeFromCodeCoverage] - public class MultiThreadedRngTests - { - private readonly IRandom rng = new MultiThreadedRng(); - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestRange01Uint() - { - var dist = new Uniform(this.rng); - for (uint n = 0; n < 1_000_000; n++) - Assert.That(await dist.NextNumber(n, 100_000 + n), Is.InRange(n, 100_000 + n)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestRange01Ulong() - { - var dist = new Uniform(this.rng); - for (ulong n = 0; n < 1_000_000; n++) - Assert.That(await dist.NextNumber(n, 100_000 + n), Is.InRange(n, 100_000 + n)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestRange01Float() - { - var dist = new Uniform(this.rng); - for (var n = 0.0; n < 1e6; n++) - Assert.That(await dist.NextNumber(n, 100_000 + n), Is.InRange(n, 100_000 + n)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestRange02Uint() - { - var dist = new Uniform(this.rng); - Assert.That(await dist.NextNumber(5, 5), Is.EqualTo(5)); - Assert.That(await dist.NextNumber(0, 0), Is.EqualTo(0)); - Assert.That(await dist.NextNumber(3_000_000_000, 3_000_000_000), Is.EqualTo(3_000_000_000)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestRange02Ulong() - { - var dist = new Uniform(this.rng); - Assert.That(await dist.NextNumber(5UL, 5), Is.EqualTo(5)); - Assert.That(await dist.NextNumber(0UL, 0), Is.EqualTo(0)); - Assert.That(await dist.NextNumber(3_000_000_000UL, 3_000_000_000), Is.EqualTo(3_000_000_000)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestRange02Float() - { - var dist = new Uniform(this.rng); - Assert.That(await dist.NextNumber(5f, 5f), Is.EqualTo(5)); - Assert.That(await dist.NextNumber(0f, 0f), Is.EqualTo(0)); - Assert.That(await dist.NextNumber(3e9, 3e9), Is.EqualTo(3e9)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestRange03Uint() - { - var dist = new Uniform(this.rng); - Assert.That(await dist.NextNumber(5, 6), Is.InRange(5, 6)); - Assert.That(await dist.NextNumber(0, 1), Is.InRange(0, 1)); - Assert.That(await dist.NextNumber(3_000_000_000, 3_000_000_002), Is.InRange(3_000_000_000, 3_000_000_002)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestRange03Ulong() - { - var dist = new Uniform(this.rng); - Assert.That(await dist.NextNumber(5UL, 6), Is.InRange(5, 6)); - Assert.That(await dist.NextNumber(0UL, 1), Is.InRange(0, 1)); - Assert.That(await dist.NextNumber(3_000_000_000UL, 3_000_000_002), Is.InRange(3_000_000_000, 3_000_000_002)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestRange03Float() - { - var dist = new Uniform(this.rng); - Assert.That(await dist.NextNumber(5f, 6), Is.InRange(5, 6)); - Assert.That(await dist.NextNumber(0f, 1), Is.InRange(0, 1)); - Assert.That(await dist.NextNumber(3e9, 3e9+2), Is.InRange(3e9, 3e9+2)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestRange04Uint() - { - var distUniform = new Uniform(this.rng); - var distNormal = new NormalS02M05(this.rng); - - Assert.That(await distUniform.NextNumber(10, 1), Is.InRange(1, 10)); - Assert.That(await distNormal.NextNumber(10, 1), Is.InRange(1, 10)); - - Assert.That(await distUniform.NextNumber(20, 1), Is.InRange(1, 20)); - Assert.That(await distNormal.NextNumber(20, 1), Is.InRange(1, 20)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestRange04Ulong() - { - var distUniform = new Uniform(this.rng); - var distNormal = new NormalS02M05(this.rng); - - Assert.That(await distUniform.NextNumber(10UL, 1), Is.InRange(1, 10)); - Assert.That(await distNormal.NextNumber(10UL, 1), Is.InRange(1, 10)); - - Assert.That(await distUniform.NextNumber(20UL, 1), Is.InRange(1, 20)); - Assert.That(await distNormal.NextNumber(20UL, 1), Is.InRange(1, 20)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestRange04Float() - { - var distUniform = new Uniform(this.rng); - var distNormal = new NormalS02M05(this.rng); - - Assert.That(await distUniform.NextNumber(10.0, 1), Is.InRange(1, 10)); - Assert.That(await distNormal.NextNumber(10.0, 1), Is.InRange(1, 10)); - - Assert.That(await distUniform.NextNumber(20.0, 1), Is.InRange(1, 20)); - Assert.That(await distNormal.NextNumber(20.0, 1), Is.InRange(1, 20)); - } - - [Test] - [Category(TestCategories.LONG_RUNNING)] - public async Task TestRange05() - { - var distUniform = new Uniform(this.rng); - var distLorentz = new CauchyLorentzX1(this.rng); - - var rngContains0 = false; - var rngContains1 = false; - - var uniformContains0 = false; - var uniformContains1 = false; - - var lorentzContains0 = false; - var lorentzContains1 = false; - - for (int i = 0; i < 100_000_000; i++) - { - var rngValue = await rng.GetUniform(); - var uniform = await distUniform.NextNumber(); - var lorentz = await distLorentz.NextNumber(); - - switch (rngValue) - { - case 0.0: - rngContains0 = true; - break; - case 1.0: - rngContains1 = true; - break; - } - - switch (uniform) - { - case 0.0: - uniformContains0 = true; - break; - case 1.0: - uniformContains1 = true; - break; - } - - switch (lorentz) - { - case 0.0: - lorentzContains0 = true; - break; - case 1.0: - lorentzContains1 = true; - break; - } - } - - TestContext.WriteLine($"Uniform generator contained 0? {rngContains0} (expected=false)"); - TestContext.WriteLine($"Uniform generator contained 1? {rngContains1} (expected=true)"); - TestContext.WriteLine($"Uniform distribution contained 0? {uniformContains0} (expected=false)"); - TestContext.WriteLine($"Uniform distribution contained 1? {uniformContains1} (expected=true)"); - TestContext.WriteLine($"Lorentz distribution contained 0? {lorentzContains0} (expected=false)"); - TestContext.WriteLine($"Lorentz distribution contained 1? {lorentzContains1} (expected=true)"); - - Assert.That(rngContains0, Is.False, "Uniform generator contained 0"); - Assert.That(rngContains1, Is.True, "Uniform generator does not contained 1"); - - Assert.That(uniformContains0, Is.False, "Uniform distribution contained 0"); - Assert.That(uniformContains1, Is.True, "Uniform distribution does not contained 1"); - - Assert.That(lorentzContains0, Is.False, "Lorentz distribution contained 0"); - Assert.That(lorentzContains1, Is.True, "Lorentz distribution does not contained 1"); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestStoppingProducers01() - { - var rng2 = new MultiThreadedRng(); - rng2.Dispose(); - - var masterToken = new CancellationTokenSource(TimeSpan.FromSeconds(16)).Token; - var wasCanceled = false; - - while(true) - { - var tokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(3)); - await rng2.GetUniform(tokenSource.Token); - if (tokenSource.IsCancellationRequested) - { - wasCanceled = true; - break; - } - - if (masterToken.IsCancellationRequested) - { - break; - } - } - - Assert.That(masterToken.IsCancellationRequested, Is.False, "Master token was used to stop test"); - Assert.That(wasCanceled, Is.True, "The consumer was not canceled"); - - var tokenSource2 = new CancellationTokenSource(TimeSpan.FromSeconds(3)); - await new NormalS02M05(rng2).NextNumber(tokenSource2.Token); - Assert.That(tokenSource2.IsCancellationRequested, Is.True); - - tokenSource2 = new CancellationTokenSource(TimeSpan.FromSeconds(3)); - await new NormalS02M05(rng2).NextNumber(-1d, 1d, tokenSource2.Token); - Assert.That(tokenSource2.IsCancellationRequested, Is.True); - - tokenSource2 = new CancellationTokenSource(TimeSpan.FromSeconds(3)); - await new NormalS02M05(rng2).NextNumber(0u, 6u, tokenSource2.Token); - Assert.That(tokenSource2.IsCancellationRequested, Is.True); - - tokenSource2 = new CancellationTokenSource(TimeSpan.FromSeconds(3)); - await new NormalS02M05(rng2).NextNumber(0ul, 6ul, tokenSource2.Token); - Assert.That(tokenSource2.IsCancellationRequested, Is.True); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task OneSeed01() - { - using var rng1 = new MultiThreadedRng(6); - using var rng2 = new MultiThreadedRng(6); - using var rng3 = new MultiThreadedRng(7); - - var rng1Sample = new double[10]; - for (var n = 0; n < rng1Sample.Length; n++) - rng1Sample[n] = await rng1.GetUniform(); - - var rng2Sample = new double[10]; - for (var n = 0; n < rng2Sample.Length; n++) - rng2Sample[n] = await rng2.GetUniform(); - - var rng3Sample = new double[10]; - for (var n = 0; n < rng3Sample.Length; n++) - rng3Sample[n] = await rng3.GetUniform(); - - Assert.That(rng1Sample, Is.EquivalentTo(rng2Sample)); - Assert.That(rng1Sample, Is.Not.EquivalentTo(rng3Sample)); - Assert.That(rng2Sample, Is.Not.EquivalentTo(rng3Sample)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TwoSeeds01() - { - using var rng1 = new MultiThreadedRng(3, 6); - using var rng2 = new MultiThreadedRng(3, 6); - using var rng3 = new MultiThreadedRng(3, 7); - using var rng4 = new MultiThreadedRng(6, 3); - - var rng1Sample = new double[10]; - for (var n = 0; n < rng1Sample.Length; n++) - rng1Sample[n] = await rng1.GetUniform(); - - var rng2Sample = new double[10]; - for (var n = 0; n < rng2Sample.Length; n++) - rng2Sample[n] = await rng2.GetUniform(); - - var rng3Sample = new double[10]; - for (var n = 0; n < rng3Sample.Length; n++) - rng3Sample[n] = await rng3.GetUniform(); - - var rng4Sample = new double[10]; - for (var n = 0; n < rng4Sample.Length; n++) - rng4Sample[n] = await rng4.GetUniform(); - - Assert.That(rng1Sample, Is.EquivalentTo(rng2Sample)); - Assert.That(rng1Sample, Is.Not.EquivalentTo(rng3Sample)); - Assert.That(rng1Sample, Is.Not.EquivalentTo(rng4Sample)); - Assert.That(rng2Sample, Is.Not.EquivalentTo(rng3Sample)); - Assert.That(rng2Sample, Is.Not.EquivalentTo(rng4Sample)); - Assert.That(rng3Sample, Is.Not.EquivalentTo(rng4Sample)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task NoSeed01() - { - using var rng1 = new MultiThreadedRng(); - using var rng2 = new MultiThreadedRng(); - using var rng3 = new MultiThreadedRng(); - - var rng1Sample = new double[10]; - for (var n = 0; n < rng1Sample.Length; n++) - rng1Sample[n] = await rng1.GetUniform(); - - var rng2Sample = new double[10]; - for (var n = 0; n < rng2Sample.Length; n++) - rng2Sample[n] = await rng2.GetUniform(); - - var rng3Sample = new double[10]; - for (var n = 0; n < rng3Sample.Length; n++) - rng3Sample[n] = await rng3.GetUniform(); - - Assert.That(rng1Sample, Is.Not.EquivalentTo(rng2Sample)); - Assert.That(rng1Sample, Is.Not.EquivalentTo(rng3Sample)); - Assert.That(rng2Sample, Is.Not.EquivalentTo(rng3Sample)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestCancellation01() - { - var tokenSource = new CancellationTokenSource(); - var token = tokenSource.Token; - tokenSource.Cancel(); - - using var rng2 = new MultiThreadedRng(); - var dist = new Uniform(rng2); - Assert.That(await dist.NextNumber(1, 100_000, token), Is.EqualTo(0)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestCancellation02() - { - var tokenSource = new CancellationTokenSource(); - var token = tokenSource.Token; - tokenSource.Cancel(); - - using var rng2 = new MultiThreadedRng(); - Assert.That(await rng2.GetUniform(token), Is.NaN); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestDeterministic01() - { - using var rng2 = new MultiThreadedRng(16); - - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.12712699).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.5764246).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.06033641).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.6822646).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.61201024).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.17746393).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.33456334).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.96167856).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.12944269).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.64489424).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.109665975).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.18188846).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.36097932).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.48192585).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.1617974).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.24791045).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.43913218).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.3343723).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.9428737).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.55195147).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.027495692).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.9621458).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.55794334).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.69002056).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.86020225).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.88220626).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.68816894).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.8583311).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.003915685).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.83575225).Within(1e-7f)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestDeterministic02() - { - using var rng2 = new MultiThreadedRng(16); - var dist = new Uniform(rng2); - - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(13)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(58)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(6)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(68)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(61)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(18)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(34)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(96)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(13)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(64)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(11)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(19)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(36)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(48)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(17)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(25)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(44)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(34)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(94)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(55)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(3)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(96)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(56)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(69)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(86)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(88)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(69)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(85)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(1)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(83)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestDeterministic03() - { - using var rng2 = new MultiThreadedRng(16); - var dist = new CauchyLorentzX0(rng2); - - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(11)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(17)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(1)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(2)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(18)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(14)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(65)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(11)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(22)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(3)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(37)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(9)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(12)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(4)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(10)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(8)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(22)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(2)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(3)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(20)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(4)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(1)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(84)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(9)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(19)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(2)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(1)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(10)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(4)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(56)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestDeterministic01b() - { - using var rng2 = new MultiThreadedRng(16, 362_436_069); - - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.12712699).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.5764246).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.06033641).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.6822646).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.61201024).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.17746393).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.33456334).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.96167856).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.12944269).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.64489424).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.109665975).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.18188846).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.36097932).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.48192585).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.1617974).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.24791045).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.43913218).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.3343723).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.9428737).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.55195147).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.027495692).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.9621458).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.55794334).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.69002056).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.86020225).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.88220626).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.68816894).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.8583311).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.003915685).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.83575225).Within(1e-7f)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestDeterministic02b() - { - using var rng2 = new MultiThreadedRng(16, 362_436_069); - var dist = new Uniform(rng2); - - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(13)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(58)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(6)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(68)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(61)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(18)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(34)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(96)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(13)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(64)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(11)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(19)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(36)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(48)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(17)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(25)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(44)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(34)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(94)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(55)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(3)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(96)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(56)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(69)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(86)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(88)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(69)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(85)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(1)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(83)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestDeterministic03b() - { - using var rng2 = new MultiThreadedRng(16, 362_436_069); - var dist = new CauchyLorentzX0(rng2); - - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(11)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(17)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(1)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(2)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(18)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(14)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(65)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(11)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(22)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(3)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(37)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(9)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(12)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(4)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(10)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(8)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(22)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(2)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(3)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(20)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(4)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(1)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(84)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(9)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(19)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(2)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(1)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(10)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(4)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(56)); - } - } -} \ No newline at end of file diff --git a/FastRngTests/Double/PerformanceTests.cs b/FastRngTests/Double/PerformanceTests.cs deleted file mode 100644 index 899d1a3..0000000 --- a/FastRngTests/Double/PerformanceTests.cs +++ /dev/null @@ -1,137 +0,0 @@ -using System; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Threading; -using System.Threading.Tasks; -using FastRng.Double; -using FastRng.Double.Distributions; -using MathNet.Numerics.Distributions; -using MathNet.Numerics.Random; -using NUnit.Framework; - -namespace FastRngTests.Double -{ - [ExcludeFromCodeCoverage] - public class PerformanceTests - { - #region FastRng - - [Test] - [Category(TestCategories.PERFORMANCE)] - public async Task Generate1MUniform() - { - using var rng = new MultiThreadedRng(); - var data = new double[1_000_000]; - var stopwatch = new Stopwatch(); - Thread.Sleep(TimeSpan.FromSeconds(10)); // Warm-up phase of generator - - stopwatch.Start(); - for (uint n = 0; n < data.Length; n++) - data[n] = await rng.GetUniform(); - - stopwatch.Stop(); - - TestContext.WriteLine($"Generated 1M uniform distributed random numbers in {stopwatch.Elapsed.Minutes} minute(s), {stopwatch.Elapsed.Seconds} second(s), and {stopwatch.Elapsed.Milliseconds} milliseconds."); - } - - [Test] - [Category(TestCategories.PERFORMANCE)] - public async Task Generate1MNormal() - { - using var rng = new MultiThreadedRng(); - var dist = new NormalS02M05(rng); - var data = new double[1_000_000]; - var stopwatch = new Stopwatch(); - Thread.Sleep(TimeSpan.FromSeconds(10)); // Warm-up phase of generator - - stopwatch.Start(); - for (uint n = 0; n < data.Length; n++) - data[n] = await dist.NextNumber(); - - stopwatch.Stop(); - - TestContext.WriteLine($"Generated 1M normal distributed random numbers in {stopwatch.Elapsed.Minutes} minute(s), {stopwatch.Elapsed.Seconds} second(s), and {stopwatch.Elapsed.Milliseconds} milliseconds."); - } - - [Test] - [Category(TestCategories.PERFORMANCE)] - public async Task Generate1MChiSquare() - { - using var rng = new MultiThreadedRng(); - var dist = new ChiSquareK4(rng); - var data = new double[1_000_000]; - var stopwatch = new Stopwatch(); - Thread.Sleep(TimeSpan.FromSeconds(10)); // Warm-up phase of generator - - stopwatch.Start(); - for (uint n = 0; n < data.Length; n++) - data[n] = await dist.NextNumber(); - - stopwatch.Stop(); - - TestContext.WriteLine($"Generated 1M chi-square distributed random numbers in {stopwatch.Elapsed.Minutes} minute(s), {stopwatch.Elapsed.Seconds} second(s), and {stopwatch.Elapsed.Milliseconds} milliseconds."); - } - - #endregion - - #region Math.NET - - [Test] - [Category(TestCategories.PERFORMANCE)] - public void ComparisonMathNet1MUniform() - { - var rng = new Xorshift(true); - var data = new float[1_000_000]; - var stopwatch = new Stopwatch(); - Thread.Sleep(TimeSpan.FromSeconds(10)); // Warm-up phase of generator - - stopwatch.Start(); - for (uint n = 0; n < data.Length; n++) - data[n] = (float) rng.NextDouble(); - - stopwatch.Stop(); - - TestContext.WriteLine($"Generated 1M uniform distributed random numbers by means of Math.NET in {stopwatch.Elapsed.Minutes} minute(s), {stopwatch.Elapsed.Seconds} second(s), and {stopwatch.Elapsed.Milliseconds} milliseconds."); - } - - [Test] - [Category(TestCategories.PERFORMANCE)] - public void ComparisonMathNet1MNormal() - { - var rng = new Xorshift(true); - var dist = new Normal(stddev: 0.2f, mean: 0.5f, randomSource: rng); - var data = new float[1_000_000]; - var stopwatch = new Stopwatch(); - Thread.Sleep(TimeSpan.FromSeconds(10)); // Warm-up phase of generator - - stopwatch.Start(); - for (uint n = 0; n < data.Length; n++) - data[n] = (float) dist.Sample(); - - stopwatch.Stop(); - - TestContext.WriteLine($"Generated 1M normal distributed random numbers by means of Math.NET in {stopwatch.Elapsed.Minutes} minute(s), {stopwatch.Elapsed.Seconds} second(s), and {stopwatch.Elapsed.Milliseconds} milliseconds."); - } - - [Test] - [Category(TestCategories.PERFORMANCE)] - public void ComparisonMathNet1MChiSquare() - { - var rng = new Xorshift(true); - var dist = new ChiSquared(4); - var data = new float[1_000_000]; - var stopwatch = new Stopwatch(); - Thread.Sleep(TimeSpan.FromSeconds(10)); // Warm-up phase of generator - - stopwatch.Start(); - for (uint n = 0; n < data.Length; n++) - data[n] = (float) dist.Sample(); - - stopwatch.Stop(); - - TestContext.WriteLine($"Generated 1M chi-squared distributed random numbers by means of Math.NET in {stopwatch.Elapsed.Minutes} minute(s), {stopwatch.Elapsed.Seconds} second(s), and {stopwatch.Elapsed.Milliseconds} milliseconds."); - } - - #endregion - } -} \ No newline at end of file diff --git a/FastRngTests/Double/RunningStatistics.cs b/FastRngTests/Double/RunningStatistics.cs deleted file mode 100644 index 4a6141d..0000000 --- a/FastRngTests/Double/RunningStatistics.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System; -using System.Diagnostics.CodeAnalysis; - -namespace FastRngTests.Double -{ - [ExcludeFromCodeCoverage] - internal sealed class RunningStatistics - { - private double previousM; - private double previousS; - private double nextM; - private double nextS; - - public RunningStatistics() - { - } - - public int NumberRecords { get; private set; } = 0; - - public void Clear() => this.NumberRecords = 0; - - public void Push(double x) - { - this.NumberRecords++; - - // See Knuth TAOCP vol 2, 3rd edition, page 232 - if (this.NumberRecords == 1) - { - this.previousM = this.nextM = x; - this.previousS = 0.0; - } - else - { - this.nextM = this.previousM + (x - this.previousM) / this.NumberRecords; - this.nextS = this.previousS + (x - this.previousM) * (x - this.nextM); - - // set up for next iteration - this.previousM = this.nextM; - this.previousS = this.nextS; - } - } - - public double Mean => this.NumberRecords > 0 ? this.nextM : 0.0; - - public double Variance => this.NumberRecords > 1 ? this.nextS / (this.NumberRecords - 1) : 0.0; - - public double StandardDeviation => Math.Sqrt(this.Variance); - } -} \ No newline at end of file diff --git a/FastRngTests/FastRngTests.csproj b/FastRngTests/FastRngTests.csproj index 63468fa..07d3755 100644 --- a/FastRngTests/FastRngTests.csproj +++ b/FastRngTests/FastRngTests.csproj @@ -1,20 +1,23 @@ - net5.0 + net7.0 false + + latest - - - - + + + + + diff --git a/FastRngTests/Float/DecisionTester.cs b/FastRngTests/Float/DecisionTester.cs deleted file mode 100644 index 88001b5..0000000 --- a/FastRngTests/Float/DecisionTester.cs +++ /dev/null @@ -1,64 +0,0 @@ -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 diff --git a/FastRngTests/Float/Distributions/BetaA2B2.cs b/FastRngTests/Float/Distributions/BetaA2B2.cs deleted file mode 100644 index 44ec472..0000000 --- a/FastRngTests/Float/Distributions/BetaA2B2.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Threading.Tasks; -using FastRng.Float; -using NUnit.Framework; - -namespace FastRngTests.Float.Distributions -{ - [ExcludeFromCodeCoverage] - public class BetaA2B2 - { - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestBetaDistribution01() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Float.Distributions.BetaA2B2(rng); - var fqa = new Float.FrequencyAnalysis(); - - for (var n = 0; n < 100_000; n++) - fqa.CountThis(await dist.NextNumber()); - - var result = fqa.NormalizeAndPlotEvents(TestContext.WriteLine); - - Assert.That(result[0], Is.EqualTo(0.0396f).Within(0.3f)); - Assert.That(result[1], Is.EqualTo(0.0784f).Within(0.3f)); - Assert.That(result[2], Is.EqualTo(0.1164f).Within(0.3f)); - - Assert.That(result[21], Is.EqualTo(0.6864f).Within(0.3f)); - Assert.That(result[22], Is.EqualTo(0.7084f).Within(0.3f)); - Assert.That(result[23], Is.EqualTo(0.7296f).Within(0.3f)); - - Assert.That(result[50], Is.EqualTo(0.9996f).Within(0.3f)); - - Assert.That(result[75], Is.EqualTo(0.7296f).Within(0.3f)); - Assert.That(result[85], Is.EqualTo(0.4816f).Within(0.3f)); - Assert.That(result[90], Is.EqualTo(0.3276f).Within(0.3f)); - - Assert.That(result[97], Is.EqualTo(0.0784f).Within(0.3f)); - Assert.That(result[98], Is.EqualTo(0.0396f).Within(0.3f)); - Assert.That(result[99], Is.EqualTo(0.0000f).Within(0.3f)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestBetaGeneratorWithRange01() - { - using var rng = new MultiThreadedRng(); - var samples = new float[1_000]; - var dist = new FastRng.Float.Distributions.BetaA2B2(rng); - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(-1.0f, 1.0f); - - Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range"); - Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range"); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestBetaGeneratorWithRange02() - { - using var rng = new MultiThreadedRng(); - var samples = new float[1_000]; - var dist = new FastRng.Float.Distributions.BetaA2B2(rng); - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(0.0f, 1.0f); - - Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range"); - Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range"); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void NoRandomNumberGenerator01() - { - Assert.Throws(() => new FastRng.Float.Distributions.BetaA2B2(null)); - } - } -} \ No newline at end of file diff --git a/FastRngTests/Float/Distributions/BetaA2B5.cs b/FastRngTests/Float/Distributions/BetaA2B5.cs deleted file mode 100644 index b88bba0..0000000 --- a/FastRngTests/Float/Distributions/BetaA2B5.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Threading.Tasks; -using FastRng.Float; -using NUnit.Framework; - -namespace FastRngTests.Float.Distributions -{ - [ExcludeFromCodeCoverage] - public class BetaA2B5 - { - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestBetaDistribution01() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Float.Distributions.BetaA2B5(rng); - var fqa = new Float.FrequencyAnalysis(); - - for (var n = 0; n < 100_000; n++) - fqa.CountThis(await dist.NextNumber()); - - var result = fqa.NormalizeAndPlotEvents(TestContext.WriteLine); - - Assert.That(result[0], Is.EqualTo(0.11719271f).Within(0.3f)); - Assert.That(result[1], Is.EqualTo(0.22505783f).Within(0.3f)); - Assert.That(result[2], Is.EqualTo(0.32401717f).Within(0.3f)); - - Assert.That(result[21], Is.EqualTo(0.99348410f).Within(0.3f)); - Assert.That(result[22], Is.EqualTo(0.98639433f).Within(0.3f)); - Assert.That(result[23], Is.EqualTo(0.97684451f).Within(0.3f)); - - Assert.That(result[50], Is.EqualTo(0.35868592f).Within(0.3f)); - - Assert.That(result[75], Is.EqualTo(0.03076227f).Within(0.03f)); - Assert.That(result[85], Is.EqualTo(0.00403061f).Within(0.03f)); - Assert.That(result[90], Is.EqualTo(0.00109800f).Within(0.01f)); - - Assert.That(result[97], Is.EqualTo(0.00000191f).Within(0.000003f)); - Assert.That(result[98], Is.EqualTo(0.00000012f).Within(0.0000003f)); - Assert.That(result[99], Is.EqualTo(0.00000000f).Within(0.0000003f)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestBetaGeneratorWithRange01() - { - using var rng = new MultiThreadedRng(); - var samples = new float[1_000]; - var dist = new FastRng.Float.Distributions.BetaA2B5(rng); - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(-1.0f, 1.0f); - - Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range"); - Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range"); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestBetaGeneratorWithRange02() - { - using var rng = new MultiThreadedRng(); - var samples = new float[1_000]; - var dist = new FastRng.Float.Distributions.BetaA2B5(rng); - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(0.0f, 1.0f); - - Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range"); - Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range"); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void NoRandomNumberGenerator01() - { - Assert.Throws(() => new FastRng.Float.Distributions.BetaA2B5(null)); - } - } -} \ No newline at end of file diff --git a/FastRngTests/Float/Distributions/BetaA5B2.cs b/FastRngTests/Float/Distributions/BetaA5B2.cs deleted file mode 100644 index 306c504..0000000 --- a/FastRngTests/Float/Distributions/BetaA5B2.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Threading.Tasks; -using FastRng.Float; -using NUnit.Framework; - -namespace FastRngTests.Float.Distributions -{ - [ExcludeFromCodeCoverage] - public class BetaA5B2 - { - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestBetaDistribution01() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Float.Distributions.BetaA5B2(rng); - var fqa = new FrequencyAnalysis(); - - for (var n = 0; n < 100_000; n++) - fqa.CountThis(await dist.NextNumber()); - - var result = fqa.NormalizeAndPlotEvents(TestContext.WriteLine); - - Assert.That(result[0], Is.EqualTo(0.0000001f).Within(0.0000003f)); - Assert.That(result[1], Is.EqualTo(0.0000019f).Within(0.00001f)); - Assert.That(result[2], Is.EqualTo(0.0000096f).Within(0.0004f)); - - Assert.That(result[21], Is.EqualTo(0.0222918f).Within(0.03f)); - Assert.That(result[22], Is.EqualTo(0.0262883f).Within(0.03f)); - Assert.That(result[23], Is.EqualTo(0.0307623f).Within(0.03f)); - - Assert.That(result[50], Is.EqualTo(0.4044237f).Within(0.2f)); - - Assert.That(result[75], Is.EqualTo(0.9768445f).Within(0.15f)); - Assert.That(result[85], Is.EqualTo(0.9552714f).Within(0.15f)); - Assert.That(result[90], Is.EqualTo(0.8004420f).Within(0.35f)); - - Assert.That(result[97], Is.EqualTo(0.2250578f).Within(0.03f)); - Assert.That(result[98], Is.EqualTo(0.1171927f).Within(0.03f)); - Assert.That(result[99], Is.EqualTo(0f).Within(0.0004f)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestBetaGeneratorWithRange01() - { - using var rng = new MultiThreadedRng(); - var samples = new float[1_000]; - var dist = new FastRng.Float.Distributions.BetaA5B2(rng); - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(-1.0f, 1.0f); - - Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range"); - Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range"); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestBetaGeneratorWithRange02() - { - using var rng = new MultiThreadedRng(); - var samples = new float[1_000]; - var dist = new FastRng.Float.Distributions.BetaA5B2(rng); - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(0.0f, 1.0f); - - Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range"); - Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range"); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void NoRandomNumberGenerator01() - { - Assert.Throws(() => new FastRng.Float.Distributions.BetaA5B2(null)); - } - } -} \ No newline at end of file diff --git a/FastRngTests/Float/Distributions/CauchyLorentzX0.cs b/FastRngTests/Float/Distributions/CauchyLorentzX0.cs deleted file mode 100644 index 0b0d2b6..0000000 --- a/FastRngTests/Float/Distributions/CauchyLorentzX0.cs +++ /dev/null @@ -1,87 +0,0 @@ -using System; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Threading.Tasks; -using FastRng.Float; -using NUnit.Framework; - -namespace FastRngTests.Float.Distributions -{ - [ExcludeFromCodeCoverage] - public class CauchyLorentzX0 - { - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestCauchyDistribution01() - { - // The properties of the cauchy distribution cannot be tested by mean, media or variance, - // cf. https://en.wikipedia.org/wiki/Cauchy_distribution#Explanation_of_undefined_moments - - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Float.Distributions.CauchyLorentzX0(rng); - var fqa = new FrequencyAnalysis(); - - for (var n = 0; n < 100_000; n++) - fqa.CountThis(await dist.NextNumber()); - - var result = fqa.NormalizeAndPlotEvents(TestContext.WriteLine); - - Assert.That(result[0], Is.EqualTo(0.976990739772031f).Within(0.06f)); - Assert.That(result[1], Is.EqualTo(0.948808314586299f).Within(0.06f)); - Assert.That(result[2], Is.EqualTo(0.905284997403441f).Within(0.06f)); - - Assert.That(result[21], Is.EqualTo(0.168965864241396f).Within(0.04f)); - Assert.That(result[22], Is.EqualTo(0.156877686354491f).Within(0.04f)); - Assert.That(result[23], Is.EqualTo(0.145970509936354f).Within(0.04f)); - - Assert.That(result[50], Is.EqualTo(0.036533159835978f).Within(0.01f)); - - Assert.That(result[75], Is.EqualTo(0.016793067514802f).Within(0.01f)); - Assert.That(result[85], Is.EqualTo(0.01316382933791f).Within(0.005f)); - Assert.That(result[90], Is.EqualTo(0.011773781734516f).Within(0.005f)); - - Assert.That(result[97], Is.EqualTo(0.010168596941156f).Within(0.005f)); - Assert.That(result[98], Is.EqualTo(0.009966272570142f).Within(0.005f)); - Assert.That(result[99], Is.EqualTo(0.00976990739772f).Within(0.005f)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestCauchyGeneratorWithRange01() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Float.Distributions.CauchyLorentzX0(rng); - var samples = new float[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(-1.0f, 1.0f); - - Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min is out of range"); - Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range"); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestCauchyGeneratorWithRange02() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Float.Distributions.CauchyLorentzX0(rng); - var samples = new float[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(0.0f, 1.0f); - - Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range"); - Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range"); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void NoRandomNumberGenerator01() - { - Assert.Throws(() => new FastRng.Float.Distributions.CauchyLorentzX0(null)); - } - } -} \ No newline at end of file diff --git a/FastRngTests/Float/Distributions/CauchyLorentzX1.cs b/FastRngTests/Float/Distributions/CauchyLorentzX1.cs deleted file mode 100644 index 70b63f3..0000000 --- a/FastRngTests/Float/Distributions/CauchyLorentzX1.cs +++ /dev/null @@ -1,87 +0,0 @@ -using System; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Threading.Tasks; -using FastRng.Float; -using NUnit.Framework; - -namespace FastRngTests.Float.Distributions -{ - [ExcludeFromCodeCoverage] - public class CauchyLorentzX1 - { - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestCauchyDistribution01() - { - // The properties of the cauchy distribution cannot be tested by mean, media or variance, - // cf. https://en.wikipedia.org/wiki/Cauchy_distribution#Explanation_of_undefined_moments - - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Float.Distributions.CauchyLorentzX1(rng); - var fqa = new FrequencyAnalysis(); - - for (var n = 0; n < 100_000; n++) - fqa.CountThis(await dist.NextNumber()); - - var result = fqa.NormalizeAndPlotEvents(TestContext.WriteLine); - - Assert.That(result[0], Is.EqualTo(0.009966272570142f).Within(0.003f)); - Assert.That(result[1], Is.EqualTo(0.010168596941156f).Within(0.004f)); - Assert.That(result[2], Is.EqualTo(0.010377123221893f).Within(0.005f)); - - Assert.That(result[21], Is.EqualTo(0.015956672819692f).Within(0.005f)); - Assert.That(result[22], Is.EqualTo(0.016366904083094f).Within(0.005f)); - Assert.That(result[23], Is.EqualTo(0.016793067514802f).Within(0.005f)); - - Assert.That(result[50], Is.EqualTo(0.039454644029179f).Within(0.015f)); - - Assert.That(result[75], Is.EqualTo(0.145970509936354f).Within(0.03f)); - Assert.That(result[85], Is.EqualTo(0.333365083503296f).Within(0.1f)); - Assert.That(result[90], Is.EqualTo(0.545171628270584f).Within(0.1f)); - - Assert.That(result[97], Is.EqualTo(0.948808314586302f).Within(0.06f)); - Assert.That(result[98], Is.EqualTo(0.976990739772032f).Within(0.03f)); - Assert.That(result[99], Is.EqualTo(0.986760647169751f).Within(0.02f)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestCauchyGeneratorWithRange01() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Float.Distributions.CauchyLorentzX0(rng); - var samples = new float[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(-1.0f, 1.0f); - - Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min is out of range"); - Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range"); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestCauchyGeneratorWithRange02() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Float.Distributions.CauchyLorentzX0(rng); - var samples = new float[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(0.0f, 1.0f); - - Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range"); - Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range"); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void NoRandomNumberGenerator01() - { - Assert.Throws(() => new FastRng.Float.Distributions.CauchyLorentzX1(null)); - } - } -} \ No newline at end of file diff --git a/FastRngTests/Float/Distributions/ChiSquareK1.cs b/FastRngTests/Float/Distributions/ChiSquareK1.cs deleted file mode 100644 index d29d32b..0000000 --- a/FastRngTests/Float/Distributions/ChiSquareK1.cs +++ /dev/null @@ -1,87 +0,0 @@ -using System; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Threading.Tasks; -using FastRng.Float; -using NUnit.Framework; - -namespace FastRngTests.Float.Distributions -{ - [ExcludeFromCodeCoverage] - public class ChiSquareK1 - { - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestChiSquareDistribution01() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Float.Distributions.ChiSquareK1(rng); - var fqa = new FrequencyAnalysis(); - - for (var n = 0; n < 100_000; n++) - { - var value = await dist.NextNumber(); - fqa.CountThis(value); - } - - var result = fqa.NormalizeAndPlotEvents(TestContext.WriteLine); - - Assert.That(result[0], Is.EqualTo(1.00032041964207f).Within(0.004f)); - Assert.That(result[1], Is.EqualTo(0.70380551227703f).Within(0.05f)); - Assert.That(result[2], Is.EqualTo(0.571788691668126f).Within(0.05f)); - - Assert.That(result[21], Is.EqualTo(0.192011337664754f).Within(0.07f)); - Assert.That(result[22], Is.EqualTo(0.186854182385981f).Within(0.07f)); - Assert.That(result[23], Is.EqualTo(0.182007652359976f).Within(0.07f)); - - Assert.That(result[50], Is.EqualTo(0.109088865614875f).Within(0.06f)); - - Assert.That(result[75], Is.EqualTo(0.07886274821701f).Within(0.02f)); - Assert.That(result[85], Is.EqualTo(0.070520397849883f).Within(0.02f)); - Assert.That(result[90], Is.EqualTo(0.066863009640287f).Within(0.02f)); - - Assert.That(result[97], Is.EqualTo(0.062214737436948f).Within(0.02f)); - Assert.That(result[98], Is.EqualTo(0.061590997922187f).Within(0.02f)); - Assert.That(result[99], Is.EqualTo(0.060976622578824f).Within(0.02f)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestChiSquareGeneratorWithRange01() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Float.Distributions.ChiSquareK1(rng); - var samples = new float[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(-1.0f, 1.0f); - - Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range"); - Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range"); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestChiSquareGeneratorWithRange02() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Float.Distributions.ChiSquareK1(rng); - var samples = new float[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(0.0f, 1.0f); - - Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range"); - Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range"); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void NoRandomNumberGenerator01() - { - Assert.Throws(() => new FastRng.Float.Distributions.ChiSquareK1(null)); - } - } -} \ No newline at end of file diff --git a/FastRngTests/Float/Distributions/ChiSquareK10.cs b/FastRngTests/Float/Distributions/ChiSquareK10.cs deleted file mode 100644 index 304ca89..0000000 --- a/FastRngTests/Float/Distributions/ChiSquareK10.cs +++ /dev/null @@ -1,87 +0,0 @@ -using System; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Threading.Tasks; -using FastRng.Float; -using NUnit.Framework; - -namespace FastRngTests.Float.Distributions -{ - [ExcludeFromCodeCoverage] - public class ChiSquareK10 - { - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestChiSquareDistribution01() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Float.Distributions.ChiSquareK10(rng); - var fqa = new FrequencyAnalysis(); - - for (var n = 0; n < 100_000; n++) - { - var value = await dist.NextNumber(); - fqa.CountThis(value); - } - - var result = fqa.NormalizeAndPlotEvents(TestContext.WriteLine); - - Assert.That(result[0], Is.EqualTo(0.0000000164021588f).Within(0.0000002f)); - Assert.That(result[1], Is.EqualTo(0.0000002611256437f).Within(0.000003f)); - Assert.That(result[2], Is.EqualTo(0.0000013153553250f).Within(0.00002f)); - - Assert.That(result[21], Is.EqualTo(0.003459320622874f).Within(0.005f)); - Assert.That(result[22], Is.EqualTo(0.004111875573379f).Within(0.005f)); - Assert.That(result[23], Is.EqualTo(0.004850674298859f).Within(0.005f)); - - Assert.That(result[50], Is.EqualTo(0.086418773275056f).Within(0.05f)); - - Assert.That(result[75], Is.EqualTo(0.376092741436046f).Within(0.08f)); - Assert.That(result[85], Is.EqualTo(0.586569751611096f).Within(0.08f)); - Assert.That(result[90], Is.EqualTo(0.717189736168766f).Within(0.08f)); - - Assert.That(result[97], Is.EqualTo(0.931477764640217f).Within(0.08f)); - Assert.That(result[98], Is.EqualTo(0.965244855212136f).Within(0.08f)); - Assert.That(result[99], Is.EqualTo(0.999827884370044f).Within(0.08f)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestChiSquareGeneratorWithRange01() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Float.Distributions.ChiSquareK10(rng); - var samples = new float[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(-1.0f, 1.0f); - - Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range"); - Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range"); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestChiSquareGeneratorWithRange02() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Float.Distributions.ChiSquareK10(rng); - var samples = new float[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(0.0f, 1.0f); - - Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range"); - Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range"); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void NoRandomNumberGenerator01() - { - Assert.Throws(() => new FastRng.Float.Distributions.ChiSquareK10(null)); - } - } -} \ No newline at end of file diff --git a/FastRngTests/Float/Distributions/ChiSquareK4.cs b/FastRngTests/Float/Distributions/ChiSquareK4.cs deleted file mode 100644 index 05ae266..0000000 --- a/FastRngTests/Float/Distributions/ChiSquareK4.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Threading.Tasks; -using FastRng.Float; -using NUnit.Framework; - -namespace FastRngTests.Float.Distributions -{ - [ExcludeFromCodeCoverage] - public class ChiSquareK4 - { - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestChiSquareDistribution01() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Float.Distributions.ChiSquareK4(rng); - var fqa = new FrequencyAnalysis(); - - for (var n = 0; n < 100_000; n++) - fqa.CountThis(await dist.NextNumber()); - - var result = fqa.NormalizeAndPlotEvents(TestContext.WriteLine); - - Assert.That(result[0], Is.EqualTo(0.016417705906679f).Within(0.02f)); - Assert.That(result[1], Is.EqualTo(0.032671644513723f).Within(0.02f)); - Assert.That(result[2], Is.EqualTo(0.048763041010352f).Within(0.02f)); - - Assert.That(result[21], Is.EqualTo(0.32518779111264f).Within(0.05f)); - Assert.That(result[22], Is.EqualTo(0.338273451612642f).Within(0.05f)); - Assert.That(result[23], Is.EqualTo(0.351220492939994f).Within(0.05f)); - - Assert.That(result[50], Is.EqualTo(0.65209223303425f).Within(0.08f)); - - Assert.That(result[75], Is.EqualTo(0.857562207152294f).Within(0.099f)); - Assert.That(result[85], Is.EqualTo(0.923072405412387f).Within(0.099f)); - Assert.That(result[90], Is.EqualTo(0.952623623874265f).Within(0.099f)); - - Assert.That(result[97], Is.EqualTo(0.990616879396201f).Within(0.099f)); - Assert.That(result[98], Is.EqualTo(0.995734077068522f).Within(0.099f)); - Assert.That(result[99], Is.EqualTo(1.00077558852585f).Within(0.1f)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestChiSquareGeneratorWithRange01() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Float.Distributions.ChiSquareK4(rng); - var samples = new float[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(-1.0f, 1.0f); - - Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range"); - Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range"); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestChiSquareGeneratorWithRange02() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Float.Distributions.ChiSquareK4(rng); - var samples = new float[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(0.0f, 1.0f); - - Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range"); - Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range"); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void NoRandomNumberGenerator01() - { - Assert.Throws(() => new FastRng.Float.Distributions.ChiSquareK4(null)); - } - } -} \ No newline at end of file diff --git a/FastRngTests/Float/Distributions/ExponentialLa10.cs b/FastRngTests/Float/Distributions/ExponentialLa10.cs deleted file mode 100644 index 919cf44..0000000 --- a/FastRngTests/Float/Distributions/ExponentialLa10.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Threading.Tasks; -using FastRng.Float; -using NUnit.Framework; - -namespace FastRngTests.Float.Distributions -{ - [ExcludeFromCodeCoverage] - public class ExponentialLa10 - { - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestExponentialDistribution01() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Float.Distributions.ExponentialLa10(rng); - var fqa = new FrequencyAnalysis(); - - for (var n = 0; n < 100_000; n++) - fqa.CountThis(await dist.NextNumber()); - - var result = fqa.NormalizeAndPlotEvents(TestContext.WriteLine); - - Assert.That(result[0], Is.EqualTo(1.00075018434777f).Within(0.05f)); - Assert.That(result[1], Is.EqualTo(0.905516212904248f).Within(0.05f)); - Assert.That(result[2], Is.EqualTo(0.81934495207398f).Within(0.05f)); - - Assert.That(result[21], Is.EqualTo(0.122548293148741f).Within(0.12f)); - Assert.That(result[22], Is.EqualTo(0.110886281157421f).Within(0.12f)); - Assert.That(result[23], Is.EqualTo(0.10033405633809f).Within(0.12f)); - - Assert.That(result[50], Is.EqualTo(0.00674300170146f).Within(0.005f)); - - Assert.That(result[75], Is.EqualTo(0.000553499285385f).Within(0.001f)); - Assert.That(result[85], Is.EqualTo(0.000203621007796f).Within(0.001f)); - Assert.That(result[90], Is.EqualTo(0.00012350238419f).Within(0.001f)); - - Assert.That(result[97], Is.EqualTo(0.0000613294689720f).Within(0.0008f)); - Assert.That(result[98], Is.EqualTo(0.0000554931983541f).Within(0.0008f)); - Assert.That(result[99], Is.EqualTo(0.0000502123223173f).Within(0.0008f)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestExponentialGeneratorWithRange01() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Float.Distributions.ExponentialLa10(rng); - var samples = new float[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(-1.0f, 1.0f); - - Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range"); - Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range"); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestExponentialGeneratorWithRange02() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Float.Distributions.ExponentialLa10(rng); - var samples = new float[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(0.0f, 1.0f); - - Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range"); - Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range"); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void NoRandomNumberGenerator01() - { - Assert.Throws(() => new FastRng.Float.Distributions.ExponentialLa10(null)); - } - } -} \ No newline at end of file diff --git a/FastRngTests/Float/Distributions/ExponentialLa5.cs b/FastRngTests/Float/Distributions/ExponentialLa5.cs deleted file mode 100644 index ad4b41b..0000000 --- a/FastRngTests/Float/Distributions/ExponentialLa5.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Threading.Tasks; -using FastRng.Float; -using NUnit.Framework; - -namespace FastRngTests.Float.Distributions -{ - [ExcludeFromCodeCoverage] - public class ExponentialLa5 - { - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestExponentialDistribution01() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Float.Distributions.ExponentialLa5(rng); - var fqa = new FrequencyAnalysis(); - - for (var n = 0; n < 100_000; n++) - fqa.CountThis(await dist.NextNumber()); - - var result = fqa.NormalizeAndPlotEvents(TestContext.WriteLine); - - Assert.That(result[0], Is.EqualTo(1.0002177398625f).Within(0.05f)); - Assert.That(result[1], Is.EqualTo(0.951436545064811f).Within(0.05f)); - Assert.That(result[2], Is.EqualTo(0.905034437210948f).Within(0.05f)); - - Assert.That(result[21], Is.EqualTo(0.35001394450853f).Within(0.05f)); - Assert.That(result[22], Is.EqualTo(0.332943563002074f).Within(0.05f)); - Assert.That(result[23], Is.EqualTo(0.31670571382568f).Within(0.05f)); - - Assert.That(result[50], Is.EqualTo(0.082102871800213f).Within(0.01f)); - - Assert.That(result[75], Is.EqualTo(0.023522866606758f).Within(0.01f)); - Assert.That(result[85], Is.EqualTo(0.014267339801329f).Within(0.01f)); - Assert.That(result[90], Is.EqualTo(0.011111415409621f).Within(0.01f)); - - Assert.That(result[97], Is.EqualTo(0.007830082099077f).Within(0.008f)); - Assert.That(result[98], Is.EqualTo(0.007448204488898f).Within(0.008f)); - Assert.That(result[99], Is.EqualTo(0.007084951269538f).Within(0.008f)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestExponentialGeneratorWithRange01() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Float.Distributions.ExponentialLa5(rng); - var samples = new float[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(-1.0f, 1.0f); - - Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range"); - Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range"); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestExponentialGeneratorWithRange02() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Float.Distributions.ExponentialLa5(rng); - var samples = new float[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(0.0f, 1.0f); - - Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range"); - Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range"); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void NoRandomNumberGenerator01() - { - Assert.Throws(() => new FastRng.Float.Distributions.ExponentialLa5(null)); - } - } -} \ No newline at end of file diff --git a/FastRngTests/Float/Distributions/GammaA5B15.cs b/FastRngTests/Float/Distributions/GammaA5B15.cs deleted file mode 100644 index 76e536a..0000000 --- a/FastRngTests/Float/Distributions/GammaA5B15.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Threading.Tasks; -using FastRng.Float; -using NUnit.Framework; - -namespace FastRngTests.Float.Distributions -{ - [ExcludeFromCodeCoverage] - public class GammaA5B15 - { - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestGammaDistribution01() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Float.Distributions.GammaA5B15(rng); - var fra = new FrequencyAnalysis(); - - for (var n = 0; n < 100_000; n++) - fra.CountThis(await dist.NextNumber()); - - var result = fra.NormalizeAndPlotEvents(TestContext.WriteLine); - - Assert.That(result[0], Is.EqualTo(0.0000929594237282f).Within(0.0008f)); - Assert.That(result[1], Is.EqualTo(0.0012801746797876f).Within(0.002f)); - Assert.That(result[2], Is.EqualTo(0.0055781488254349f).Within(0.004f)); - - Assert.That(result[21], Is.EqualTo(0.9331608887752720f).Within(0.09f)); - Assert.That(result[22], Is.EqualTo(0.9594734828891280f).Within(0.09f)); - Assert.That(result[23], Is.EqualTo(0.9790895765535350f).Within(0.09f)); - - Assert.That(result[50], Is.EqualTo(0.3478287795336570f).Within(0.06f)); - - Assert.That(result[75], Is.EqualTo(0.0403399049422936f).Within(0.009f)); - Assert.That(result[85], Is.EqualTo(0.0163628388658126f).Within(0.009f)); - Assert.That(result[90], Is.EqualTo(0.0097147611446660f).Within(0.005f)); - - Assert.That(result[97], Is.EqualTo(0.0041135143233153f).Within(0.008f)); - Assert.That(result[98], Is.EqualTo(0.0036872732029996f).Within(0.008f)); - Assert.That(result[99], Is.EqualTo(0.0033038503429554f).Within(0.008f)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestGammaGeneratorWithRange01() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Float.Distributions.GammaA5B15(rng); - var samples = new float[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(-1.0f, 1.0f); - - Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min is out of range"); - Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range"); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestGammaGeneratorWithRange02() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Float.Distributions.GammaA5B15(rng); - var samples = new float[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(0.0f, 1.0f); - - Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range"); - Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range"); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void NoRandomNumberGenerator01() - { - Assert.Throws(() => new FastRng.Float.Distributions.GammaA5B15(null)); - } - } -} \ No newline at end of file diff --git a/FastRngTests/Float/Distributions/InverseExponentialLa10.cs b/FastRngTests/Float/Distributions/InverseExponentialLa10.cs deleted file mode 100644 index b6ac2d5..0000000 --- a/FastRngTests/Float/Distributions/InverseExponentialLa10.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Threading.Tasks; -using FastRng.Float; -using NUnit.Framework; - -namespace FastRngTests.Float.Distributions -{ - [ExcludeFromCodeCoverage] - public class InverseExponentialLa10 - { - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestExponentialDistribution01() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Float.Distributions.InverseExponentialLa10(rng); - var fqa = new FrequencyAnalysis(); - - for (var n = 0; n < 100_000; n++) - fqa.CountThis(await dist.NextNumber()); - - var result = fqa.NormalizeAndPlotEvents(TestContext.WriteLine); - - Assert.That(result[0], Is.EqualTo(0.0000501746820562f).Within(0.0003f)); - Assert.That(result[1], Is.EqualTo(0.0000554515994322f).Within(0.0003f)); - Assert.That(result[2], Is.EqualTo(0.0000612834950532f).Within(0.0003f)); - - Assert.That(result[21], Is.EqualTo(0.00040973497898f).Within(0.00045f)); - Assert.That(result[22], Is.EqualTo(0.000452827182887f).Within(0.00050f)); - Assert.That(result[23], Is.EqualTo(0.000500451433441f).Within(0.0006f)); - - Assert.That(result[50], Is.EqualTo(0.007446583070924f).Within(0.003f)); - - Assert.That(result[75], Is.EqualTo(0.090717953289412f).Within(0.02f)); - Assert.That(result[85], Is.EqualTo(0.246596963941606f).Within(0.05f)); - Assert.That(result[90], Is.EqualTo(0.406569659740598f).Within(0.08f)); - - Assert.That(result[97], Is.EqualTo(0.81873075307798f).Within(0.08f)); - Assert.That(result[98], Is.EqualTo(0.904837418035957f).Within(0.08f)); - Assert.That(result[99], Is.EqualTo(0.999999999999999f).Within(0.08f)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestExponentialGeneratorWithRange01() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Float.Distributions.InverseExponentialLa10(rng); - var samples = new float[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(-1.0f, 1.0f); - - Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range"); - Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range"); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestExponentialGeneratorWithRange02() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Float.Distributions.InverseExponentialLa10(rng); - var samples = new float[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(0.0f, 1.0f); - - Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range"); - Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range"); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void NoRandomNumberGenerator01() - { - Assert.Throws(() => new FastRng.Float.Distributions.InverseExponentialLa10(null)); - } - } -} \ No newline at end of file diff --git a/FastRngTests/Float/Distributions/InverseExponentialLa5.cs b/FastRngTests/Float/Distributions/InverseExponentialLa5.cs deleted file mode 100644 index cb464e6..0000000 --- a/FastRngTests/Float/Distributions/InverseExponentialLa5.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Threading.Tasks; -using FastRng.Float; -using NUnit.Framework; - -namespace FastRngTests.Float.Distributions -{ - [ExcludeFromCodeCoverage] - public class InverseExponentialLa5 - { - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestExponentialDistribution01() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Float.Distributions.InverseExponentialLa5(rng); - var fqa = new FrequencyAnalysis(); - - for (var n = 0; n < 100_000; n++) - fqa.CountThis(await dist.NextNumber()); - - var result = fqa.NormalizeAndPlotEvents(TestContext.WriteLine); - - Assert.That(result[0], Is.EqualTo(0.007083408929052f).Within(0.008f)); - Assert.That(result[1], Is.EqualTo(0.007446583070924f).Within(0.008f)); - Assert.That(result[2], Is.EqualTo(0.007828377549226f).Within(0.008f)); - - Assert.That(result[21], Is.EqualTo(0.020241911445804f).Within(0.05f)); - Assert.That(result[22], Is.EqualTo(0.021279736438377f).Within(0.05f)); - Assert.That(result[23], Is.EqualTo(0.022370771856166f).Within(0.05f)); - - Assert.That(result[50], Is.EqualTo(0.08629358649937f).Within(0.02f)); - - Assert.That(result[75], Is.EqualTo(0.301194211912202f).Within(0.03f)); - Assert.That(result[85], Is.EqualTo(0.496585303791409f).Within(0.05f)); - Assert.That(result[90], Is.EqualTo(0.637628151621772f).Within(0.06f)); - - Assert.That(result[97], Is.EqualTo(0.904837418035959f).Within(0.08f)); - Assert.That(result[98], Is.EqualTo(0.951229424500713f).Within(0.08f)); - Assert.That(result[99], Is.EqualTo(1f).Within(0.08f)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestExponentialGeneratorWithRange01() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Float.Distributions.InverseExponentialLa5(rng); - var samples = new float[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(-1.0f, 1.0f); - - Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range"); - Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range"); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestExponentialGeneratorWithRange02() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Float.Distributions.InverseExponentialLa5(rng); - var samples = new float[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(0.0f, 1.0f); - - Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range"); - Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range"); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void NoRandomNumberGenerator01() - { - Assert.Throws(() => new FastRng.Float.Distributions.InverseExponentialLa5(null)); - } - } -} \ No newline at end of file diff --git a/FastRngTests/Float/Distributions/InverseGammaA3B05.cs b/FastRngTests/Float/Distributions/InverseGammaA3B05.cs deleted file mode 100644 index 5bdcba9..0000000 --- a/FastRngTests/Float/Distributions/InverseGammaA3B05.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Threading.Tasks; -using FastRng.Float; -using NUnit.Framework; - -namespace FastRngTests.Float.Distributions -{ - [ExcludeFromCodeCoverage] - public class InverseGammaA3B05 - { - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestInverseGammaDistribution01() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Float.Distributions.InverseGammaA3B05(rng); - var fra = new FrequencyAnalysis(); - - for (var n = 0; n < 100_000; n++) - fra.CountThis(await dist.NextNumber()); - - var result = fra.NormalizeAndPlotEvents(TestContext.WriteLine); - - Assert.That(result[0], Is.EqualTo(0.0000000000000003f).Within(0.0000001f)); - Assert.That(result[1], Is.EqualTo(0.0000011605257228f).Within(0.00001f)); - Assert.That(result[2], Is.EqualTo(0.0009536970016103f).Within(0.0015f)); - - Assert.That(result[21], Is.EqualTo(0.5880485243048120f).Within(0.05f)); - Assert.That(result[22], Is.EqualTo(0.5433842148912880f).Within(0.05f)); - Assert.That(result[23], Is.EqualTo(0.5017780549216030f).Within(0.05f)); - - Assert.That(result[50], Is.EqualTo(0.0741442015957425f).Within(0.009f)); - - Assert.That(result[75], Is.EqualTo(0.0207568945092484f).Within(0.006f)); - Assert.That(result[85], Is.EqualTo(0.0136661506653688f).Within(0.006f)); - Assert.That(result[90], Is.EqualTo(0.0112550619601327f).Within(0.006f)); - - Assert.That(result[97], Is.EqualTo(0.0087026933539773f).Within(0.005f)); - Assert.That(result[98], Is.EqualTo(0.0083995375385004f).Within(0.005f)); - Assert.That(result[99], Is.EqualTo(0.0081094156379928f).Within(0.005f)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestInverseGammaGeneratorWithRange01() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Float.Distributions.InverseGammaA3B05(rng); - var samples = new float[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(-1.0f, 1.0f); - - Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range"); - Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range"); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestInverseGammaGeneratorWithRange02() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Float.Distributions.InverseGammaA3B05(rng); - var samples = new float[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(0.0f, 1.0f); - - Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range"); - Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range"); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void NoRandomNumberGenerator01() - { - Assert.Throws(() => new FastRng.Float.Distributions.InverseGammaA3B05(null)); - } - } -} \ No newline at end of file diff --git a/FastRngTests/Float/Distributions/LaplaceB01M0.cs b/FastRngTests/Float/Distributions/LaplaceB01M0.cs deleted file mode 100644 index c08295a..0000000 --- a/FastRngTests/Float/Distributions/LaplaceB01M0.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Threading.Tasks; -using FastRng.Float; -using NUnit.Framework; - -namespace FastRngTests.Float.Distributions -{ - [ExcludeFromCodeCoverage] - public class LaplaceB01M0 - { - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestLaplaceDistribution01() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Float.Distributions.LaplaceB01M0(rng); - var fra = new FrequencyAnalysis(); - - for (var n = 0; n < 100_000; n++) - fra.CountThis(await dist.NextNumber()); - - var result = fra.NormalizeAndPlotEvents(TestContext.WriteLine); - - Assert.That(result[0], Is.EqualTo(1.0000000000000000f).Within(0.05f)); - Assert.That(result[1], Is.EqualTo(0.9048374180359590f).Within(0.05f)); - Assert.That(result[2], Is.EqualTo(0.8187307530779810f).Within(0.05f)); - - Assert.That(result[21], Is.EqualTo(0.1224564282529820f).Within(0.05f)); - Assert.That(result[22], Is.EqualTo(0.1108031583623340f).Within(0.05f)); - Assert.That(result[23], Is.EqualTo(0.1002588437228040f).Within(0.05f)); - - Assert.That(result[50], Is.EqualTo(0.0067379469990855f).Within(0.003f)); - - Assert.That(result[75], Is.EqualTo(0.0005530843701478f).Within(0.0015f)); - Assert.That(result[85], Is.EqualTo(0.0002034683690106f).Within(0.0015f)); - Assert.That(result[90], Is.EqualTo(0.0001234098040867f).Within(0.0015f)); - - Assert.That(result[97], Is.EqualTo(0.0000612834950532f).Within(0.0002f)); - Assert.That(result[98], Is.EqualTo(0.0000554515994322f).Within(0.0002f)); - Assert.That(result[99], Is.EqualTo(0.0000501746820562f).Within(0.0002f)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestLaplaceGeneratorWithRange01() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Float.Distributions.LaplaceB01M0(rng); - var samples = new float[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(-1.0f, 1.0f); - - Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range"); - Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range"); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestLaplaceGeneratorWithRange02() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Float.Distributions.LaplaceB01M0(rng); - var samples = new float[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(0.0f, 1.0f); - - Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range"); - Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range"); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void NoRandomNumberGenerator01() - { - Assert.Throws(() => new FastRng.Float.Distributions.LaplaceB01M0(null)); - } - } -} \ No newline at end of file diff --git a/FastRngTests/Float/Distributions/LaplaceB01M05.cs b/FastRngTests/Float/Distributions/LaplaceB01M05.cs deleted file mode 100644 index 50ca09e..0000000 --- a/FastRngTests/Float/Distributions/LaplaceB01M05.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Threading.Tasks; -using FastRng.Float; -using NUnit.Framework; - -namespace FastRngTests.Float.Distributions -{ - [ExcludeFromCodeCoverage] - public class LaplaceB01M05 - { - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestLaplaceDistribution01() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Float.Distributions.LaplaceB01M05(rng); - var fra = new FrequencyAnalysis(); - - for (var n = 0; n < 100_000; n++) - fra.CountThis(await dist.NextNumber()); - - var result = fra.NormalizeAndPlotEvents(TestContext.WriteLine); - - Assert.That(result[0], Is.EqualTo(0.0074465830709244f).Within(0.004f)); - Assert.That(result[1], Is.EqualTo(0.0082297470490200f).Within(0.004f)); - Assert.That(result[2], Is.EqualTo(0.0090952771016958f).Within(0.01f)); - - Assert.That(result[21], Is.EqualTo(0.0608100626252180f).Within(0.02f)); - Assert.That(result[22], Is.EqualTo(0.0672055127397498f).Within(0.02f)); - Assert.That(result[23], Is.EqualTo(0.0742735782143340f).Within(0.02f)); - - Assert.That(result[50], Is.EqualTo(1.0000000000000000f).Within(0.2f)); - - Assert.That(result[75], Is.EqualTo(0.0742735782143335f).Within(0.01f)); - Assert.That(result[85], Is.EqualTo(0.0273237224472924f).Within(0.01f)); - Assert.That(result[90], Is.EqualTo(0.0165726754017612f).Within(0.01f)); - - Assert.That(result[97], Is.EqualTo(0.0082297470490200f).Within(0.004f)); - Assert.That(result[98], Is.EqualTo(0.0074465830709243f).Within(0.004f)); - Assert.That(result[99], Is.EqualTo(0.0067379469990854f).Within(0.004f)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestLaplaceGeneratorWithRange01() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Float.Distributions.LaplaceB01M05(rng); - var samples = new float[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(-1.0f, 1.0f); - - Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range"); - Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range"); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestLaplaceGeneratorWithRange02() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Float.Distributions.LaplaceB01M05(rng); - var samples = new float[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(0.0f, 1.0f); - - Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range"); - Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range"); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void NoRandomNumberGenerator01() - { - Assert.Throws(() => new FastRng.Float.Distributions.LaplaceB01M05(null)); - } - } -} \ No newline at end of file diff --git a/FastRngTests/Float/Distributions/LogNormalS1M0.cs b/FastRngTests/Float/Distributions/LogNormalS1M0.cs deleted file mode 100644 index c578a71..0000000 --- a/FastRngTests/Float/Distributions/LogNormalS1M0.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Threading.Tasks; -using FastRng.Float; -using NUnit.Framework; - -namespace FastRngTests.Float.Distributions -{ - [ExcludeFromCodeCoverage] - public class LogNormalS1M0 - { - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestLogNormalDistribution01() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Float.Distributions.LogNormalS1M0(rng); - var fra = new FrequencyAnalysis(); - - for (var n = 0; n < 100_000; n++) - fra.CountThis(await dist.NextNumber()); - - var result = fra.NormalizeAndPlotEvents(TestContext.WriteLine); - - Assert.That(result[0], Is.EqualTo(0.001505531f).Within(0.003f)); - Assert.That(result[1], Is.EqualTo(0.014408709f).Within(0.01f)); - Assert.That(result[2], Is.EqualTo(0.043222256f).Within(0.02f)); - - Assert.That(result[21], Is.EqualTo(0.876212056f).Within(0.15f)); - Assert.That(result[22], Is.EqualTo(0.895582226f).Within(0.15f)); - Assert.That(result[23], Is.EqualTo(0.912837250f).Within(0.15f)); - - Assert.That(result[50], Is.EqualTo(0.948062005f).Within(0.2f)); - - Assert.That(result[75], Is.EqualTo(0.768584762f).Within(0.089f)); - Assert.That(result[85], Is.EqualTo(0.697303612f).Within(0.089f)); - Assert.That(result[90], Is.EqualTo(0.663570581f).Within(0.089f)); - - Assert.That(result[97], Is.EqualTo(0.618792767f).Within(0.089f)); - Assert.That(result[98], Is.EqualTo(0.612636410f).Within(0.089f)); - Assert.That(result[99], Is.EqualTo(0.606540679f).Within(0.089f)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestLogNormalGeneratorWithRange01() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Float.Distributions.LogNormalS1M0(rng); - var samples = new float[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(-1.0f, 1.0f); - - Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range"); - Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range"); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestLogNormalGeneratorWithRange02() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Float.Distributions.LogNormalS1M0(rng); - var samples = new float[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(0.0f, 1.0f); - - Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range"); - Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range"); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void NoRandomNumberGenerator01() - { - Assert.Throws(() => new FastRng.Float.Distributions.LogNormalS1M0(null)); - } - } -} \ No newline at end of file diff --git a/FastRngTests/Float/Distributions/NormalS02M05.cs b/FastRngTests/Float/Distributions/NormalS02M05.cs deleted file mode 100644 index 75a0274..0000000 --- a/FastRngTests/Float/Distributions/NormalS02M05.cs +++ /dev/null @@ -1,80 +0,0 @@ -using System; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Threading.Tasks; -using FastRng.Float; -using NUnit.Framework; - -namespace FastRngTests.Float.Distributions -{ - [ExcludeFromCodeCoverage] - public class NormalS02M05 - { - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestNormalDistribution01() - { - const float MEAN = 0.5f; - const float STANDARD_DEVIATION = 0.2f; - - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Float.Distributions.NormalS02M05(rng); - var stats = new RunningStatistics(); - var fra = new FrequencyAnalysis(); - - for (var n = 0; n < 100_000; n++) - { - var nextNumber = await dist.NextNumber(); - stats.Push(nextNumber); - fra.CountThis(nextNumber); - } - - fra.NormalizeAndPlotEvents(TestContext.WriteLine); - - TestContext.WriteLine($"mean={MEAN} vs. {stats.Mean}"); - TestContext.WriteLine($"variance={STANDARD_DEVIATION * STANDARD_DEVIATION} vs {stats.Variance}"); - - Assert.That(stats.Mean, Is.EqualTo(MEAN).Within(0.01f), "Mean is out of range"); - Assert.That(stats.Variance, Is.EqualTo(STANDARD_DEVIATION*STANDARD_DEVIATION).Within(0.01f), "Variance is out of range"); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestNormalGeneratorWithRange01() - { - using var rng = new MultiThreadedRng(); - var samples = new float[1_000]; - var dist = new FastRng.Float.Distributions.NormalS02M05(rng); - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(-1.0f, 1.0f); - - Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min is out of range"); - Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range"); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestNormalGeneratorWithRange02() - { - using var rng = new MultiThreadedRng(); - var samples = new float[1_000]; - var dist = new FastRng.Float.Distributions.NormalS02M05(rng); - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(0.0f, 1.0f); - - Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range"); - Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range"); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void NoRandomNumberGenerator01() - { - Assert.Throws(() => new FastRng.Float.Distributions.NormalS02M05(null)); - } - } -} \ No newline at end of file diff --git a/FastRngTests/Float/Distributions/StudentTNu1.cs b/FastRngTests/Float/Distributions/StudentTNu1.cs deleted file mode 100644 index 215add9..0000000 --- a/FastRngTests/Float/Distributions/StudentTNu1.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Threading.Tasks; -using FastRng.Float; -using NUnit.Framework; - -namespace FastRngTests.Float.Distributions -{ - [ExcludeFromCodeCoverage] - public class StudentTNu1 - { - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestStudentTDistribution01() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Float.Distributions.StudentTNu1(rng); - var fra = new FrequencyAnalysis(); - - for (var n = 0; n < 100_000; n++) - fra.CountThis(await dist.NextNumber()); - - var result = fra.NormalizeAndPlotEvents(TestContext.WriteLine); - - Assert.That(result[0], Is.EqualTo(1.000000000f).Within(0.2f)); - Assert.That(result[1], Is.EqualTo(0.999700120f).Within(0.2f)); - Assert.That(result[2], Is.EqualTo(0.999200719f).Within(0.2f)); - - Assert.That(result[21], Is.EqualTo(0.953929798f).Within(0.2f)); - Assert.That(result[22], Is.EqualTo(0.949852788f).Within(0.2f)); - Assert.That(result[23], Is.EqualTo(0.945631619f).Within(0.2f)); - - Assert.That(result[50], Is.EqualTo(0.793667169f).Within(0.095f)); - - Assert.That(result[75], Is.EqualTo(0.633937627f).Within(0.09f)); - Assert.That(result[85], Is.EqualTo(0.574902276f).Within(0.09f)); - Assert.That(result[90], Is.EqualTo(0.547070729f).Within(0.09f)); - - Assert.That(result[97], Is.EqualTo(0.510150990f).Within(0.09f)); - Assert.That(result[98], Is.EqualTo(0.505075501f).Within(0.09f)); - Assert.That(result[99], Is.EqualTo(0.500050000f).Within(0.09f)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestStudentTGeneratorWithRange01() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Float.Distributions.StudentTNu1(rng); - var samples = new float[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(-1.0f, 1.0f); - - Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range"); - Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range"); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestStudentTGeneratorWithRange02() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Float.Distributions.StudentTNu1(rng); - var samples = new float[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(0.0f, 1.0f); - - Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range"); - Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range"); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void NoRandomNumberGenerator01() - { - Assert.Throws(() => new FastRng.Float.Distributions.StudentTNu1(null)); - } - } -} \ No newline at end of file diff --git a/FastRngTests/Float/Distributions/Uniform.cs b/FastRngTests/Float/Distributions/Uniform.cs deleted file mode 100644 index 62a9cc1..0000000 --- a/FastRngTests/Float/Distributions/Uniform.cs +++ /dev/null @@ -1,297 +0,0 @@ -using System; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Threading.Tasks; -using FastRng.Float; -using NUnit.Framework; - -namespace FastRngTests.Float.Distributions -{ - [ExcludeFromCodeCoverage] - public class Uniform - { - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestUniformDistribution01() - { - const float A = 0.0f; - const float B = 1.0f; - const float MEAN = 0.5f * (A + B); - const float VARIANCE = (1.0f / 12.0f) * (B - A) * (B - A); - - using var rng = new MultiThreadedRng(); - var stats = new RunningStatistics(); - var fra = new FrequencyAnalysis(); - - for (var n = 0; n < 100_000; n++) - { - var value = await rng.GetUniform(); - stats.Push(value); - fra.CountThis(value); - } - - fra.NormalizeAndPlotEvents(TestContext.WriteLine); - fra.PlotOccurence(TestContext.WriteLine); - TestContext.WriteLine($"mean={MEAN} vs. {stats.Mean}"); - TestContext.WriteLine($"variance={VARIANCE} vs {stats.Variance}"); - - Assert.That(stats.Mean, Is.EqualTo(MEAN).Within(0.01f), "Mean is out of range"); - Assert.That(stats.Variance, Is.EqualTo(VARIANCE).Within(0.001f), "Variance is out of range"); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task KolmogorovSmirnovTest() - { - // Kolmogorov-Smirnov test for distributions. - // See Knuth volume 2, page 48-51 (third edition). - // This test should *fail* on average one time in 1000 runs. - // That's life with random number generators: if the test passed all the time, - // the source wouldn't be random enough! If the test were to fail more frequently, - // the most likely explanation would be a bug in the code. - - const int NUM_ROUNDS = 10_000; - const float FAILURE_PROBABILITY = 0.001f; // probability of test failing with normal distributed input - const float P_LOW = 0.25f * FAILURE_PROBABILITY; - const float P_HIGH = 1.0f - 0.25f * FAILURE_PROBABILITY; - - var samples = new float[NUM_ROUNDS]; - using var rng = new MultiThreadedRng(); - int n; - - for (n = 0; n != NUM_ROUNDS; ++n) - samples[n] = await rng.GetUniform(); - - Array.Sort(samples); - - var jMinus = 0; - var jPlus = 0; - var kPlus = -float.MaxValue; - var kMinus = -float.MaxValue; - - for (n = 0; n != NUM_ROUNDS; ++n) - { - var cdf = samples[n]; - var temp = (n + 1.0f) / NUM_ROUNDS - cdf; - - if (kPlus < temp) - { - kPlus = temp; - jPlus = n; - } - - temp = cdf - (n + 0.0f) / NUM_ROUNDS; - if (kMinus < temp) - { - kMinus = temp; - jMinus = n; - } - } - - var sqrtNumReps = MathF.Sqrt(NUM_ROUNDS); - kPlus *= sqrtNumReps; - kMinus *= sqrtNumReps; - - // We divide the failure probability by four because we have four tests: - // left and right tests for K+ and K-. - var cutoffLow = MathF.Sqrt(0.5f * MathF.Log(1.0f / (1.0f - P_LOW))) - 1.0f / (6.0f * sqrtNumReps); - var cutoffHigh = MathF.Sqrt(0.5f * MathF.Log(1.0f / (1.0f - P_HIGH))) - 1.0f / (6.0f * sqrtNumReps); - - TestContext.WriteLine($"K+ = {kPlus} | K- = {kMinus}"); - TestContext.WriteLine($"K+ max at position {jPlus} = {samples[jPlus]}"); - TestContext.WriteLine($"K- max at position {jMinus} = {samples[jMinus]}"); - TestContext.WriteLine($"Acceptable interval: [{cutoffLow}, {cutoffHigh}]"); - - Assert.That(kPlus, Is.GreaterThanOrEqualTo(cutoffLow), "K+ is lower than low cutoff"); - Assert.That(kPlus, Is.LessThanOrEqualTo(cutoffHigh), "K+ is higher than high cutoff"); - Assert.That(kMinus, Is.GreaterThanOrEqualTo(cutoffLow), "K- is lower than low cutoff"); - Assert.That(kMinus, Is.LessThanOrEqualTo(cutoffHigh), "K- is lower than high cutoff"); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestUniformGeneratorWithRange01() - { - using var rng = new MultiThreadedRng(); - var samples = new float[1_000]; - var dist = new FastRng.Float.Distributions.Uniform(rng); - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(-1.0f, 1.0f); - - Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min is out of range"); - Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range"); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestUniformGeneratorWithRange02() - { - using var rng = new MultiThreadedRng(); - var samples = new float[1_000]; - var dist = new FastRng.Float.Distributions.Uniform(rng); - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(0.0f, 1.0f); - - Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range"); - Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range"); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestUniformGeneratorWithRange04() - { - using var rng = new MultiThreadedRng(); - var samples = new float[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await rng.GetUniform(); - - Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range"); - Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range"); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestRange05Uint() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Float.Distributions.Uniform(rng); - var distribution = new uint[101]; - var runs = 1_000_000; - for (var n = 0; n < runs; n++) - distribution[await dist.NextNumber(0, 100)]++; - - for (var n = 0; n < distribution.Length - 1; n++) - Assert.That(distribution[n], Is.GreaterThan(0)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestRange05Ulong() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Float.Distributions.Uniform(rng); - var distribution = new uint[101]; - var runs = 1_000_000; - for (var n = 0; n < runs; n++) - distribution[await dist.NextNumber(0UL, 100)]++; - - for (var n = 0; n < distribution.Length - 1; n++) - Assert.That(distribution[n], Is.GreaterThan(0)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestRange05Float() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Float.Distributions.Uniform(rng); - var distribution = new uint[101]; - var runs = 1_000_000; - for (var n = 0; n < runs; n++) - distribution[(uint)MathF.Floor(await dist.NextNumber(0.0f, 100.0f))]++; - - for (var n = 0; n < distribution.Length - 1; n++) - Assert.That(distribution[n], Is.GreaterThan(0)); - } - - [Test] - [Category(TestCategories.NORMAL)] - public async Task TestDistribution001Uint() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Float.Distributions.Uniform(rng); - var distribution = new uint[101]; - var runs = 1_000_000; - for (var n = 0; n < runs; n++) - distribution[await dist.NextNumber(0, 100)]++; - - Assert.That(distribution[..^1].Max() - distribution[..^1].Min(), Is.InRange(0, 600)); - } - - [Test] - [Category(TestCategories.NORMAL)] - public async Task TestDistribution001Ulong() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Float.Distributions.Uniform(rng); - var distribution = new uint[101]; - var runs = 1_000_000; - for (var n = 0; n < runs; n++) - distribution[await dist.NextNumber(0UL, 100)]++; - - Assert.That(distribution[..^1].Max() - distribution[..^1].Min(), Is.InRange(0, 600)); - } - - [Test] - [Category(TestCategories.NORMAL)] - public async Task TestDistribution001Float() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Float.Distributions.Uniform(rng); - var distribution = new uint[101]; - var runs = 1_000_000; - for (var n = 0; n < runs; n++) - distribution[(uint)MathF.Floor(await dist.NextNumber(0.0f, 100.0f))]++; - - Assert.That(distribution[..^1].Max() - distribution[..^1].Min(), Is.InRange(0, 600)); - } - - [Test] - [Category(TestCategories.LONG_RUNNING)] - public async Task TestDistribution002Uint() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Float.Distributions.Uniform(rng); - var distribution = new uint[101]; - var runs = 100_000_000; - for (var n = 0; n < runs; n++) - distribution[await dist.NextNumber(0, 100)]++; - - Assert.That(distribution[..^1].Max() - distribution[..^1].Min(), Is.InRange(0, 6_000)); - } - - [Test] - [Category(TestCategories.LONG_RUNNING)] - public async Task TestDistribution002Ulong() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Float.Distributions.Uniform(rng); - var distribution = new uint[101]; - var runs = 100_000_000; - for (var n = 0; n < runs; n++) - distribution[await dist.NextNumber(0UL, 100)]++; - - Assert.That(distribution[..^1].Max() - distribution[..^1].Min(), Is.InRange(0, 6_000)); - } - - [Test] - [Category(TestCategories.LONG_RUNNING)] - public async Task TestDistribution002Float() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Float.Distributions.Uniform(rng); - var distribution = new uint[101]; - var runs = 100_000_000; - for (var n = 0; n < runs; n++) - distribution[(uint)MathF.Floor(await dist.NextNumber(0.0f, 100.0f))]++; - - Assert.That(distribution[..^1].Max() - distribution[..^1].Min(), Is.InRange(0, 6_000)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void NoRandomNumberGenerator01() - { - Assert.Throws(() => new FastRng.Float.Distributions.Uniform(null)); - } - } -} \ No newline at end of file diff --git a/FastRngTests/Float/Distributions/WeibullK05La1.cs b/FastRngTests/Float/Distributions/WeibullK05La1.cs deleted file mode 100644 index a4db6d7..0000000 --- a/FastRngTests/Float/Distributions/WeibullK05La1.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Threading.Tasks; -using FastRng.Float; -using NUnit.Framework; - -namespace FastRngTests.Float.Distributions -{ - [ExcludeFromCodeCoverage] - public class WeibullK05La1 - { - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestWeibullDistribution01() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Float.Distributions.WeibullK05La1(rng); - var fra = new FrequencyAnalysis(); - - for (var n = 0; n < 100_000; n++) - fra.CountThis(await dist.NextNumber()); - - var result = fra.NormalizeAndPlotEvents(TestContext.WriteLine); - - Assert.That(result[0], Is.EqualTo(1.000000000f).Within(0.2f)); - Assert.That(result[1], Is.EqualTo(0.678415772f).Within(0.09f)); - Assert.That(result[2], Is.EqualTo(0.536595233f).Within(0.09f)); - - Assert.That(result[21], Is.EqualTo(0.147406264f).Within(0.02f)); - Assert.That(result[22], Is.EqualTo(0.142654414f).Within(0.02f)); - Assert.That(result[23], Is.EqualTo(0.138217760f).Within(0.02f)); - - Assert.That(result[50], Is.EqualTo(0.075769787f).Within(0.095f)); - - Assert.That(result[75], Is.EqualTo(0.053016799f).Within(0.05f)); - Assert.That(result[85], Is.EqualTo(0.047144614f).Within(0.05f)); - Assert.That(result[90], Is.EqualTo(0.044629109f).Within(0.05f)); - - Assert.That(result[97], Is.EqualTo(0.041484591f).Within(0.05f)); - Assert.That(result[98], Is.EqualTo(0.041067125f).Within(0.05f)); - Assert.That(result[99], Is.EqualTo(0.040656966f).Within(0.05f)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestWeibullGeneratorWithRange01() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Float.Distributions.WeibullK05La1(rng); - var samples = new float[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(-1.0f, 1.0f); - - Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0f), "Min out of range"); - Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max out of range"); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestWeibullGeneratorWithRange02() - { - using var rng = new MultiThreadedRng(); - var dist = new FastRng.Float.Distributions.WeibullK05La1(rng); - var samples = new float[1_000]; - for (var n = 0; n < samples.Length; n++) - samples[n] = await dist.NextNumber(0.0f, 1.0f); - - Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0f), "Min is out of range"); - Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0f), "Max is out of range"); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void NoRandomNumberGenerator01() - { - Assert.Throws(() => new FastRng.Float.Distributions.WeibullK05La1(null)); - } - } -} \ No newline at end of file diff --git a/FastRngTests/Float/FrequencyAnalysis.cs b/FastRngTests/Float/FrequencyAnalysis.cs deleted file mode 100644 index 5166275..0000000 --- a/FastRngTests/Float/FrequencyAnalysis.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Text; - -namespace FastRngTests.Float -{ - [ExcludeFromCodeCoverage] - public sealed class FrequencyAnalysis - { - private readonly uint[] data; - - public FrequencyAnalysis(int samples = 100) - { - this.data = new uint[samples]; - } - - public void CountThis(float value) - { - var bucket = (int)MathF.Floor(value * this.data.Length); - this.data[bucket]++; - } - - public float[] GetNormalizedEvents() - { - var max = (float) this.data.Max(); - var result = new float[this.data.Length]; - for (var n = 0; n < this.data.Length; n++) - { - result[n] = this.data[n] / max; - } - - return result; - } - - private float[] Normalize() - { - var max = (float)this.data.Max(); - var result = new float[this.data.Length]; - for (var n = 0; n < this.data.Length; n++) - result[n] = this.data[n] / max; - - return result; - } - - public float[] NormalizeAndPlotEvents(Action writer) - { - var result = this.Normalize(); - FrequencyAnalysis.Plot(result, writer, "Event Distribution"); - - return result; - } - - public void PlotOccurence(Action writer) - { - var data = this.data.Select(n => n > 0f ? 1.0f : 0.0f).ToArray(); - FrequencyAnalysis.Plot(data, writer, "Occurrence Distribution"); - } - - private static void Plot(float[] data, Action writer, string name) - { - const int HEIGHT = 16; - - var values = new float[data.Length]; - for (var n = 0; n < data.Length; n++) - { - values[n] = data[n] * HEIGHT; - } - - var sb = new StringBuilder(); - for (var line = HEIGHT; line > 0; line--) - { - for (var column = 0; column < data.Length; column++) - sb.Append(values[column] >= line ? '█' : '░'); - - writer.Invoke(sb.ToString()); - sb.Clear(); - } - - writer.Invoke(name); - writer.Invoke(string.Empty); - } - } -} \ No newline at end of file diff --git a/FastRngTests/Float/MathToolsTests.cs b/FastRngTests/Float/MathToolsTests.cs deleted file mode 100644 index 778647d..0000000 --- a/FastRngTests/Float/MathToolsTests.cs +++ /dev/null @@ -1,341 +0,0 @@ -using System; -using System.Diagnostics.CodeAnalysis; -using FastRng.Float; -using NUnit.Framework; - -namespace FastRngTests.Float -{ - [ExcludeFromCodeCoverage] - public class MathToolsTests - { - #region Gamma - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void GammaTest01() - { - Assert.That(MathTools.Gamma(-0.5f), Is.EqualTo(-3.544907701811087f).Within(1e-6f)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void GammaTest02() - { - Assert.That(MathTools.Gamma(0.1f), Is.EqualTo(9.51350975f).Within(1e-6f)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void GammaTest03() - { - Assert.That(MathTools.Gamma(0.5f), Is.EqualTo(1.772453850905517f).Within(1e-6f)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void GammaTest04() - { - Assert.That(MathTools.Gamma(1.0f), Is.EqualTo(1.0f).Within(1e-6f)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void GammaTest05() - { - Assert.That(MathTools.Gamma(1.5f), Is.EqualTo(0.8862269254527587f).Within(1e-6f)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void GammaTest06() - { - Assert.That(MathTools.Gamma(2.0f), Is.EqualTo(1.0f).Within(1e-6f)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void GammaTest07() - { - Assert.That(MathTools.Gamma(3.0f), Is.EqualTo(2.0f).Within(1e-6f)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void GammaTest08() - { - Assert.That(MathTools.Gamma(10.0f), Is.EqualTo(362_880.719f).Within(1e-6f)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void GammaTest09() - { - Assert.That(MathTools.Gamma(140.0f), Is.EqualTo(float.NaN)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void GammaTest10() - { - Assert.That(MathTools.Gamma(170.0f), Is.EqualTo(float.NaN)); - } - - #endregion - - #region Factorial (integer) - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void FactorialInteger01() - { - Assert.That(MathTools.Factorial(0), Is.EqualTo(1)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void FactorialInteger02() - { - Assert.That(MathTools.Factorial(1), Is.EqualTo(1)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void FactorialInteger03() - { - Assert.That(MathTools.Factorial(2), Is.EqualTo(2)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void FactorialInteger04() - { - Assert.That(MathTools.Factorial(3), Is.EqualTo(6)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void FactorialInteger05() - { - Assert.That(MathTools.Factorial(4), Is.EqualTo(24)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void FactorialInteger06() - { - Assert.That(MathTools.Factorial(5), Is.EqualTo(120)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void FactorialInteger07() - { - Assert.That(MathTools.Factorial(6), Is.EqualTo(720)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void FactorialInteger08() - { - Assert.That(MathTools.Factorial(7), Is.EqualTo(5_040)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void FactorialInteger09() - { - Assert.That(MathTools.Factorial(8), Is.EqualTo(40_320)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void FactorialInteger10() - { - Assert.That(MathTools.Factorial(9), Is.EqualTo(362_880)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void FactorialInteger11() - { - Assert.That(MathTools.Factorial(10), Is.EqualTo(3_628_800)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void FactorialInteger12() - { - Assert.That(MathTools.Factorial(11), Is.EqualTo(39_916_800)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void FactorialInteger13() - { - Assert.That(MathTools.Factorial(12), Is.EqualTo(479_001_600)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void FactorialInteger14() - { - Assert.That(MathTools.Factorial(13), Is.EqualTo(6_227_020_800)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void FactorialInteger15() - { - Assert.That(MathTools.Factorial(14), Is.EqualTo(87_178_291_200)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void FactorialInteger16() - { - Assert.That(MathTools.Factorial(15), Is.EqualTo(1_307_674_368_000)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void FactorialInteger17() - { - Assert.That(MathTools.Factorial(16), Is.EqualTo(20_922_789_888_000)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void FactorialInteger18() - { - Assert.That(MathTools.Factorial(17), Is.EqualTo(355_687_428_096_000)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void FactorialInteger19() - { - Assert.That(MathTools.Factorial(18), Is.EqualTo(6_402_373_705_728_000)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void FactorialInteger20() - { - Assert.That(MathTools.Factorial(19), Is.EqualTo(121_645_100_408_832_000)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void FactorialInteger21() - { - Assert.That(MathTools.Factorial(20), Is.EqualTo(2_432_902_008_176_640_000)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void FactorialInteger22() - { - Assert.Throws(() => MathTools.Factorial(21)); - - // Note: 21! is not possible in C# until we got 128 bit integers, since: - // ulong.max == 18_446_744_073_709_551_615 < 51_090_942_171_709_400_000 - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void FactorialInteger23() - { - Assert.Throws(() => MathTools.Factorial(45_646)); - - // Note: 45_646! is not possible in C# since: - // ulong.max == 18_446_744_073_709_551_615 - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void FactorialInteger24() - { - Assert.Throws(() => MathTools.Factorial(-1)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void FactorialInteger25() - { - Assert.Throws(() => MathTools.Factorial(-6_565)); - } - - #endregion - - #region Factorial (floating point) - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void FactorialFloatingPoint01() - { - Assert.That(MathTools.Factorial(0.5f), Is.EqualTo(0.886226925f).Within(1e6f)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void FactorialFloatingPoint02() - { - Assert.That(MathTools.Factorial(1.5f), Is.EqualTo(1.329340388f).Within(1e6f)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void FactorialFloatingPoint03() - { - Assert.That(MathTools.Factorial(-1.5f), Is.EqualTo(-1.329340388f).Within(1e6f)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public void FactorialFloatingPoint04() - { - Assert.That(MathTools.Factorial(7.5f), Is.EqualTo(14_034.407293483f).Within(1e6f)); - } - - #endregion - } -} \ No newline at end of file diff --git a/FastRngTests/Float/MultiThreadedRngTests.cs b/FastRngTests/Float/MultiThreadedRngTests.cs deleted file mode 100644 index f4f706c..0000000 --- a/FastRngTests/Float/MultiThreadedRngTests.cs +++ /dev/null @@ -1,625 +0,0 @@ -using System; -using System.Diagnostics.CodeAnalysis; -using System.Threading; -using System.Threading.Tasks; -using FastRng.Float; -using FastRng.Float.Distributions; -using NUnit.Framework; - -namespace FastRngTests.Float -{ - [ExcludeFromCodeCoverage] - public class MultiThreadedRngTests - { - private readonly IRandom rng = new MultiThreadedRng(); - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestRange01Uint() - { - var dist = new Uniform(this.rng); - for (uint n = 0; n < 1_000_000; n++) - Assert.That(await dist.NextNumber(n, 100_000 + n), Is.InRange(n, 100_000 + n)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestRange01Ulong() - { - var dist = new Uniform(this.rng); - for (ulong n = 0; n < 1_000_000; n++) - Assert.That(await dist.NextNumber(n, 100_000 + n), Is.InRange(n, 100_000 + n)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestRange01Float() - { - var dist = new Uniform(this.rng); - for (var n = 0.0f; n < 1e6f; n++) - Assert.That(await dist.NextNumber(n, 100_000 + n), Is.InRange(n, 100_000 + n)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestRange02Uint() - { - var dist = new Uniform(this.rng); - Assert.That(await dist.NextNumber(5, 5), Is.EqualTo(5)); - Assert.That(await dist.NextNumber(0, 0), Is.EqualTo(0)); - Assert.That(await dist.NextNumber(3_000_000_000, 3_000_000_000), Is.EqualTo(3_000_000_000)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestRange02Ulong() - { - var dist = new Uniform(this.rng); - Assert.That(await dist.NextNumber(5UL, 5), Is.EqualTo(5)); - Assert.That(await dist.NextNumber(0UL, 0), Is.EqualTo(0)); - Assert.That(await dist.NextNumber(3_000_000_000UL, 3_000_000_000), Is.EqualTo(3_000_000_000)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestRange02Float() - { - var dist = new Uniform(this.rng); - Assert.That(await dist.NextNumber(5f, 5f), Is.EqualTo(5)); - Assert.That(await dist.NextNumber(0f, 0f), Is.EqualTo(0)); - Assert.That(await dist.NextNumber(3e9f, 3e9f), Is.EqualTo(3e9f)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestRange03Uint() - { - var dist = new Uniform(this.rng); - Assert.That(await dist.NextNumber(5, 6), Is.InRange(5, 6)); - Assert.That(await dist.NextNumber(0, 1), Is.InRange(0, 1)); - Assert.That(await dist.NextNumber(3_000_000_000, 3_000_000_002), Is.InRange(3_000_000_000, 3_000_000_002)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestRange03Ulong() - { - var dist = new Uniform(this.rng); - Assert.That(await dist.NextNumber(5UL, 6), Is.InRange(5, 6)); - Assert.That(await dist.NextNumber(0UL, 1), Is.InRange(0, 1)); - Assert.That(await dist.NextNumber(3_000_000_000UL, 3_000_000_002), Is.InRange(3_000_000_000, 3_000_000_002)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestRange03Float() - { - var dist = new Uniform(this.rng); - Assert.That(await dist.NextNumber(5f, 6f), Is.InRange(5f, 6f)); - Assert.That(await dist.NextNumber(0f, 1f), Is.InRange(0f, 1f)); - Assert.That(await dist.NextNumber(3e9f, 3e9f+2f), Is.InRange(3e9f, 3e9f+2f)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestRange04Uint() - { - var distUniform = new Uniform(this.rng); - var distNormal = new NormalS02M05(this.rng); - - Assert.That(await distUniform.NextNumber(10, 1), Is.InRange(1, 10)); - Assert.That(await distNormal.NextNumber(10, 1), Is.InRange(1, 10)); - - Assert.That(await distUniform.NextNumber(20, 1), Is.InRange(1, 20)); - Assert.That(await distNormal.NextNumber(20, 1), Is.InRange(1, 20)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestRange04Ulong() - { - var distUniform = new Uniform(this.rng); - var distNormal = new NormalS02M05(this.rng); - - Assert.That(await distUniform.NextNumber(10UL, 1), Is.InRange(1, 10)); - Assert.That(await distNormal.NextNumber(10UL, 1), Is.InRange(1, 10)); - - Assert.That(await distUniform.NextNumber(20UL, 1), Is.InRange(1, 20)); - Assert.That(await distNormal.NextNumber(20UL, 1), Is.InRange(1, 20)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestRange04Float() - { - var distUniform = new Uniform(this.rng); - var distNormal = new NormalS02M05(this.rng); - - Assert.That(await distUniform.NextNumber(10.0f, 1), Is.InRange(1, 10)); - Assert.That(await distNormal.NextNumber(10.0f, 1), Is.InRange(1, 10)); - - Assert.That(await distUniform.NextNumber(20.0f, 1), Is.InRange(1, 20)); - Assert.That(await distNormal.NextNumber(20.0f, 1), Is.InRange(1, 20)); - } - - [Test] - [Category(TestCategories.LONG_RUNNING)] - public async Task TestRange05() - { - var distUniform = new Uniform(this.rng); - var distLorentz = new CauchyLorentzX1(this.rng); - - var rngContains0 = false; - var rngContains1 = false; - - var uniformContains0 = false; - var uniformContains1 = false; - - var lorentzContains0 = false; - var lorentzContains1 = false; - - for (int i = 0; i < 100_000_000; i++) - { - var rngValue = await rng.GetUniform(); - var uniform = await distUniform.NextNumber(); - var lorentz = await distLorentz.NextNumber(); - - switch (rngValue) - { - case 0.0f: - rngContains0 = true; - break; - case 1.0f: - rngContains1 = true; - break; - } - - switch (uniform) - { - case 0.0f: - uniformContains0 = true; - break; - case 1.0f: - uniformContains1 = true; - break; - } - - switch (lorentz) - { - case 0.0f: - lorentzContains0 = true; - break; - case 1.0f: - lorentzContains1 = true; - break; - } - } - - TestContext.WriteLine($"Uniform generator contained 0? {rngContains0} (expected=false)"); - TestContext.WriteLine($"Uniform generator contained 1? {rngContains1} (expected=true)"); - TestContext.WriteLine($"Uniform distribution contained 0? {uniformContains0} (expected=false)"); - TestContext.WriteLine($"Uniform distribution contained 1? {uniformContains1} (expected=true)"); - TestContext.WriteLine($"Lorentz distribution contained 0? {lorentzContains0} (expected=false)"); - TestContext.WriteLine($"Lorentz distribution contained 1? {lorentzContains1} (expected=true)"); - - Assert.That(rngContains0, Is.False, "Uniform generator contained 0"); - Assert.That(rngContains1, Is.True, "Uniform generator does not contained 1"); - - Assert.That(uniformContains0, Is.False, "Uniform distribution contained 0"); - Assert.That(uniformContains1, Is.True, "Uniform distribution does not contained 1"); - - Assert.That(lorentzContains0, Is.False, "Lorentz distribution contained 0"); - Assert.That(lorentzContains1, Is.True, "Lorentz distribution does not contained 1"); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestStoppingProducers01() - { - var rng2 = new MultiThreadedRng(); - rng2.Dispose(); - - var masterToken = new CancellationTokenSource(TimeSpan.FromSeconds(16)).Token; - var wasCanceled = false; - - while(true) - { - var tokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(3)); - await rng2.GetUniform(tokenSource.Token); - if (tokenSource.IsCancellationRequested) - { - wasCanceled = true; - break; - } - - if (masterToken.IsCancellationRequested) - { - break; - } - } - - Assert.That(masterToken.IsCancellationRequested, Is.False, "Master token was used to stop test"); - Assert.That(wasCanceled, Is.True, "The consumer was not canceled"); - - var tokenSource2 = new CancellationTokenSource(TimeSpan.FromSeconds(3)); - await new NormalS02M05(rng2).NextNumber(tokenSource2.Token); - Assert.That(tokenSource2.IsCancellationRequested, Is.True); - - tokenSource2 = new CancellationTokenSource(TimeSpan.FromSeconds(3)); - await new NormalS02M05(rng2).NextNumber(-1f, 1f, tokenSource2.Token); - Assert.That(tokenSource2.IsCancellationRequested, Is.True); - - tokenSource2 = new CancellationTokenSource(TimeSpan.FromSeconds(3)); - await new NormalS02M05(rng2).NextNumber(0u, 6u, tokenSource2.Token); - Assert.That(tokenSource2.IsCancellationRequested, Is.True); - - tokenSource2 = new CancellationTokenSource(TimeSpan.FromSeconds(3)); - await new NormalS02M05(rng2).NextNumber(0ul, 6ul, tokenSource2.Token); - Assert.That(tokenSource2.IsCancellationRequested, Is.True); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task OneSeed01() - { - using var rng1 = new MultiThreadedRng(6); - using var rng2 = new MultiThreadedRng(6); - using var rng3 = new MultiThreadedRng(7); - - var rng1Sample = new float[10]; - for (var n = 0; n < rng1Sample.Length; n++) - rng1Sample[n] = await rng1.GetUniform(); - - var rng2Sample = new float[10]; - for (var n = 0; n < rng2Sample.Length; n++) - rng2Sample[n] = await rng2.GetUniform(); - - var rng3Sample = new float[10]; - for (var n = 0; n < rng3Sample.Length; n++) - rng3Sample[n] = await rng3.GetUniform(); - - Assert.That(rng1Sample, Is.EquivalentTo(rng2Sample)); - Assert.That(rng1Sample, Is.Not.EquivalentTo(rng3Sample)); - Assert.That(rng2Sample, Is.Not.EquivalentTo(rng3Sample)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TwoSeeds01() - { - using var rng1 = new MultiThreadedRng(3, 6); - using var rng2 = new MultiThreadedRng(3, 6); - using var rng3 = new MultiThreadedRng(3, 7); - using var rng4 = new MultiThreadedRng(6, 3); - - var rng1Sample = new float[10]; - for (var n = 0; n < rng1Sample.Length; n++) - rng1Sample[n] = await rng1.GetUniform(); - - var rng2Sample = new float[10]; - for (var n = 0; n < rng2Sample.Length; n++) - rng2Sample[n] = await rng2.GetUniform(); - - var rng3Sample = new float[10]; - for (var n = 0; n < rng3Sample.Length; n++) - rng3Sample[n] = await rng3.GetUniform(); - - var rng4Sample = new float[10]; - for (var n = 0; n < rng4Sample.Length; n++) - rng4Sample[n] = await rng4.GetUniform(); - - Assert.That(rng1Sample, Is.EquivalentTo(rng2Sample)); - Assert.That(rng1Sample, Is.Not.EquivalentTo(rng3Sample)); - Assert.That(rng1Sample, Is.Not.EquivalentTo(rng4Sample)); - Assert.That(rng2Sample, Is.Not.EquivalentTo(rng3Sample)); - Assert.That(rng2Sample, Is.Not.EquivalentTo(rng4Sample)); - Assert.That(rng3Sample, Is.Not.EquivalentTo(rng4Sample)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task NoSeed01() - { - using var rng1 = new MultiThreadedRng(); - using var rng2 = new MultiThreadedRng(); - using var rng3 = new MultiThreadedRng(); - - var rng1Sample = new float[10]; - for (var n = 0; n < rng1Sample.Length; n++) - rng1Sample[n] = await rng1.GetUniform(); - - var rng2Sample = new float[10]; - for (var n = 0; n < rng2Sample.Length; n++) - rng2Sample[n] = await rng2.GetUniform(); - - var rng3Sample = new float[10]; - for (var n = 0; n < rng3Sample.Length; n++) - rng3Sample[n] = await rng3.GetUniform(); - - Assert.That(rng1Sample, Is.Not.EquivalentTo(rng2Sample)); - Assert.That(rng1Sample, Is.Not.EquivalentTo(rng3Sample)); - Assert.That(rng2Sample, Is.Not.EquivalentTo(rng3Sample)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestCancellation01() - { - var tokenSource = new CancellationTokenSource(); - var token = tokenSource.Token; - tokenSource.Cancel(); - - using var rng2 = new MultiThreadedRng(); - var dist = new Uniform(this.rng); - Assert.That(await dist.NextNumber(1, 100_000, token), Is.EqualTo(0)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestCancellation02() - { - var tokenSource = new CancellationTokenSource(); - var token = tokenSource.Token; - tokenSource.Cancel(); - - using var rng2 = new MultiThreadedRng(); - Assert.That(await rng2.GetUniform(token), Is.NaN); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestDeterministic01() - { - using var rng2 = new MultiThreadedRng(16); - - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.12712699).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.5764246).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.06033641).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.6822646).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.61201024).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.17746393).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.33456334).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.96167856).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.12944269).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.64489424).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.109665975).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.18188846).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.36097932).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.48192585).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.1617974).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.24791045).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.43913218).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.3343723).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.9428737).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.55195147).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.027495692).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.9621458).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.55794334).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.69002056).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.86020225).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.88220626).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.68816894).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.8583311).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.003915685).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.83575225).Within(1e-7f)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestDeterministic02() - { - using var rng2 = new MultiThreadedRng(16); - var dist = new Uniform(rng2); - - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(13)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(58)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(6)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(68)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(61)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(18)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(34)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(96)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(13)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(64)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(11)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(19)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(36)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(48)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(17)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(25)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(44)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(34)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(94)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(55)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(3)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(96)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(56)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(69)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(86)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(88)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(69)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(85)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(1)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(83)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestDeterministic03() - { - using var rng2 = new MultiThreadedRng(16); - var dist = new CauchyLorentzX0(rng2); - - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(11)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(17)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(1)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(2)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(18)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(14)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(65)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(11)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(22)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(3)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(37)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(9)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(12)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(4)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(10)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(8)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(22)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(2)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(3)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(20)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(4)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(1)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(84)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(9)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(19)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(2)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(1)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(10)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(4)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(56)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestDeterministic01b() - { - using var rng2 = new MultiThreadedRng(16, 362_436_069); - - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.12712699).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.5764246).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.06033641).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.6822646).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.61201024).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.17746393).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.33456334).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.96167856).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.12944269).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.64489424).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.109665975).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.18188846).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.36097932).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.48192585).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.1617974).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.24791045).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.43913218).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.3343723).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.9428737).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.55195147).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.027495692).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.9621458).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.55794334).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.69002056).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.86020225).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.88220626).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.68816894).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.8583311).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.003915685).Within(1e-7f)); - Assert.That(await rng2.GetUniform(), Is.EqualTo(0.83575225).Within(1e-7f)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestDeterministic02b() - { - using var rng2 = new MultiThreadedRng(16, 362_436_069); - var dist = new Uniform(rng2); - - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(13)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(58)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(6)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(68)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(61)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(18)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(34)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(96)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(13)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(64)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(11)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(19)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(36)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(48)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(17)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(25)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(44)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(34)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(94)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(55)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(3)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(96)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(56)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(69)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(86)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(88)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(69)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(85)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(1)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(83)); - } - - [Test] - [Category(TestCategories.COVER)] - [Category(TestCategories.NORMAL)] - public async Task TestDeterministic03b() - { - using var rng2 = new MultiThreadedRng(16, 362_436_069); - var dist = new CauchyLorentzX0(rng2); - - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(11)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(17)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(1)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(2)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(18)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(14)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(65)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(11)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(22)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(3)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(37)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(9)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(12)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(4)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(10)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(8)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(22)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(2)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(3)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(20)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(4)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(1)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(84)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(9)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(19)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(2)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(1)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(10)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(4)); - Assert.That(await dist.NextNumber(1, 100), Is.EqualTo(56)); - } - } -} \ No newline at end of file diff --git a/FastRngTests/Float/PerformanceTests.cs b/FastRngTests/Float/PerformanceTests.cs deleted file mode 100644 index bf99a11..0000000 --- a/FastRngTests/Float/PerformanceTests.cs +++ /dev/null @@ -1,137 +0,0 @@ -using System; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Threading; -using System.Threading.Tasks; -using FastRng.Float; -using FastRng.Float.Distributions; -using MathNet.Numerics.Distributions; -using MathNet.Numerics.Random; -using NUnit.Framework; - -namespace FastRngTests.Float -{ - [ExcludeFromCodeCoverage] - public class PerformanceTests - { - #region FastRng - - [Test] - [Category(TestCategories.PERFORMANCE)] - public async Task Generate1MUniform() - { - using var rng = new MultiThreadedRng(); - var data = new float[1_000_000]; - var stopwatch = new Stopwatch(); - Thread.Sleep(TimeSpan.FromSeconds(10)); // Warm-up phase of generator - - stopwatch.Start(); - for (uint n = 0; n < data.Length; n++) - data[n] = await rng.GetUniform(); - - stopwatch.Stop(); - - TestContext.WriteLine($"Generated 1M uniform distributed random numbers in {stopwatch.Elapsed.Minutes} minute(s), {stopwatch.Elapsed.Seconds} second(s), and {stopwatch.Elapsed.Milliseconds} milliseconds."); - } - - [Test] - [Category(TestCategories.PERFORMANCE)] - public async Task Generate1MNormal() - { - using var rng = new MultiThreadedRng(); - var dist = new NormalS02M05(rng); - var data = new float[1_000_000]; - var stopwatch = new Stopwatch(); - Thread.Sleep(TimeSpan.FromSeconds(10)); // Warm-up phase of generator - - stopwatch.Start(); - for (uint n = 0; n < data.Length; n++) - data[n] = await dist.NextNumber(); - - stopwatch.Stop(); - - TestContext.WriteLine($"Generated 1M normal distributed random numbers in {stopwatch.Elapsed.Minutes} minute(s), {stopwatch.Elapsed.Seconds} second(s), and {stopwatch.Elapsed.Milliseconds} milliseconds."); - } - - [Test] - [Category(TestCategories.PERFORMANCE)] - public async Task Generate1MChiSquare() - { - using var rng = new MultiThreadedRng(); - var dist = new ChiSquareK4(rng); - var data = new float[1_000_000]; - var stopwatch = new Stopwatch(); - Thread.Sleep(TimeSpan.FromSeconds(10)); // Warm-up phase of generator - - stopwatch.Start(); - for (uint n = 0; n < data.Length; n++) - data[n] = await dist.NextNumber(); - - stopwatch.Stop(); - - TestContext.WriteLine($"Generated 1M chi-square distributed random numbers in {stopwatch.Elapsed.Minutes} minute(s), {stopwatch.Elapsed.Seconds} second(s), and {stopwatch.Elapsed.Milliseconds} milliseconds."); - } - - #endregion - - #region Math.NET - - [Test] - [Category(TestCategories.PERFORMANCE)] - public void ComparisonMathNet1MUniform() - { - var rng = new Xorshift(true); - var data = new float[1_000_000]; - var stopwatch = new Stopwatch(); - Thread.Sleep(TimeSpan.FromSeconds(10)); // Warm-up phase of generator - - stopwatch.Start(); - for (uint n = 0; n < data.Length; n++) - data[n] = (float) rng.NextDouble(); - - stopwatch.Stop(); - - TestContext.WriteLine($"Generated 1M uniform distributed random numbers by means of Math.NET in {stopwatch.Elapsed.Minutes} minute(s), {stopwatch.Elapsed.Seconds} second(s), and {stopwatch.Elapsed.Milliseconds} milliseconds."); - } - - [Test] - [Category(TestCategories.PERFORMANCE)] - public void ComparisonMathNet1MNormal() - { - var rng = new Xorshift(true); - var dist = new Normal(stddev: 0.2f, mean: 0.5f, randomSource: rng); - var data = new float[1_000_000]; - var stopwatch = new Stopwatch(); - Thread.Sleep(TimeSpan.FromSeconds(10)); // Warm-up phase of generator - - stopwatch.Start(); - for (uint n = 0; n < data.Length; n++) - data[n] = (float) dist.Sample(); - - stopwatch.Stop(); - - TestContext.WriteLine($"Generated 1M normal distributed random numbers by means of Math.NET in {stopwatch.Elapsed.Minutes} minute(s), {stopwatch.Elapsed.Seconds} second(s), and {stopwatch.Elapsed.Milliseconds} milliseconds."); - } - - [Test] - [Category(TestCategories.PERFORMANCE)] - public void ComparisonMathNet1MChiSquare() - { - var rng = new Xorshift(true); - var dist = new ChiSquared(4); - var data = new float[1_000_000]; - var stopwatch = new Stopwatch(); - Thread.Sleep(TimeSpan.FromSeconds(10)); // Warm-up phase of generator - - stopwatch.Start(); - for (uint n = 0; n < data.Length; n++) - data[n] = (float) dist.Sample(); - - stopwatch.Stop(); - - TestContext.WriteLine($"Generated 1M chi-squared distributed random numbers by means of Math.NET in {stopwatch.Elapsed.Minutes} minute(s), {stopwatch.Elapsed.Seconds} second(s), and {stopwatch.Elapsed.Milliseconds} milliseconds."); - } - - #endregion - } -} \ No newline at end of file diff --git a/FastRngTests/Float/RunningStatistics.cs b/FastRngTests/Float/RunningStatistics.cs deleted file mode 100644 index 13be97e..0000000 --- a/FastRngTests/Float/RunningStatistics.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System; -using System.Diagnostics.CodeAnalysis; - -namespace FastRngTests.Float -{ - [ExcludeFromCodeCoverage] - internal sealed class RunningStatistics - { - private float previousM; - private float previousS; - private float nextM; - private float nextS; - - public RunningStatistics() - { - } - - public int NumberRecords { get; private set; } = 0; - - public void Clear() => this.NumberRecords = 0; - - public void Push(float x) - { - this.NumberRecords++; - - // See Knuth TAOCP vol 2, 3rd edition, page 232 - if (this.NumberRecords == 1) - { - this.previousM = this.nextM = x; - this.previousS = 0.0f; - } - else - { - this.nextM = this.previousM + (x - this.previousM) / this.NumberRecords; - this.nextS = this.previousS + (x - this.previousM) * (x - this.nextM); - - // set up for next iteration - this.previousM = this.nextM; - this.previousS = this.nextS; - } - } - - public float Mean => this.NumberRecords > 0 ? this.nextM : 0.0f; - - public float Variance => this.NumberRecords > 1 ? this.nextS / (this.NumberRecords - 1f) : 0.0f; - - public float StandardDeviation => MathF.Sqrt(this.Variance); - } -} \ No newline at end of file diff --git a/FastRngTests/FrequencyAnalysis.cs b/FastRngTests/FrequencyAnalysis.cs new file mode 100644 index 0000000..64c7b4d --- /dev/null +++ b/FastRngTests/FrequencyAnalysis.cs @@ -0,0 +1,83 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Text; + +namespace FastRngTests; + +[ExcludeFromCodeCoverage] +public sealed class FrequencyAnalysis +{ + private readonly uint[] data; + + public FrequencyAnalysis(int samples = 100) + { + this.data = new uint[samples]; + } + + public void CountThis(float value) + { + var bucket = (int)MathF.Floor(value * this.data.Length); + this.data[bucket]++; + } + + public float[] GetNormalizedEvents() + { + var max = (float) this.data.Max(); + var result = new float[this.data.Length]; + for (var n = 0; n < this.data.Length; n++) + { + result[n] = this.data[n] / max; + } + + return result; + } + + private float[] Normalize() + { + var max = (float)this.data.Max(); + var result = new float[this.data.Length]; + for (var n = 0; n < this.data.Length; n++) + result[n] = this.data[n] / max; + + return result; + } + + public float[] NormalizeAndPlotEvents(Action writer) + { + var result = this.Normalize(); + Plot(result, writer, "Event Distribution"); + + return result; + } + + public void PlotOccurence(Action writer) + { + var data = this.data.Select(n => n > 0f ? 1.0f : 0.0f).ToArray(); + Plot(data, writer, "Occurrence Distribution"); + } + + private static void Plot(float[] data, Action writer, string name) + { + const int HEIGHT = 16; + + var values = new float[data.Length]; + for (var n = 0; n < data.Length; n++) + { + values[n] = data[n] * HEIGHT; + } + + var sb = new StringBuilder(); + for (var line = HEIGHT; line > 0; line--) + { + for (var column = 0; column < data.Length; column++) + sb.Append(values[column] >= line ? '█' : '░'); + + writer.Invoke(sb.ToString()); + sb.Clear(); + } + + writer.Invoke(name); + writer.Invoke(string.Empty); + } +} \ No newline at end of file diff --git a/FastRngTests/MathToolsTests.cs b/FastRngTests/MathToolsTests.cs new file mode 100644 index 0000000..3a4e0a3 --- /dev/null +++ b/FastRngTests/MathToolsTests.cs @@ -0,0 +1,324 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using FastRng; +using NUnit.Framework; + +namespace FastRngTests; + +[ExcludeFromCodeCoverage] +public class MathToolsTests +{ + #region Gamma + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void GammaTest01() + { + Assert.That(MathToolsFloatingPoint.Gamma(-0.5f), Is.EqualTo(-3.544907701811087f).Within(1e-6f)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void GammaTest02() + { + Assert.That(MathToolsFloatingPoint.Gamma(0.1f), Is.EqualTo(9.51350975f).Within(1e-6f)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void GammaTest03() + { + Assert.That(MathToolsFloatingPoint.Gamma(0.5f), Is.EqualTo(1.772453850905517f).Within(1e-6f)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void GammaTest04() + { + Assert.That(MathToolsFloatingPoint.Gamma(1.0f), Is.EqualTo(1.0f).Within(1e-6f)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void GammaTest05() + { + Assert.That(MathToolsFloatingPoint.Gamma(1.5f), Is.EqualTo(0.8862269254527587f).Within(1e-6f)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void GammaTest06() + { + Assert.That(MathToolsFloatingPoint.Gamma(2.0f), Is.EqualTo(1.0f).Within(1e-6f)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void GammaTest07() + { + Assert.That(MathToolsFloatingPoint.Gamma(3.0f), Is.EqualTo(2.0f).Within(1e-6f)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void GammaTest08() + { + Assert.That(MathToolsFloatingPoint.Gamma(10.0f), Is.EqualTo(362_880.719f).Within(1e-6f)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void GammaTest09() + { + Assert.That(MathToolsFloatingPoint.Gamma(140.0f), Is.EqualTo(float.NaN)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void GammaTest10() + { + Assert.That(MathToolsFloatingPoint.Gamma(170.0f), Is.EqualTo(float.NaN)); + } + + #endregion + + #region Factorial (integer) + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void FactorialInteger01() + { + Assert.That(MathToolsInteger.Factorial(0), Is.EqualTo(1)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void FactorialInteger02() + { + Assert.That(MathToolsInteger.Factorial(1), Is.EqualTo(1)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void FactorialInteger03() + { + Assert.That(MathToolsInteger.Factorial(2), Is.EqualTo(2)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void FactorialInteger04() + { + Assert.That(MathToolsInteger.Factorial(3), Is.EqualTo(6)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void FactorialInteger05() + { + Assert.That(MathToolsInteger.Factorial(4), Is.EqualTo(24)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void FactorialInteger06() + { + Assert.That(MathToolsInteger.Factorial(5), Is.EqualTo(120)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void FactorialInteger07() + { + Assert.That(MathToolsInteger.Factorial(6), Is.EqualTo(720)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void FactorialInteger08() + { + Assert.That(MathToolsInteger.Factorial(7), Is.EqualTo(5_040)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void FactorialInteger09() + { + Assert.That(MathToolsInteger.Factorial(8), Is.EqualTo(40_320)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void FactorialInteger10() + { + Assert.That(MathToolsInteger.Factorial(9), Is.EqualTo(362_880)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void FactorialInteger11() + { + Assert.That(MathToolsInteger.Factorial(10), Is.EqualTo(3_628_800)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void FactorialInteger12() + { + Assert.That(MathToolsInteger.Factorial(11), Is.EqualTo(39_916_800)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void FactorialInteger13() + { + Assert.That(MathToolsInteger.Factorial(12), Is.EqualTo(479_001_600)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void FactorialInteger14() + { + Assert.That(MathToolsInteger.Factorial(13), Is.EqualTo(6_227_020_800)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void FactorialInteger15() + { + Assert.That(MathToolsInteger.Factorial(14), Is.EqualTo(87_178_291_200)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void FactorialInteger16() + { + Assert.That(MathToolsInteger.Factorial(15), Is.EqualTo(1_307_674_368_000)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void FactorialInteger17() + { + Assert.That(MathToolsInteger.Factorial(16), Is.EqualTo(20_922_789_888_000)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void FactorialInteger18() + { + Assert.That(MathToolsInteger.Factorial(17), Is.EqualTo(355_687_428_096_000)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void FactorialInteger19() + { + Assert.That(MathToolsInteger.Factorial(18), Is.EqualTo(6_402_373_705_728_000)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void FactorialInteger20() + { + Assert.That(MathToolsInteger.Factorial(19), Is.EqualTo(121_645_100_408_832_000)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void FactorialInteger21() + { + Assert.That(MathToolsInteger.Factorial(20), Is.EqualTo(2_432_902_008_176_640_000)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void FactorialInteger22() + { + Assert.Throws(() => MathToolsInteger.Factorial(21)); + + // Note: 21! is not possible in C# until we got 128 bit integers, since: + // ulong.max == 18_446_744_073_709_551_615 < 51_090_942_171_709_400_000 + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void FactorialInteger23() + { + Assert.Throws(() => MathToolsInteger.Factorial(45_646)); + + // Note: 45_646! is not possible in C# since: + // ulong.max == 18_446_744_073_709_551_615 + } + + #endregion + + #region Factorial (floating point) + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void FactorialFloatingPoint01() + { + Assert.That(MathToolsFloatingPoint.Factorial(0.5f), Is.EqualTo(0.886226925f).Within(1e6f)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void FactorialFloatingPoint02() + { + Assert.That(MathToolsFloatingPoint.Factorial(1.5f), Is.EqualTo(1.329340388f).Within(1e6f)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void FactorialFloatingPoint03() + { + Assert.That(MathToolsFloatingPoint.Factorial(-1.5f), Is.EqualTo(-1.329340388f).Within(1e6f)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void FactorialFloatingPoint04() + { + Assert.That(MathToolsFloatingPoint.Factorial(7.5f), Is.EqualTo(14_034.407293483f).Within(1e6f)); + } + + #endregion +} \ No newline at end of file diff --git a/FastRngTests/MultiThreadedRngTests.cs b/FastRngTests/MultiThreadedRngTests.cs new file mode 100644 index 0000000..ae9cc83 --- /dev/null +++ b/FastRngTests/MultiThreadedRngTests.cs @@ -0,0 +1,623 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Threading; +using FastRng; +using FastRng.Distributions; +using NUnit.Framework; + +namespace FastRngTests; + +[ExcludeFromCodeCoverage] +public class MultiThreadedRngTests +{ + private readonly IRandom rng = new MultiThreadedRng(); + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestRange01Uint() + { + var dist = new Uniform(this.rng); + for (uint n = 0; n < 1_000_000; n++) + Assert.That(dist.NextNumber(n, 100_000 + n), Is.InRange(n, 100_000 + n)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestRange01Ulong() + { + var dist = new Uniform(this.rng); + for (ulong n = 0; n < 1_000_000; n++) + Assert.That(dist.NextNumber (n, 100_000 + n), Is.InRange(n, 100_000 + n)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestRange01Float() + { + var dist = new Uniform(this.rng); + for (var n = 0.0f; n < 1e6f; n++) + Assert.That(dist.NextNumber (n, 100_000 + n), Is.InRange(n, 100_000 + n)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestRange02Uint() + { + var dist = new Uniform(this.rng); + Assert.That(dist.NextNumber (5, 5), Is.EqualTo(5)); + Assert.That(dist.NextNumber (0, 0), Is.EqualTo(0)); + Assert.That(dist.NextNumber (3_000_000_000, 3_000_000_000), Is.EqualTo(3_000_000_000)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestRange02Ulong() + { + var dist = new Uniform(this.rng); + Assert.That(dist.NextNumber (5UL, 5), Is.EqualTo(5)); + Assert.That(dist.NextNumber (0UL, 0), Is.EqualTo(0)); + Assert.That(dist.NextNumber (3_000_000_000UL, 3_000_000_000), Is.EqualTo(3_000_000_000)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestRange02Float() + { + var dist = new Uniform(this.rng); + Assert.That(dist.NextNumber (5f, 5f), Is.EqualTo(5)); + Assert.That(dist.NextNumber (0f, 0f), Is.EqualTo(0)); + Assert.That(dist.NextNumber (3e9f, 3e9f), Is.EqualTo(3e9f)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestRange03Uint() + { + var dist = new Uniform(this.rng); + Assert.That(dist.NextNumber (5, 6), Is.InRange(5, 6)); + Assert.That(dist.NextNumber (0, 1), Is.InRange(0, 1)); + Assert.That(dist.NextNumber (3_000_000_000, 3_000_000_002), Is.InRange(3_000_000_000, 3_000_000_002)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestRange03Ulong() + { + var dist = new Uniform(this.rng); + Assert.That(dist.NextNumber (5UL, 6), Is.InRange(5, 6)); + Assert.That(dist.NextNumber (0UL, 1), Is.InRange(0, 1)); + Assert.That(dist.NextNumber (3_000_000_000UL, 3_000_000_002), Is.InRange(3_000_000_000, 3_000_000_002)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestRange03Float() + { + var dist = new Uniform(this.rng); + Assert.That(dist.NextNumber (5f, 6f), Is.InRange(5f, 6f)); + Assert.That(dist.NextNumber (0f, 1f), Is.InRange(0f, 1f)); + Assert.That(dist.NextNumber (3e9f, 3e9f+2f), Is.InRange(3e9f, 3e9f+2f)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestRange04Uint() + { + var distUniform = new Uniform(this.rng); + var distNormal = new NormalS02M05(this.rng); + + Assert.That(distUniform.NextNumber(10, 1), Is.InRange(1, 10)); + Assert.That(distNormal.NextNumber(10, 1), Is.InRange(1, 10)); + + Assert.That(distUniform.NextNumber(20, 1), Is.InRange(1, 20)); + Assert.That(distNormal.NextNumber(20, 1), Is.InRange(1, 20)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestRange04Ulong() + { + var distUniform = new Uniform(this.rng); + var distNormal = new NormalS02M05(this.rng); + + Assert.That(distUniform.NextNumber(10UL, 1), Is.InRange(1, 10)); + Assert.That(distNormal.NextNumber(10UL, 1), Is.InRange(1, 10)); + + Assert.That(distUniform.NextNumber(20UL, 1), Is.InRange(1, 20)); + Assert.That(distNormal.NextNumber(20UL, 1), Is.InRange(1, 20)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestRange04Float() + { + var distUniform = new Uniform(this.rng); + var distNormal = new NormalS02M05(this.rng); + + Assert.That(distUniform.NextNumber(10.0f, 1), Is.InRange(1, 10)); + Assert.That(distNormal.NextNumber(10.0f, 1), Is.InRange(1, 10)); + + Assert.That(distUniform.NextNumber(20.0f, 1), Is.InRange(1, 20)); + Assert.That(distNormal.NextNumber(20.0f, 1), Is.InRange(1, 20)); + } + + [Test] + [Category(TestCategories.LONG_RUNNING)] + public void TestRange05() + { + var distUniform = new Uniform(this.rng); + var distLorentz = new CauchyLorentzX1(this.rng); + + var rngContains0 = false; + var rngContains1 = false; + + var uniformContains0 = false; + var uniformContains1 = false; + + var lorentzContains0 = false; + var lorentzContains1 = false; + + for (int i = 0; i < 100_000_000; i++) + { + var rngValue = this.rng.GetUniform(); + var uniform = distUniform.NextNumber(); + var lorentz = distLorentz.NextNumber(); + + switch (rngValue) + { + case 0.0f: + rngContains0 = true; + break; + case 1.0f: + rngContains1 = true; + break; + } + + switch (uniform) + { + case 0.0f: + uniformContains0 = true; + break; + case 1.0f: + uniformContains1 = true; + break; + } + + switch (lorentz) + { + case 0.0f: + lorentzContains0 = true; + break; + case 1.0f: + lorentzContains1 = true; + break; + } + } + + TestContext.WriteLine($"Uniform generator contained 0? {rngContains0} (expected=false)"); + TestContext.WriteLine($"Uniform generator contained 1? {rngContains1} (expected=true)"); + TestContext.WriteLine($"Uniform distribution contained 0? {uniformContains0} (expected=false)"); + TestContext.WriteLine($"Uniform distribution contained 1? {uniformContains1} (expected=true)"); + TestContext.WriteLine($"Lorentz distribution contained 0? {lorentzContains0} (expected=false)"); + TestContext.WriteLine($"Lorentz distribution contained 1? {lorentzContains1} (expected=true)"); + + Assert.That(rngContains0, Is.False, "Uniform generator contained 0"); + Assert.That(rngContains1, Is.True, "Uniform generator does not contained 1"); + + Assert.That(uniformContains0, Is.False, "Uniform distribution contained 0"); + Assert.That(uniformContains1, Is.True, "Uniform distribution does not contained 1"); + + Assert.That(lorentzContains0, Is.False, "Lorentz distribution contained 0"); + Assert.That(lorentzContains1, Is.True, "Lorentz distribution does not contained 1"); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestStoppingProducers01() + { + var rng2 = new MultiThreadedRng(); + rng2.Dispose(); + + var masterToken = new CancellationTokenSource(TimeSpan.FromSeconds(16)).Token; + var wasCanceled = false; + + while(true) + { + var tokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(3)); + rng2.GetUniform(tokenSource.Token); + if (tokenSource.IsCancellationRequested) + { + wasCanceled = true; + break; + } + + if (masterToken.IsCancellationRequested) + { + break; + } + } + + Assert.That(masterToken.IsCancellationRequested, Is.False, "Master token was used to stop test"); + Assert.That(wasCanceled, Is.True, "The consumer was not canceled"); + + var tokenSource2 = new CancellationTokenSource(TimeSpan.FromSeconds(3)); + new NormalS02M05(rng2).NextNumber(tokenSource2.Token); + Assert.That(tokenSource2.IsCancellationRequested, Is.True); + + tokenSource2 = new CancellationTokenSource(TimeSpan.FromSeconds(3)); + new NormalS02M05(rng2).NextNumber(-1f, 1f, tokenSource2.Token); + Assert.That(tokenSource2.IsCancellationRequested, Is.True); + + tokenSource2 = new CancellationTokenSource(TimeSpan.FromSeconds(3)); + new NormalS02M05(rng2).NextNumber(0u, 6u, tokenSource2.Token); + Assert.That(tokenSource2.IsCancellationRequested, Is.True); + + tokenSource2 = new CancellationTokenSource(TimeSpan.FromSeconds(3)); + new NormalS02M05(rng2).NextNumber(0ul, 6ul, tokenSource2.Token); + Assert.That(tokenSource2.IsCancellationRequested, Is.True); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void OneSeed01() + { + using var rng1 = new MultiThreadedRng(6); + using var rng2 = new MultiThreadedRng(6); + using var rng3 = new MultiThreadedRng(7); + + var rng1Sample = new float[10]; + for (var n = 0; n < rng1Sample.Length; n++) + rng1Sample[n] = rng1.GetUniform(); + + var rng2Sample = new float[10]; + for (var n = 0; n < rng2Sample.Length; n++) + rng2Sample[n] = rng2.GetUniform(); + + var rng3Sample = new float[10]; + for (var n = 0; n < rng3Sample.Length; n++) + rng3Sample[n] = rng3.GetUniform(); + + Assert.That(rng1Sample, Is.EquivalentTo(rng2Sample)); + Assert.That(rng1Sample, Is.Not.EquivalentTo(rng3Sample)); + Assert.That(rng2Sample, Is.Not.EquivalentTo(rng3Sample)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TwoSeeds01() + { + using var rng1 = new MultiThreadedRng(3, 6); + using var rng2 = new MultiThreadedRng(3, 6); + using var rng3 = new MultiThreadedRng(3, 7); + using var rng4 = new MultiThreadedRng(6, 3); + + var rng1Sample = new float[10]; + for (var n = 0; n < rng1Sample.Length; n++) + rng1Sample[n] = rng1.GetUniform(); + + var rng2Sample = new float[10]; + for (var n = 0; n < rng2Sample.Length; n++) + rng2Sample[n] = rng2.GetUniform(); + + var rng3Sample = new float[10]; + for (var n = 0; n < rng3Sample.Length; n++) + rng3Sample[n] = rng3.GetUniform(); + + var rng4Sample = new float[10]; + for (var n = 0; n < rng4Sample.Length; n++) + rng4Sample[n] = rng4.GetUniform(); + + Assert.That(rng1Sample, Is.EquivalentTo(rng2Sample)); + Assert.That(rng1Sample, Is.Not.EquivalentTo(rng3Sample)); + Assert.That(rng1Sample, Is.Not.EquivalentTo(rng4Sample)); + Assert.That(rng2Sample, Is.Not.EquivalentTo(rng3Sample)); + Assert.That(rng2Sample, Is.Not.EquivalentTo(rng4Sample)); + Assert.That(rng3Sample, Is.Not.EquivalentTo(rng4Sample)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void NoSeed01() + { + using var rng1 = new MultiThreadedRng(); + using var rng2 = new MultiThreadedRng(); + using var rng3 = new MultiThreadedRng(); + + var rng1Sample = new float[10]; + for (var n = 0; n < rng1Sample.Length; n++) + rng1Sample[n] = rng1.GetUniform(); + + var rng2Sample = new float[10]; + for (var n = 0; n < rng2Sample.Length; n++) + rng2Sample[n] = rng2.GetUniform(); + + var rng3Sample = new float[10]; + for (var n = 0; n < rng3Sample.Length; n++) + rng3Sample[n] = rng3.GetUniform(); + + Assert.That(rng1Sample, Is.Not.EquivalentTo(rng2Sample)); + Assert.That(rng1Sample, Is.Not.EquivalentTo(rng3Sample)); + Assert.That(rng2Sample, Is.Not.EquivalentTo(rng3Sample)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestCancellation01() + { + var tokenSource = new CancellationTokenSource(); + var token = tokenSource.Token; + tokenSource.Cancel(); + + using var rng2 = new MultiThreadedRng(); + var dist = new Uniform(this.rng); + Assert.That(dist.NextNumber (1, 100_000, token), Is.EqualTo(0)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestCancellation02() + { + var tokenSource = new CancellationTokenSource(); + var token = tokenSource.Token; + tokenSource.Cancel(); + + using var rng2 = new MultiThreadedRng(); + Assert.That(rng2.GetUniform(token), Is.NaN); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestDeterministic01() + { + using var rng2 = new MultiThreadedRng(16); + + Assert.That(rng2.GetUniform(), Is.EqualTo(0.12712699).Within(1e-7f)); + Assert.That(rng2.GetUniform(), Is.EqualTo(0.5764246).Within(1e-7f)); + Assert.That(rng2.GetUniform(), Is.EqualTo(0.06033641).Within(1e-7f)); + Assert.That(rng2.GetUniform(), Is.EqualTo(0.6822646).Within(1e-7f)); + Assert.That(rng2.GetUniform(), Is.EqualTo(0.61201024).Within(1e-7f)); + Assert.That(rng2.GetUniform(), Is.EqualTo(0.17746393).Within(1e-7f)); + Assert.That(rng2.GetUniform(), Is.EqualTo(0.33456334).Within(1e-7f)); + Assert.That(rng2.GetUniform(), Is.EqualTo(0.96167856).Within(1e-7f)); + Assert.That(rng2.GetUniform(), Is.EqualTo(0.12944269).Within(1e-7f)); + Assert.That(rng2.GetUniform(), Is.EqualTo(0.64489424).Within(1e-7f)); + Assert.That(rng2.GetUniform(), Is.EqualTo(0.109665975).Within(1e-7f)); + Assert.That(rng2.GetUniform(), Is.EqualTo(0.18188846).Within(1e-7f)); + Assert.That(rng2.GetUniform(), Is.EqualTo(0.36097932).Within(1e-7f)); + Assert.That(rng2.GetUniform(), Is.EqualTo(0.48192585).Within(1e-7f)); + Assert.That(rng2.GetUniform(), Is.EqualTo(0.1617974).Within(1e-7f)); + Assert.That(rng2.GetUniform(), Is.EqualTo(0.24791045).Within(1e-7f)); + Assert.That(rng2.GetUniform(), Is.EqualTo(0.43913218).Within(1e-7f)); + Assert.That(rng2.GetUniform(), Is.EqualTo(0.3343723).Within(1e-7f)); + Assert.That(rng2.GetUniform(), Is.EqualTo(0.9428737).Within(1e-7f)); + Assert.That(rng2.GetUniform(), Is.EqualTo(0.55195147).Within(1e-7f)); + Assert.That(rng2.GetUniform(), Is.EqualTo(0.027495692).Within(1e-7f)); + Assert.That(rng2.GetUniform(), Is.EqualTo(0.9621458).Within(1e-7f)); + Assert.That(rng2.GetUniform(), Is.EqualTo(0.55794334).Within(1e-7f)); + Assert.That(rng2.GetUniform(), Is.EqualTo(0.69002056).Within(1e-7f)); + Assert.That(rng2.GetUniform(), Is.EqualTo(0.86020225).Within(1e-7f)); + Assert.That(rng2.GetUniform(), Is.EqualTo(0.88220626).Within(1e-7f)); + Assert.That(rng2.GetUniform(), Is.EqualTo(0.68816894).Within(1e-7f)); + Assert.That(rng2.GetUniform(), Is.EqualTo(0.8583311).Within(1e-7f)); + Assert.That(rng2.GetUniform(), Is.EqualTo(0.003915685).Within(1e-7f)); + Assert.That(rng2.GetUniform(), Is.EqualTo(0.83575225).Within(1e-7f)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestDeterministic02() + { + using var rng2 = new MultiThreadedRng(16); + var dist = new Uniform(rng2); + + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(13)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(58)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(6)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(68)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(61)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(18)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(34)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(96)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(13)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(64)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(11)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(19)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(36)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(48)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(17)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(25)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(44)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(34)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(94)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(55)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(3)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(96)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(56)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(69)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(86)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(88)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(69)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(85)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(1)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(83)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestDeterministic03() + { + using var rng2 = new MultiThreadedRng(16); + var dist = new CauchyLorentzX0(rng2); + + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(11)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(17)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(1)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(2)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(18)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(14)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(65)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(11)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(22)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(3)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(37)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(9)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(12)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(4)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(10)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(8)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(22)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(2)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(3)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(20)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(4)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(1)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(84)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(9)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(19)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(2)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(1)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(10)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(4)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(56)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestDeterministic01b() + { + using var rng2 = new MultiThreadedRng(16, 362_436_069); + + Assert.That(rng2.GetUniform(), Is.EqualTo(0.12712699).Within(1e-7f)); + Assert.That(rng2.GetUniform(), Is.EqualTo(0.5764246).Within(1e-7f)); + Assert.That(rng2.GetUniform(), Is.EqualTo(0.06033641).Within(1e-7f)); + Assert.That(rng2.GetUniform(), Is.EqualTo(0.6822646).Within(1e-7f)); + Assert.That(rng2.GetUniform(), Is.EqualTo(0.61201024).Within(1e-7f)); + Assert.That(rng2.GetUniform(), Is.EqualTo(0.17746393).Within(1e-7f)); + Assert.That(rng2.GetUniform(), Is.EqualTo(0.33456334).Within(1e-7f)); + Assert.That(rng2.GetUniform(), Is.EqualTo(0.96167856).Within(1e-7f)); + Assert.That(rng2.GetUniform(), Is.EqualTo(0.12944269).Within(1e-7f)); + Assert.That(rng2.GetUniform(), Is.EqualTo(0.64489424).Within(1e-7f)); + Assert.That(rng2.GetUniform(), Is.EqualTo(0.109665975).Within(1e-7f)); + Assert.That(rng2.GetUniform(), Is.EqualTo(0.18188846).Within(1e-7f)); + Assert.That(rng2.GetUniform(), Is.EqualTo(0.36097932).Within(1e-7f)); + Assert.That(rng2.GetUniform(), Is.EqualTo(0.48192585).Within(1e-7f)); + Assert.That(rng2.GetUniform(), Is.EqualTo(0.1617974).Within(1e-7f)); + Assert.That(rng2.GetUniform(), Is.EqualTo(0.24791045).Within(1e-7f)); + Assert.That(rng2.GetUniform(), Is.EqualTo(0.43913218).Within(1e-7f)); + Assert.That(rng2.GetUniform(), Is.EqualTo(0.3343723).Within(1e-7f)); + Assert.That(rng2.GetUniform(), Is.EqualTo(0.9428737).Within(1e-7f)); + Assert.That(rng2.GetUniform(), Is.EqualTo(0.55195147).Within(1e-7f)); + Assert.That(rng2.GetUniform(), Is.EqualTo(0.027495692).Within(1e-7f)); + Assert.That(rng2.GetUniform(), Is.EqualTo(0.9621458).Within(1e-7f)); + Assert.That(rng2.GetUniform(), Is.EqualTo(0.55794334).Within(1e-7f)); + Assert.That(rng2.GetUniform(), Is.EqualTo(0.69002056).Within(1e-7f)); + Assert.That(rng2.GetUniform(), Is.EqualTo(0.86020225).Within(1e-7f)); + Assert.That(rng2.GetUniform(), Is.EqualTo(0.88220626).Within(1e-7f)); + Assert.That(rng2.GetUniform(), Is.EqualTo(0.68816894).Within(1e-7f)); + Assert.That(rng2.GetUniform(), Is.EqualTo(0.8583311).Within(1e-7f)); + Assert.That(rng2.GetUniform(), Is.EqualTo(0.003915685).Within(1e-7f)); + Assert.That(rng2.GetUniform(), Is.EqualTo(0.83575225).Within(1e-7f)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestDeterministic02b() + { + using var rng2 = new MultiThreadedRng(16, 362_436_069); + var dist = new Uniform(rng2); + + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(13)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(58)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(6)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(68)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(61)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(18)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(34)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(96)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(13)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(64)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(11)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(19)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(36)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(48)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(17)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(25)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(44)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(34)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(94)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(55)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(3)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(96)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(56)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(69)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(86)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(88)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(69)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(85)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(1)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(83)); + } + + [Test] + [Category(TestCategories.COVER)] + [Category(TestCategories.NORMAL)] + public void TestDeterministic03b() + { + using var rng2 = new MultiThreadedRng(16, 362_436_069); + var dist = new CauchyLorentzX0(rng2); + + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(11)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(17)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(1)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(2)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(18)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(14)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(65)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(11)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(22)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(3)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(37)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(9)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(12)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(4)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(10)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(8)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(22)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(2)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(3)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(20)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(4)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(1)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(84)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(9)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(19)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(2)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(1)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(10)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(4)); + Assert.That(dist.NextNumber (1, 100), Is.EqualTo(56)); + } +} \ No newline at end of file diff --git a/FastRngTests/PerformanceTests.cs b/FastRngTests/PerformanceTests.cs new file mode 100644 index 0000000..f0b151e --- /dev/null +++ b/FastRngTests/PerformanceTests.cs @@ -0,0 +1,154 @@ +using System; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Threading; +using System.Threading.Tasks; +using FastRng; +using FastRng.Distributions; +using MathNet.Numerics.Distributions; +using MathNet.Numerics.Random; +using NUnit.Framework; + +namespace FastRngTests; + +[ExcludeFromCodeCoverage] +public class PerformanceTests +{ + #region FastRng + + [Test] + [Category(TestCategories.PERFORMANCE)] + public async Task Generate1MUniformMultiThreaded() + { + using var rng = new MultiThreadedRng(); + var data = new float[1_000_000]; + var stopwatch = new Stopwatch(); + Thread.Sleep(TimeSpan.FromSeconds(10)); // Warm-up phase of generator + + stopwatch.Start(); + for (uint n = 0; n < data.Length; n++) + data[n] = rng.GetUniform(); + + stopwatch.Stop(); + + TestContext.WriteLine($"Generated 1M uniform distributed random numbers in {stopwatch.Elapsed.Minutes} minute(s), {stopwatch.Elapsed.Seconds} second(s), and {stopwatch.Elapsed.Milliseconds} milliseconds."); + } + + [Test] + [Category(TestCategories.PERFORMANCE)] + public async Task Generate1MUniformMultiChannel() + { + using var rng = new MultiChannelRng(); + var data = new float[1_000_000]; + var stopwatch = new Stopwatch(); + Thread.Sleep(TimeSpan.FromSeconds(10)); // Warm-up phase of generator + + stopwatch.Start(); + for (uint n = 0; n < data.Length; n++) + data[n] = rng.GetUniform(); + + stopwatch.Stop(); + + TestContext.WriteLine($"Generated 1M uniform distributed random numbers in {stopwatch.Elapsed.Minutes} minute(s), {stopwatch.Elapsed.Seconds} second(s), and {stopwatch.Elapsed.Milliseconds} milliseconds."); + } + + [Test] + [Category(TestCategories.PERFORMANCE)] + public async Task Generate1MNormal() + { + using var rng = new MultiThreadedRng(); + var dist = new NormalS02M05(rng); + var data = new float[1_000_000]; + var stopwatch = new Stopwatch(); + Thread.Sleep(TimeSpan.FromSeconds(10)); // Warm-up phase of generator + + stopwatch.Start(); + for (uint n = 0; n < data.Length; n++) + data[n] = dist.NextNumber(); + + stopwatch.Stop(); + + TestContext.WriteLine($"Generated 1M normal distributed random numbers in {stopwatch.Elapsed.Minutes} minute(s), {stopwatch.Elapsed.Seconds} second(s), and {stopwatch.Elapsed.Milliseconds} milliseconds."); + } + + [Test] + [Category(TestCategories.PERFORMANCE)] + public async Task Generate1MChiSquare() + { + using var rng = new MultiThreadedRng(); + var dist = new ChiSquareK4(rng); + var data = new float[1_000_000]; + var stopwatch = new Stopwatch(); + Thread.Sleep(TimeSpan.FromSeconds(10)); // Warm-up phase of generator + + stopwatch.Start(); + for (uint n = 0; n < data.Length; n++) + data[n] = dist.NextNumber(); + + stopwatch.Stop(); + + TestContext.WriteLine($"Generated 1M chi-square distributed random numbers in {stopwatch.Elapsed.Minutes} minute(s), {stopwatch.Elapsed.Seconds} second(s), and {stopwatch.Elapsed.Milliseconds} milliseconds."); + } + + #endregion + + #region Math.NET + + [Test] + [Category(TestCategories.PERFORMANCE)] + public void ComparisonMathNet1MUniform() + { + var rng = new Xorshift(true); + var data = new float[1_000_000]; + var stopwatch = new Stopwatch(); + Thread.Sleep(TimeSpan.FromSeconds(10)); // Warm-up phase of generator + + stopwatch.Start(); + for (uint n = 0; n < data.Length; n++) + data[n] = (float) rng.NextDouble(); + + stopwatch.Stop(); + + TestContext.WriteLine($"Generated 1M uniform distributed random numbers by means of Math.NET in {stopwatch.Elapsed.Minutes} minute(s), {stopwatch.Elapsed.Seconds} second(s), and {stopwatch.Elapsed.Milliseconds} milliseconds."); + } + + [Test] + [Category(TestCategories.PERFORMANCE)] + public void ComparisonMathNet1MNormal() + { + var rng = new Xorshift(true); + var dist = new Normal(stddev: 0.2f, mean: 0.5f, randomSource: rng); + var data = new float[1_000_000]; + var stopwatch = new Stopwatch(); + Thread.Sleep(TimeSpan.FromSeconds(10)); // Warm-up phase of generator + + stopwatch.Start(); + for (uint n = 0; n < data.Length; n++) + data[n] = (float) dist.Sample(); + + stopwatch.Stop(); + + TestContext.WriteLine($"Generated 1M normal distributed random numbers by means of Math.NET in {stopwatch.Elapsed.Minutes} minute(s), {stopwatch.Elapsed.Seconds} second(s), and {stopwatch.Elapsed.Milliseconds} milliseconds."); + } + + [Test] + [Category(TestCategories.PERFORMANCE)] + public void ComparisonMathNet1MChiSquare() + { + var rng = new Xorshift(true); + var dist = new ChiSquared(4); + var data = new float[1_000_000]; + var stopwatch = new Stopwatch(); + Thread.Sleep(TimeSpan.FromSeconds(10)); // Warm-up phase of generator + + stopwatch.Start(); + for (uint n = 0; n < data.Length; n++) + data[n] = (float) dist.Sample(); + + stopwatch.Stop(); + + TestContext.WriteLine($"Generated 1M chi-squared distributed random numbers by means of Math.NET in {stopwatch.Elapsed.Minutes} minute(s), {stopwatch.Elapsed.Seconds} second(s), and {stopwatch.Elapsed.Milliseconds} milliseconds."); + } + + #endregion +} \ No newline at end of file diff --git a/FastRngTests/RunningStatistics.cs b/FastRngTests/RunningStatistics.cs new file mode 100644 index 0000000..3bd51fe --- /dev/null +++ b/FastRngTests/RunningStatistics.cs @@ -0,0 +1,44 @@ +using System; +using System.Diagnostics.CodeAnalysis; + +namespace FastRngTests; + +[ExcludeFromCodeCoverage] +internal sealed class RunningStatistics +{ + private float previousM; + private float previousS; + private float nextM; + private float nextS; + + private int NumberRecords { get; set; } = 0; + + public void Clear() => this.NumberRecords = 0; + + public void Push(float x) + { + this.NumberRecords++; + + // See Knuth TAOCP vol 2, 3rd edition, page 232 + if (this.NumberRecords == 1) + { + this.previousM = this.nextM = x; + this.previousS = 0.0f; + } + else + { + this.nextM = this.previousM + (x - this.previousM) / this.NumberRecords; + this.nextS = this.previousS + (x - this.previousM) * (x - this.nextM); + + // set up for next iteration + this.previousM = this.nextM; + this.previousS = this.nextS; + } + } + + public float Mean => this.NumberRecords > 0 ? this.nextM : 0.0f; + + public float Variance => this.NumberRecords > 1 ? this.nextS / (this.NumberRecords - 1f) : 0.0f; + + public float StandardDeviation => MathF.Sqrt(this.Variance); +} \ No newline at end of file diff --git a/FastRngTests/TestCategories.cs b/FastRngTests/TestCategories.cs index d23fb4b..a523612 100644 --- a/FastRngTests/TestCategories.cs +++ b/FastRngTests/TestCategories.cs @@ -1,11 +1,10 @@ -namespace FastRngTests +namespace FastRngTests; + +public static class TestCategories { - public class TestCategories - { - public const string COVER = "cover"; - public const string PERFORMANCE = "performance"; - public const string NORMAL = "normal"; - public const string EXAMPLE = "example"; - public const string LONG_RUNNING = "long running"; - } + public const string COVER = "cover"; + public const string PERFORMANCE = "performance"; + public const string NORMAL = "normal"; + public const string EXAMPLE = "example"; + public const string LONG_RUNNING = "long running"; } \ No newline at end of file diff --git a/README.md b/README.md index 9a99d2c..a9b8e04 100644 --- a/README.md +++ b/README.md @@ -2,13 +2,13 @@ FastRng is a multi-threaded pseudo-random number generator. Besides the generation of uniformly distributed random numbers, there are several other distributions to choose from. For performance reasons the parameters of the distributions are not user-definable. For some distributions, therefore, different parameter variations are available. If a different combination is desired, a separate class can be created. -Please note, that Math.NET's (https://www.mathdotnet.com/) random number generator is in some situations faster. Unlike Math.NET, MultiThreadedRng is multi-threaded and async. Consumers can await the next number without blocking resources. Additionally, consumers can use a token to cancel e.g. timeout an operation as well. +Please note, that Math.NET's (https://www.mathdotnet.com/) random number generator is in some situations faster. Unlike Math.NET, MultiThreadedRng is multi-threaded. Consumers can use a token to cancel e.g. timeout an operation. FastRng (class `MultiThreadedRng`) using a shape fitter (a rejection sampler) to enforce arbitrary shapes of probabilities for desired distributions. By using the shape fitter, it is even easy to define discontinuous, arbitrary functions as shapes. Any consumer can define and use own distributions. The class `MultiThreadedRng` uses the George Marsaglia's MWC algorithm. The algorithm's implementation based loosely on John D. Cook's (johndcook.com) [implementation](https://www.codeproject.com/Articles/25172/Simple-Random-Number-Generation). Thanks John for the inspiration. -Please notice: When using the debug environment, MultiThreadedRng uses a smaller buffer size. Please ensure, that the production environment uses a release build, though. +Please notice: When using the debug environment, MultiThreadedRng might uses a smaller buffer size. Please ensure, that the production environment uses a release build, though. ## Usage Example code: @@ -19,19 +19,19 @@ using FastRng.Float.Distributions; [...] -using var rng = new MultiThreadedRng(); -var dist = new ChiSquareK1(rng); +using var rng = new MultiThreadedRng(); +var dist = new ChiSquareK1(rng); -var value1 = await dist.NextNumber(); -var value2 = await dist.NextNumber(rangeStart: -1.0f, rangeEnd: 1.0f); -if(await dist.HasDecisionBeenMade(above: 0.8f, below: 0.9f)) +var value1 = dist.NextNumber(); +var value2 = dist.NextNumber(rangeStart: -1.0f, rangeEnd: 1.0f); +if(dist.HasDecisionBeenMade(above: 0.8f, below: 0.9f)) { // Decision has been made } ``` Notes: -- `MultiThreadedRng` and all distributions are available as `float` and `double` variations. Both are supporting `uint` and `ulong` as well. +- `MultiThreadedRng` and all distributions are using generic math types: you might use `float`, `double`, or `Half`. - `MultiThreadedRng` is `IDisposable`. It is important to call `Dispose`, when the generator is not needed anymore. Otherwise, the supporting background threads are still running.