using System.Numerics;
using Core.Annotations;
namespace Core.Utils;
[Injectable(InjectionType.Singleton)]
public class MathUtil
{
///
/// Helper to create the sum of all list elements
///
/// List of floats to sum
/// sum of all values
public float ListSum(List values)
{
// Sum the list starting with an initial value of 0
return values.Aggregate(0f, (sum, x) => sum + x);
}
///
/// Helper to create the cumulative sum of all list elements
/// ListCumSum([1, 2, 3, 4]) = [1, 3, 6, 10]
///
/// The list with numbers of which to calculate the cumulative sum
/// cumulative sum of values
public List ListCumSum(List values)
{
var cumSumList = new List(values.Count);
float sum = 0;
foreach (var value in values)
{
sum += value;
cumSumList.Add(sum);
}
return cumSumList;
}
///
/// Helper to create the product of each element times factor
///
/// The list of numbers which shall be multiplied by the factor
/// Number to multiply each element by
/// A list of elements all multiplied by the factor
public List ListProduct(List values, float factor)
{
return values.Select(v => v * factor).ToList();
}
///
/// Helper to add a constant to all list elements
///
/// The list of numbers to which the summand should be added
///
/// A list of elements with the additive added to all elements
public List ListAdd(List values, float additive)
{
return values.Select(v => v + additive).ToList();
}
///
/// Maps a value from an input range to an output range linearly.
///
/// Example:
/// a_min = 0; a_max=1;
/// b_min = 1; b_max=3;
/// MapToRange(0.5, a_min, a_max, b_min, b_max) // returns 2
///
///
/// The value from the input range to be mapped to the output range.
/// Minimum of the input range.
/// Maximum of the input range.
/// Minimum of the output range.
/// Maximum of the output range.
/// The result of the mapping.
public double MapToRange(double x, double minIn, double maxIn, double minOut, double maxOut)
{
var deltaIn = maxIn - minIn;
var deltaOut = maxOut - minOut;
var xScale = (x - minIn) / deltaIn;
return Math.Max(minOut, Math.Min(maxOut, minOut + xScale * deltaOut));
}
///
/// Linear interpolation
/// e.g. used to do a continuous integration for quest rewards which are defined for specific support centers of pmcLevel
///
/// The point of x at which to interpolate
/// Support points in x (of same length as y)
/// Support points in y (of same length as x)
/// Interpolated value at xp, or null if xp is out of bounds
public static double? Interp1(double xp, double[] x, double[] y)
{
if (xp > x[^1]) // ^1 is the last index in C#
{
return y[^1];
}
if (xp < x[0])
{
return y[0];
}
for (var i = 0; i < x.Length - 1; i++)
{
if (xp >= x[i] && xp <= x[i + 1])
{
return y[i] + (xp - x[i]) * (y[i + 1] - y[i]) / (x[i + 1] - x[i]);
}
}
return null;
}
}