import clone from 'just-clone';
-// import { Constants } from './internal';
import { Constants } from './Constants';
import { WebSocketCloseEventStatusString } from '../types';
return Math.floor(crypto.randomInt(max + 1));
}
+ /**
+ * Rounds the given number to the given scale.
+ * The rounding is done using the "round half away from zero" method.
+ *
+ * @param numberValue - The number to round.
+ * @param scale - The scale to round to.
+ * @returns The rounded number.
+ */
public static roundTo(numberValue: number, scale: number): number {
const roundPower = Math.pow(10, scale);
- return Math.round(numberValue * roundPower) / roundPower;
- }
-
- public static truncTo(numberValue: number, scale: number): number {
- const truncPower = Math.pow(10, scale);
- return Math.trunc(numberValue * truncPower) / truncPower;
+ return Math.round(numberValue * roundPower * (1 + Number.EPSILON)) / roundPower;
}
public static getRandomFloatRounded(max = Number.MAX_VALUE, min = 0, scale = 2): number {
return value == null;
}
- public static isEmptyArray(object: unknown | unknown[]): boolean {
+ public static isEmptyArray(object: unknown): boolean {
return Array.isArray(object) && object.length === 0;
}
- public static isNotEmptyArray(object: unknown | unknown[]): boolean {
+ public static isNotEmptyArray(object: unknown): boolean {
return Array.isArray(object) && object.length > 0;
}
`${str.slice(0, pos)}${subStr}${str.slice(pos)}`;
/**
+ * Computes the retry delay in milliseconds using an exponential backoff algorithm.
+ *
* @param retryNumber - the number of retries that have already been attempted
* @returns delay in milliseconds
*/
}
/**
- * Generate a cryptographically secure random number in the [0,1[ range
+ * Generates a cryptographically secure random number in the [0,1[ range
*
* @returns
*/
}
/**
- * Convert websocket error code to human readable string message
+ * Converts websocket error code to human readable string message
*
* @param code - websocket error code
* @returns human readable string message
}
return '(Unknown)';
}
-
- public static median(dataSet: number[]): number {
- if (Utils.isEmptyArray(dataSet)) {
- return 0;
- }
- if (Array.isArray(dataSet) === true && dataSet.length === 1) {
- return dataSet[0];
- }
- const sortedDataSet = dataSet.slice().sort((a, b) => a - b);
- return (
- (sortedDataSet[(sortedDataSet.length - 1) >> 1] + sortedDataSet[sortedDataSet.length >> 1]) /
- 2
- );
- }
-
- // TODO: use order statistics tree https://en.wikipedia.org/wiki/Order_statistic_tree
- public static percentile(dataSet: number[], percentile: number): number {
- if (percentile < 0 && percentile > 100) {
- throw new RangeError('Percentile is not between 0 and 100');
- }
- if (Utils.isEmptyArray(dataSet)) {
- return 0;
- }
- const sortedDataSet = dataSet.slice().sort((a, b) => a - b);
- if (percentile === 0 || sortedDataSet.length === 1) {
- return sortedDataSet[0];
- }
- if (percentile === 100) {
- return sortedDataSet[sortedDataSet.length - 1];
- }
- const percentileIndexBase = (percentile / 100) * (sortedDataSet.length - 1);
- const percentileIntegerIndex = Math.floor(percentileIndexBase);
- if (!Utils.isNullOrUndefined(sortedDataSet[percentileIntegerIndex + 1])) {
- return (
- sortedDataSet[percentileIntegerIndex] +
- (percentileIndexBase - percentileIntegerIndex) *
- (sortedDataSet[percentileIntegerIndex + 1] - sortedDataSet[percentileIntegerIndex])
- );
- }
- return sortedDataSet[percentileIntegerIndex];
- }
-
- public static stdDeviation(dataSet: number[]): number {
- let totalDataSet = 0;
- for (const data of dataSet) {
- totalDataSet += data;
- }
- const dataSetMean = totalDataSet / dataSet.length;
- let totalGeometricDeviation = 0;
- for (const data of dataSet) {
- const deviation = data - dataSetMean;
- totalGeometricDeviation += deviation * deviation;
- }
- return Math.sqrt(totalGeometricDeviation / dataSet.length);
- }
}