FastRng/FastRng/Distributions/Distribution.cs
2023-07-06 10:08:46 +02:00

75 lines
2.7 KiB
C#

using System;
using System.Threading;
using System.Threading.Tasks;
namespace FastRng.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<float> GetDistributedValue(CancellationToken token = default) => await this.fitter.NextNumber(token);
public async ValueTask<uint> 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<ulong> 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<float> 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<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;
}
}
}