This commit is contained in:
158
packages/util/src/numbers.ts
Normal file
158
packages/util/src/numbers.ts
Normal file
@@ -0,0 +1,158 @@
|
||||
//pin implementations
|
||||
const random = Math.random;
|
||||
const ceil = Math.ceil;
|
||||
const floor = Math.floor;
|
||||
|
||||
/**
|
||||
* Rounds a number to one decimal places.
|
||||
* @param num The number to round.
|
||||
* @returns The input number rounded to one decimal places.
|
||||
*/
|
||||
export function roundTo1(num: number): number {
|
||||
return Math.round((num + Number.EPSILON) * 10) / 10;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rounds a number to two decimal places.
|
||||
* @param num The number to round.
|
||||
* @returns The input number rounded to two decimal places.
|
||||
*/
|
||||
export function roundTo2(num: number): number {
|
||||
return Math.round((num + Number.EPSILON) * 100) / 100;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the mean (average) of an array of numbers.
|
||||
* @param array An array of numbers.
|
||||
* @returns The mean of the input array.
|
||||
*/
|
||||
export function mean(array: number[]): number {
|
||||
try {
|
||||
return (
|
||||
array.reduce((previous, current) => (current += previous)) / array.length
|
||||
);
|
||||
} catch (e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the standard deviation of an array of numbers.
|
||||
* @param array An array of numbers.
|
||||
* @returns The standard deviation of the input array.
|
||||
*/
|
||||
export function stdDev(array: number[]): number {
|
||||
try {
|
||||
const n = array.length;
|
||||
const meanValue = mean(array);
|
||||
return Math.sqrt(
|
||||
array.map((x) => Math.pow(x - meanValue, 2)).reduce((a, b) => a + b) / n,
|
||||
);
|
||||
} catch (e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the median of an array of numbers.
|
||||
* https://www.w3resource.com/javascript-exercises/fundamental/javascript-fundamental-exercise-88.php
|
||||
* @param arr An array of numbers.
|
||||
* @returns The median of the input array.
|
||||
*/
|
||||
export function median(arr: number[]): number {
|
||||
try {
|
||||
const mid = Math.floor(arr.length / 2),
|
||||
nums = [...arr].sort((a, b) => a - b);
|
||||
return arr.length % 2 !== 0
|
||||
? (nums[mid] as number)
|
||||
: ((nums[mid - 1] as number) + (nums[mid] as number)) / 2;
|
||||
} catch (e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates consistency by mapping COV from [0, +infinity) to [100, 0).
|
||||
* The mapping function is a version of the sigmoid function tanh(x) that is closer to the identity function tanh(arctanh(x)) in [0, 1).
|
||||
* @param cov The coefficient of variation of an array of numbers (standard deviation / mean).
|
||||
* @returns Consistency
|
||||
*/
|
||||
export function kogasa(cov: number): number {
|
||||
return (
|
||||
100 * (1 - Math.tanh(cov + Math.pow(cov, 3) / 3 + Math.pow(cov, 5) / 5))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an integer between min and max, both are inclusive.
|
||||
* @param min
|
||||
* @param max
|
||||
* @returns Random integer betwen min and max.
|
||||
*/
|
||||
export function randomIntFromRange(min: number, max: number): number {
|
||||
const minNorm = ceil(min);
|
||||
const maxNorm = floor(max);
|
||||
return floor(random() * (maxNorm - minNorm + 1) + minNorm);
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a value from one range to another.
|
||||
* @param value The value to map.
|
||||
* @param inMin Input range minimum.
|
||||
* @param inMax Input range maximum.
|
||||
* @param outMin Output range minimum.
|
||||
* @param outMax Output range maximum.
|
||||
* @param clamp If true, the result is clamped to the output range. Default true.
|
||||
* @returns The mapped value.
|
||||
*/
|
||||
export function mapRange(
|
||||
value: number,
|
||||
inMin: number,
|
||||
inMax: number,
|
||||
outMin: number,
|
||||
outMax: number,
|
||||
clamp = true,
|
||||
): number {
|
||||
if (inMin === inMax) {
|
||||
return outMin;
|
||||
}
|
||||
|
||||
const result =
|
||||
((value - inMin) * (outMax - outMin)) / (inMax - inMin) + outMin;
|
||||
|
||||
if (clamp) {
|
||||
if (outMin < outMax) {
|
||||
return Math.min(Math.max(result, outMin), outMax);
|
||||
} else {
|
||||
return Math.max(Math.min(result, outMin), outMax);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a value is a safe number. Safe numbers are finite and not NaN.
|
||||
* @param value The value to check.
|
||||
* @returns True if the value is a safe number, false otherwise.
|
||||
*/
|
||||
export function isSafeNumber(value: unknown): value is number {
|
||||
if (typeof value === "number") {
|
||||
return !isNaN(value) && isFinite(value);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a number to a safe number or undefined. NaN, Infinity, and -Infinity are converted to undefined.
|
||||
* @param value The value to convert.
|
||||
* @returns The input number if it is safe, undefined otherwise.
|
||||
*/
|
||||
export function safeNumber(
|
||||
value: number | undefined | null,
|
||||
): number | undefined {
|
||||
if (isSafeNumber(value)) {
|
||||
return value;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
Reference in New Issue
Block a user