using System;
using System.Numerics;
namespace FastRng;
///
/// Provides some mathematical function, which are not available within in .NET itself.
///
public static class FloatingPointMathTools 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);
}