X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=src%2Futils%2FUtils.ts;h=3d8c73bdf0cdbeec9516dd079832587a0696ebba;hb=6082281f1beebdf0126417b694c134ea4753442c;hp=f701cea041ab831d1b1ff323123e02c60b69b11b;hpb=878e026c886468c5d488b75a6d3636abea6fc07c;p=e-mobility-charging-stations-simulator.git diff --git a/src/utils/Utils.ts b/src/utils/Utils.ts index f701cea0..3d8c73bd 100644 --- a/src/utils/Utils.ts +++ b/src/utils/Utils.ts @@ -3,7 +3,6 @@ import util from 'node:util'; import clone from 'just-clone'; -// import { Constants } from './internal'; import { Constants } from './Constants'; import { WebSocketCloseEventStatusString } from '../types'; @@ -191,7 +190,7 @@ export class Utils { } public static isCFEnvironment(): boolean { - return process.env.VCAP_APPLICATION !== undefined; + return !Utils.isNullOrUndefined(process.env.VCAP_APPLICATION); } public static isIterable(obj: T): boolean { @@ -222,18 +221,12 @@ export class Utils { return value == null; } - public static isEmptyArray(object: unknown | unknown[]): boolean { - if (Array.isArray(object) && object.length === 0) { - return true; - } - return false; + public static isEmptyArray(object: unknown): boolean { + return Array.isArray(object) && object.length === 0; } - public static isNotEmptyArray(object: unknown | unknown[]): boolean { - if (Array.isArray(object) && object.length > 0) { - return true; - } - return false; + public static isNotEmptyArray(object: unknown): boolean { + return Array.isArray(object) && object.length > 0; } public static isEmptyObject(obj: object): boolean { @@ -255,9 +248,9 @@ export class Utils { * @param retryNumber - the number of retries that have already been attempted * @returns delay in milliseconds */ - public static exponentialDelay(retryNumber = 0): number { + public static exponentialDelay(retryNumber = 0, maxDelayRatio = 0.2): number { const delay = Math.pow(2, retryNumber) * 100; - const randomSum = delay * 0.2 * Utils.secureRandom(); // 0-20% of the delay + const randomSum = delay * maxDelayRatio * Utils.secureRandom(); // 0-20% of the delay return delay + randomSum; } @@ -341,4 +334,59 @@ export class Utils { } 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 percentileIndexInteger = Math.floor(percentileIndexBase); + if (!Utils.isNullOrUndefined(sortedDataSet[percentileIndexInteger + 1])) { + return ( + sortedDataSet[percentileIndexInteger] + + (percentileIndexBase - percentileIndexInteger) * + (sortedDataSet[percentileIndexInteger + 1] - sortedDataSet[percentileIndexInteger]) + ); + } + return sortedDataSet[percentileIndexInteger]; + } + + 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); + } }