FastRng/FastRng/Distributions/Distribution.cs
2023-07-06 10:26:12 +02:00

63 lines
2.4 KiB
C#

using System;
using System.Threading;
using System.Threading.Tasks;
namespace FastRng.Distributions;
public abstract class Distribution : IDistribution
{
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 float ShapeFunction(float x);
public async ValueTask<float> GetDistributedValue(CancellationToken token = default) => await this.fitter.NextNumber(token);
public async ValueTask<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 = await this.GetDistributedValue(cancel);
return (uint) ((distributedValue * range) + rangeStart);
}
public async ValueTask<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 = await this.GetDistributedValue(cancel);
return (ulong) ((distributedValue * range) + rangeStart);
}
public async ValueTask<float> NextNumber(float rangeStart, float 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 = await this.GetDistributedValue(cancel);
return (distributedValue * range) + rangeStart;
}
public async ValueTask<float> NextNumber(CancellationToken cancel = default) => await this.NextNumber(0.0f, 1.0f, cancel);
public async ValueTask<bool> HasDecisionBeenMade(float above, float below = 1, CancellationToken cancel = default)
{
var number = await this.NextNumber(cancel);
return number > above && number < below;
}
}