Server/project/src/utils/MathUtil.ts
2023-03-03 15:23:46 +00:00

104 lines
3.6 KiB
TypeScript

import { injectable } from "tsyringe";
@injectable()
export class MathUtil
{
/**
* Helper to create the sum of all array elements
* @param {array} values The array with numbers of which to calculate the sum
* @return {number} sum(values)
*/
public arraySum(values: number[]): number
{
// sum with initial value being 0
return values.reduce((sum, x) => sum + x, 0);
}
/**
* Helper to create the cumulative sum of all array elements
* arrayCumsum([1, 2, 3, 4]) = [1, 3, 6, 10]
* @param {array} values The array with numbers of which to calculate the cumulative sum
* @return {array} cumsum(values)
*/
public arrayCumsum(values: number[]): number[]
{
// curried function for cumulative sum: (cum, x) => cum += x
// and 0 being the initial value for the map
return values.map((cum => x => cum += x)(0));
}
/**
* Helper to create the product of each element times factor
* @param {array} values The array of numbers which shall be multiplied by the factor
* @return {array} array times factor
*/
public arrayProd(values: number[], factor: number): number[]
{
return values.map(x => x * factor);
}
/**
* Helper to add a constant to all array elements
* @param {array} values The array of numbers to which the summand should be added
* @return {array} array plus summand
*/
public arrayAdd(values: number[], summand: number): number[]
{
return values.map(x => x + summand);
}
/**
* Map a value from an input range to an output range linearly
*
* Example:
* a_min = 0; a_max=1;
* b_min = 1; b_max=3;
* MathUtil.mapToRange(0.5, a_min, a_max, b_min, b_max) // returns 2
*
* @param {number} x The value from input range to be mapped to output range
* @param {number} minIn min of input range
* @param {number} maxIn max of input range
* @param {number} minOut min of output range
* @param {number} maxOut max of outout range
* @return {number} the result of the mapping
*/
public mapToRange(x: number, minIn: number, maxIn: number, minOut: number, maxOut: number): number
{
const deltaIn = maxIn - minIn;
const deltaOut = maxOut - minOut;
const 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
*
* @param {string} xp the point of x at which to interpolate
* @param {array} x support points in x (of same length as y)
* @param {array} y support points in y (of same length as x)
* @return {number} y(xp)
*/
public interp1(xp: number, x: number[], y: number[]): number
{
if (xp > x[x.length - 1])
{
return y[y.length - 1];
}
else if (xp < x[0])
{
return y[0];
}
else
{
for (let 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]);
}
}
}
}
}