name:
src/Formulas/Statistical.ts
-rw-r--r--
70516
1import {
2 ArgsChecker
3} from "../Utilities/ArgsChecker";
4import {
5 CriteriaFunctionFactory
6} from "../Utilities/CriteriaFunctionFactory";
7import {
8 Filter
9} from "../Utilities/Filter";
10import {
11 TypeConverter
12} from "../Utilities/TypeConverter";
13import {
14 RefError, NumError, DivZeroError, NAError, ValueError
15} from "../Errors";
16import {
17 SUM,
18 ABS,
19 FLOOR,
20 COMBIN
21} from "./Math";
22import {
23 cdf,
24 covariance,
25 inv,
26 pdf,
27 stdev,
28 cleanFloat,
29 mean,
30 gammafn,
31 sum,
32 erf,
33 gammaln
34} from "../Utilities/MathHelpers";
35import {isDefined, isUndefined} from "../Utilities/MoreUtils";
36
37
38/**
39 * Calculates the sum of squares of deviations based on a sample.
40 * @param values - The values or ranges of the sample.
41 * @returns {number} sum of squares of deviations
42 * @constructor
43 */
44let DEVSQ = function (...values) : number {
45 ArgsChecker.checkAtLeastLength(values, 1, "DEVSQ");
46 let range = Filter.flattenAndThrow(values);
47 let result = 0;
48 let count = 0;
49 for (let i = 0; i < range.length; i++) {
50 result = result + TypeConverter.valueToNumber(range[i]);
51 count++;
52 }
53 let mean = result / count;
54 result = 0;
55 for (let i = 0; i < range.length; i++) {
56 result += Math.pow((TypeConverter.valueToNumber(range[i]) - mean), 2);
57 }
58 return result;
59};
60
61/**
62 * Returns the median value in a numeric dataset.
63 * @param values - The value(s) or range(s) to consider when calculating the median value.
64 * @returns {number} the median value of the dataset
65 * @constructor
66 */
67let MEDIAN = function (...values) : number {
68 ArgsChecker.checkAtLeastLength(values, 1, "MEDIAN");
69 let sortedArray = [];
70 values.forEach(function (currentValue) {
71 if (currentValue instanceof Array) {
72 if (currentValue.length === 0) {
73 throw new RefError("Reference does not exist.");
74 }
75 let filtered = Filter.filterOutStringValues(currentValue);
76 sortedArray = sortedArray.concat(filtered);
77 } else {
78 sortedArray.push(TypeConverter.valueToNumber(currentValue));
79 }
80 });
81 sortedArray = sortedArray.sort(function (a, b) {
82 let aN = TypeConverter.valueToNumber(a);
83 let bN = TypeConverter.valueToNumber(b);
84 return aN - bN;
85 });
86 if (sortedArray.length === 1) {
87 return TypeConverter.valueToNumber(sortedArray[0]);
88 }
89 if (sortedArray.length === 0) {
90 throw new NumError("MEDIAN has no valid input data.");
91 }
92 // even number of values
93 if (sortedArray.length % 2 === 0) {
94 if (sortedArray.length === 2) {
95 return AVERAGE(sortedArray[0], sortedArray[1]);
96 }
97 let top = sortedArray[sortedArray.length / 2];
98 let bottom = sortedArray[(sortedArray.length / 2) - 1];
99 return AVERAGE(top, bottom);
100 } else {
101 // odd number of values
102 return sortedArray[Math.round(sortedArray.length / 2) - 1];
103 }
104};
105
106/**
107 * Returns the numerical average value in a dataset, ignoring text.
108 * @param values - The values or ranges to consider when calculating the average value.
109 * @returns {number} the average value of this dataset.
110 * @constructor
111 */
112let AVERAGE = function (...values) : number {
113 ArgsChecker.checkAtLeastLength(values, 1, "AVERAGE");
114 let result = 0;
115 let count = 0;
116 for (let i = 0; i < values.length; i++) {
117 if (values[i] instanceof Array) {
118 if (values[i].length === 0) {
119 throw new RefError("Reference does not exist.");
120 }
121 let filtered = Filter.filterOutStringValues(values[i]);
122 result = result + SUM.apply(this, filtered);
123 count += filtered.length;
124 } else {
125 result = result + TypeConverter.valueToNumber(values[i]);
126 count++;
127 }
128 }
129 return result / count;
130};
131
132/**
133 * Calculates the average of the magnitudes of deviations of data from a dataset's mean.
134 * @param values - The value(s) or range(s)
135 * @returns {number} average of the magnitudes of deviations of data from a dataset's mean
136 * @constructor
137 */
138let AVEDEV = function (...values) {
139 ArgsChecker.checkAtLeastLength(values, 1, "AVEDEV");
140
141 // Sort to array-values, and non-array-values
142 let arrayValues = [];
143 let nonArrayValues = [];
144 for (let i = 0; i < values.length; i++) {
145 let X = values[i];
146 if (X instanceof Array) {
147 if (X.length === 0) {
148 throw new RefError("Reference does not exist.");
149 }
150 arrayValues.push(X);
151 } else {
152 nonArrayValues.push(TypeConverter.valueToNumber(X));
153 }
154 }
155
156 // Remove string values from array-values, but not from non-array-values, and concat.
157 let flatValues = Filter.filterOutStringValues(Filter.flatten(arrayValues)).map(function (value) {
158 return TypeConverter.valueToNumber(value);
159 }).concat(nonArrayValues);
160
161 // Calculating mean
162 let result = 0;
163 let count = 0;
164 for (let i = 0; i < flatValues.length; i++) {
165 result = result + TypeConverter.valueToNumber(flatValues[i]);
166 count++;
167 }
168 if (count === 0) {
169 throw new DivZeroError("Evaluation of function AVEDEV caused a devide by zero error.");
170 }
171 let mean = result / count;
172
173 for (let i = 0; i < flatValues.length; i++) {
174 flatValues[i] = ABS(TypeConverter.valueToNumber(flatValues[i]) - mean);
175 }
176 return SUM(flatValues) / flatValues.length;
177};
178
179/**
180 * Returns the numerical average value in a dataset, coercing text values in ranges to 0 values.
181 * @param values - value(s) or range(s) to consider when calculating the average value.
182 * @returns {number} the numerical average value in a dataset
183 * @constructor
184 */
185let AVERAGEA = function (...values) {
186 ArgsChecker.checkAtLeastLength(values, 1, "AVERAGEA");
187 let result = 0;
188 let count = 0;
189 for (let i = 0; i < values.length; i++) {
190 if (values[i] instanceof Array) {
191 if (values[i].length === 0) {
192 throw new RefError("Reference does not exist.");
193 }
194 let filtered = Filter.stringValuesToZeros(values[i]);
195 result = result + SUM.apply(this, filtered);
196 count += filtered.length;
197 } else {
198 result = result + TypeConverter.valueToNumber(values[i]);
199 count++;
200 }
201 }
202 if (count === 0) {
203 throw new DivZeroError("Evaluation of function AVEDEV caused a devide by zero error.");
204 }
205 return result / count;
206};
207
208
209/**
210 * Calculates r, the Pearson product-moment correlation coefficient of a dataset. Any text encountered in the arguments
211 * will be ignored. CORREL is synonymous with PEARSON.
212 * @param dataY - The range representing the array or matrix of dependent data.
213 * @param dataX - The range representing the array or matrix of independent data.
214 * @returns {number} the Pearson product-moment correlation coefficient.
215 * @constructor
216 */
217let CORREL = function (dataY, dataX) : number {
218 ArgsChecker.checkLength(arguments, 2, "CORREL");
219 if (!Array.isArray(dataY)) {
220 dataY = [dataY];
221 }
222 if (!Array.isArray(dataX)) {
223 dataX = [dataX];
224 }
225 if (dataY.length !== dataX.length) {
226 throw new NAError("CORREL has mismatched argument count " + dataY + " vs " + dataX + ".");
227 }
228 let arr1 = Filter.filterOutNonNumberValues(Filter.flattenAndThrow(dataY));
229 let arr2 = Filter.filterOutNonNumberValues(Filter.flattenAndThrow(dataX));
230 let stdevArr1 = stdev(arr1, 1);
231 let stdevArr2 = stdev(arr2, 1);
232 if (stdevArr1 === 0 || stdevArr2 === 0) {
233 throw new DivZeroError("Evaluation of function CORREL caused a divide by zero error.");
234 }
235 return covariance(arr1, arr2) / stdevArr1 / stdevArr2;
236};
237
238/**
239 * Calculates r, the Pearson product-moment correlation coefficient of a dataset. Any text encountered in the arguments
240 * will be ignored. PEARSON is synonymous with CORREL.
241 * @param dataY - The range representing the array or matrix of dependent data.
242 * @param dataX - The range representing the array or matrix of independent data.
243 * @returns {number} the Pearson product-moment correlation coefficient.
244 * @constructor
245 */
246let PEARSON = function (dataY, dataX) {
247 ArgsChecker.checkLength(arguments, 2, "PEARSON");
248 return CORREL.apply(this, [dataY, dataX]);
249};
250
251/**
252 * Returns the value of the exponential distribution function with a specified lambda at a specified value.
253 * @param x - The input to the exponential distribution function. If cumulative is TRUE then EXPONDIST returns
254 * the cumulative probability of all values up to x.
255 * @param lambda - The lambda to specify the exponential distribution function.
256 * @param cumulative - Whether to use the exponential cumulative distribution.
257 * @returns {number} value of the exponential distribution function.
258 * @constructor
259 */
260let EXPONDIST = function (x, lambda, cumulative) : number {
261 ArgsChecker.checkLength(arguments, 3, "EXPONDIST");
262 function cdf(x, rate) {
263 return x < 0 ? 0 : 1 - Math.exp(-rate * x);
264 }
265 function pdf(x, rate) {
266 return x < 0 ? 0 : rate * Math.exp(-rate * x);
267 }
268 x = TypeConverter.firstValueAsNumber(x);
269 lambda = TypeConverter.firstValueAsNumber(lambda);
270 cumulative = TypeConverter.firstValueAsBoolean(cumulative);
271 return (cumulative) ? cdf(x, lambda) : pdf(x, lambda);
272};
273
274
275
276/**
277 * Calculates the left-tailed F probability distribution (degree of diversity) for two data sets with given input x.
278 * Alternately called Fisher-Snedecor distribution or Snecdor's F distribution.
279 * @param x - The input to the F probability distribution function. The value at which to evaluate the function.
280 * Must be a positive number.
281 * @param degreesFreedom1 - The numerator degrees of freedom.
282 * @param degreesFreedom2 - The denominator degrees of freedom.
283 * @param cumulative - Logical value that determines the form of the function. If true returns the cumulative
284 * distribution function. If false returns the probability density function.
285 * @returns {number|boolean} left-tailed F probability distribution
286 * @constructor
287 * TODO: This function should be stricter in its return type.
288 */
289let FDIST$LEFTTAILED = function (x, degreesFreedom1, degreesFreedom2, cumulative) : number|undefined|boolean {
290 ArgsChecker.checkLength(arguments, 4, "FDIST$LEFTTAILED");
291
292 x = TypeConverter.firstValueAsNumber(x);
293 if (x < 0) {
294 throw new NumError("Function F.DIST parameter 1 value is " + x + ". It should be greater than or equal to 0.");
295 }
296 let d1 = TypeConverter.firstValueAsNumber(degreesFreedom1);
297 let d2 = TypeConverter.firstValueAsNumber(degreesFreedom2);
298 let cum = TypeConverter.firstValueAsBoolean(cumulative);
299 return (cum) ? cdf(x, d1, d2) : pdf(x, d1, d2);
300};
301
302
303/**
304 * Returns the inverse of the (right-tailed) F probability distribution. If p = FDIST(x,...), then FINV(p,...) = x. The
305 * F distribution can be used in an F-test that compares the degree of variability in two data sets.
306 * @param probability - A probability associated with the F cumulative distribution.
307 * @param degFreedom1 - Required. The numerator degrees of freedom.
308 * @param degFreedom2 - Required. The denominator degrees of freedom.
309 * @returns {number} inverse of the (right-tailed) F probability distribution
310 * @constructor
311 */
312let FINV = function (probability, degFreedom1, degFreedom2) : number {
313 ArgsChecker.checkLength(arguments, 3, "FINV");
314
315 probability = TypeConverter.firstValueAsNumber(probability);
316 if (probability <= 0.0 || probability > 1.0) {
317 throw new NumError("Function FINV parameter 1 value is " + probability
318 + ". It should be greater than or equal to 0, and less than 1.")
319 }
320 let d1 = TypeConverter.firstValueAsNumber(degFreedom1);
321 let d2 = TypeConverter.firstValueAsNumber(degFreedom2);
322 return inv(1.0 - probability, d1, d2);
323};
324
325/**
326 * Returns the Fisher transformation of a specified value.
327 * @param value - The value for which to calculate the Fisher transformation.
328 * @returns {number} Fisher transformation
329 * @constructor
330 */
331let FISHER = function (value) : number {
332 ArgsChecker.checkLength(arguments, 1, "FISHER");
333 let x = TypeConverter.firstValueAsNumber(value);
334 if (x <= -1 || x >= 1) {
335 throw new NumError("Function FISHER parameter 1 value is " + x + ". Valid values are between -1 and 1 exclusive.");
336 }
337 return Math.log((1 + x) / (1 - x)) / 2;
338};
339
340/**
341 * Returns the inverse Fisher transformation of a specified value.
342 * @param value - The value for which to calculate the inverse Fisher transformation.
343 * @returns {number} inverse Fisher transformation
344 * @constructor
345 */
346let FISHERINV = function (value) : number {
347 ArgsChecker.checkLength(arguments, 1, "FISHERINV");
348 let y = TypeConverter.firstValueAsNumber(value);
349 let e2y = Math.exp(2 * y);
350 return (e2y - 1) / (e2y + 1);
351};
352
353/**
354 * Returns the maximum value in a numeric dataset.
355 * @param values - The values or range(s) to consider when calculating the maximum value.
356 * @returns {number} the maximum value of the dataset
357 * @constructor
358 */
359let MAX = function (...values) {
360 ArgsChecker.checkAtLeastLength(values, 1, "MAX");
361 let maxSoFar = -Infinity;
362 for (let i = 0; i < values.length; i++) {
363 if (values[i] instanceof Array) {
364 if (values[i].length === 0) {
365 throw new RefError("Reference does not exist.");
366 }
367 let filtered = Filter.filterOutStringValues(values[i]);
368 if (filtered.length !== 0) {
369 maxSoFar = Math.max(MAX.apply(this, filtered), maxSoFar);
370 }
371 } else {
372 maxSoFar = Math.max(TypeConverter.valueToNumber(values[i]), maxSoFar);
373 }
374 }
375 return maxSoFar;
376};
377
378/**
379 * Returns the maximum numeric value in a dataset.
380 * @param values - The value(s) or range(s) to consider when calculating the maximum value.
381 * @returns {number} maximum value of the dataset
382 * @constructor
383 */
384let MAXA = function (...values) : number {
385 ArgsChecker.checkAtLeastLength(values, 1, "MAXA");
386 let maxSoFar = -Infinity;
387 let filteredValues = Filter.stringValuesToZeros(values);
388 for (let i = 0; i < filteredValues.length; i++) {
389 if (filteredValues[i] instanceof Array) {
390 if (values[i].length === 0) {
391 throw new RefError("Reference does not exist.");
392 }
393 let filtered = Filter.stringValuesToZeros(filteredValues[i]);
394 if (filtered.length !== 0) {
395 maxSoFar = Math.max(MAXA.apply(this, filtered), maxSoFar);
396 }
397 } else {
398 maxSoFar = Math.max(TypeConverter.valueToNumber(filteredValues[i]), maxSoFar);
399 }
400 }
401 return maxSoFar;
402};
403
404
405/**
406 * Returns the minimum value in a numeric dataset.
407 * @param values - The value(s) or range(s) to consider when calculating the minimum value.
408 * @returns {number} the minimum value of the dataset
409 * @constructor
410 */
411let MIN = function (...values) {
412 ArgsChecker.checkAtLeastLength(values, 1, "MIN");
413 let minSoFar = Infinity;
414 for (let i = 0; i < values.length; i++) {
415 if (values[i] instanceof Array) {
416 if (values[i].length === 0) {
417 throw new RefError("Reference does not exist.");
418 }
419 let filtered = Filter.filterOutStringValues(values[i]);
420 if (filtered.length !== 0) {
421 minSoFar = Math.min(MIN.apply(this, filtered), minSoFar);
422 }
423 } else {
424 minSoFar = Math.min(TypeConverter.valueToNumber(values[i]), minSoFar);
425 }
426 }
427 return minSoFar;
428};
429
430
431/**
432 * Returns the minimum numeric value in a dataset.
433 * @param values - The value(s) or range(s) to consider when calculating the minimum value.
434 * @returns {number} the minimum value in the dataset
435 * @constructor
436 */
437let MINA = function (...values) : number {
438 ArgsChecker.checkAtLeastLength(values, 1, "MINA");
439 return MIN.apply(this, values);
440};
441
442
443/**
444 * Returns the average of a range depending on criteria.
445 * @param criteriaRange - The range to check against criterion.
446 * @param criterion - The pattern or test to apply to criteria_range.
447 * @param averageRange - [optional] The range to average. If not included, criteria_range is used for the
448 * average instead.
449 * @returns {number}
450 * @constructor
451 * TODO: This needs to also accept a third parameter "average_range"
452 */
453let AVERAGEIF = function (criteriaRange, criterion, averageRange?) {
454 ArgsChecker.checkLength(arguments, 2, "AVERAGEIF");
455 let range = Filter.flatten(criteriaRange);
456 let criteriaEvaluation = CriteriaFunctionFactory.createCriteriaFunction(criterion);
457
458 let result = 0;
459 let count = 0;
460 for (let i = 0; i < range.length; i++) {
461 let val = TypeConverter.valueToNumber(range[i]);
462 if (criteriaEvaluation(val)) {
463 result = result + val;
464 count++;
465 }
466 }
467 if (count === 0) {
468 throw new DivZeroError("Evaluation of function AVERAGEIF caused a divide by zero error.");
469 }
470 return result / count;
471};
472
473
474/**
475 * Returns the a count of the number of numeric values in a dataset.
476 * @param values - The values or ranges to consider when counting.
477 * @returns {number} number of numeric values in a dataset.
478 * @constructor
479 */
480let COUNT = function (...values) : number {
481 ArgsChecker.checkAtLeastLength(values, 1, "COUNT");
482 let count = 0;
483 for (let i = 0; i < values.length; i++) {
484 if (values[i] instanceof Array) {
485 if (values[i].length > 0) {
486 count += COUNT.apply(this, values[i]);
487 }
488 } else if (TypeConverter.canCoerceToNumber(values[i])) {
489 count++;
490 }
491 }
492 return count;
493};
494
495/**
496 * Returns the a count of the number of values in a dataset.
497 * @param values - The values or ranges to consider when counting.
498 * @returns {number} number of values in a dataset.
499 * @constructor
500 */
501let COUNTA = function (...values) : number {
502 ArgsChecker.checkAtLeastLength(values, 1, "COUNTA");
503 let count = 0;
504 for (let i = 0; i < values.length; i++) {
505 if (values[i] instanceof Array) {
506 if (values[i].length > 0) {
507 count += COUNTA.apply(this, values[i]);
508 } else {
509 count++;
510 }
511 } else {
512 count++;
513 }
514 }
515 return count;
516};
517
518
519/**
520 * Returns the value at a given percentile of a set of data.
521 * @param data - The array or range containing the dataset to consider.
522 * @param percent - percentile to be calculated and returned.
523 * @returns {number}
524 * @constructor
525 */
526let PERCENTILE = function (data, percent) {
527 ArgsChecker.checkLength(arguments, 2, "PERCENTILE");
528 let p = TypeConverter.firstValueAsNumber(percent);
529 if (p < 0 || p > 1) {
530 throw new NumError("Function PERCENTILE parameter 2 value " + p + " is out of range.");
531 }
532 let range = Filter.flattenAndThrow(data).sort(function (a, b) {
533 return a - b;
534 }).map(function (value) {
535 return TypeConverter.valueToNumber(value);
536 });
537
538 let n = range.length;
539 let l = p * (n - 1);
540 let fl = Math.floor(l);
541 return cleanFloat((l === fl) ? range[l] : range[fl] + (l - fl) * (range[fl + 1] - range[fl]));
542};
543
544
545/**
546 * Returns a value nearest to a specified quartile of a set of data.
547 * @param data - The array or range containing the set of data to consider.
548 * @param quartile - Which quartile value to return. 0 returns 0 percent mark, 1 returns 25 percent mark, 2 returns 50
549 * percent mark, 3 returns 75 percent mark, 4 returns 100 percent mark.
550 * @constructor
551 */
552let QUARTILE = function (data, quartile) {
553 ArgsChecker.checkLength(arguments, 2, "QUARTILE");
554 let q = TypeConverter.firstValueAsNumber(quartile);
555 if (q < 0 || q > 4) {
556 throw new NumError("Function QUARTILE parameter 2 value " + q + " is out of range.");
557 }
558
559
560 let range = Filter.flattenAndThrow(data).sort(function (a, b) {
561 return a - b;
562 }).map(function (value) {
563 return TypeConverter.valueToNumber(value);
564 });
565
566 switch (q) {
567 case 0:
568 return PERCENTILE(range, 0);
569 case 1:
570 return PERCENTILE(range, 0.25);
571 case 2:
572 return PERCENTILE(range, 0.5);
573 case 3:
574 return PERCENTILE(range, 0.75);
575 case 4:
576 return PERCENTILE(range, 1);
577 }
578};
579
580
581/**
582 * Calculates the standard deviation of a range, ignoring string values, regardless of whether they can be converted to
583 * numbers.
584 * @param values - Range of sample.
585 * @returns {number}
586 * @constructor
587 */
588let STDEV = function (...values) {
589 ArgsChecker.checkAtLeastLength(arguments, 1, "STDEV");
590 let range = Filter.flattenAndThrow(values);
591 let n = range.length;
592 let sigma = 0;
593 let count = 0;
594 let mean = AVERAGE(range);
595 for (let i = 0; i < n; i++) {
596 let value = TypeConverter.firstValue(range[i]);
597 if (typeof value !== "string") {
598 sigma += Math.pow(TypeConverter.valueToNumber(value) - mean, 2);
599 count++;
600 }
601 }
602 return Math.sqrt(sigma / (count - 1));
603};
604
605
606/**
607 * Calculates the standard deviation of a range, converting string values to numbers, if possible. If a value cannot
608 * be converted to a number, formula will throw a value error.
609 * @param values - Range of sample.
610 * @returns {number}
611 * @constructor
612 */
613let STDEVA = function (...values) {
614 ArgsChecker.checkAtLeastLength(arguments, 1, "STDEVA");
615 let range = Filter.flattenAndThrow(values).map(function (value) {
616 return TypeConverter.firstValueAsNumber(value);
617 });
618 let n = range.length;
619 let sigma = 0;
620 let m = mean(range);
621 for (let i = 0; i < n; i++) {
622 sigma += Math.pow(range[i] - m, 2);
623 }
624 return Math.sqrt(sigma / (n - 1));
625};
626
627
628/**
629 * Calculates the standard deviation of an entire population, ignoring string values, regardless of whether they can be
630 * converted to numbers.
631 * @param values - Entire sample.
632 * @returns {number}
633 * @constructor
634 */
635let STDEVP = function (...values) {
636 ArgsChecker.checkAtLeastLength(arguments, 1, "STDEVP");
637 let range = Filter.flattenAndThrow(values);
638 let n = range.length;
639 let sigma = 0;
640 let count = 0;
641 let m = AVERAGE(range);
642 for (let i = 0; i < n; i++) {
643 let value = TypeConverter.firstValue(range[i]);
644 if (typeof value !== "string") {
645 sigma += Math.pow(value - m, 2);
646 count++;
647 }
648 }
649 return Math.sqrt(sigma / count);
650};
651
652
653/**
654 * Calculates the standard deviation of an entire population, including text and boolean values, if possible. If a value
655 * cannot be converted to a number, formula will throw a value error.
656 * @param values - Entire sample.
657 * @returns {number}
658 * @constructor
659 */
660let STDEVPA = function (...values) {
661 ArgsChecker.checkAtLeastLength(arguments, 1, "STDEVPA");
662 let range = Filter.flattenAndThrow(values).map(function (value) {
663 return TypeConverter.firstValueAsNumber(value);
664 });
665 let n = range.length;
666 let sigma = 0;
667 let count = 0;
668 let m = AVERAGE(range);
669 for (let i = 0; i < n; i++) {
670 let value = TypeConverter.firstValue(range[i]);
671 if (typeof value !== "string") {
672 sigma += Math.pow(value - m, 2);
673 count++;
674 }
675 }
676 return Math.sqrt(sigma / count);
677};
678
679
680/**
681 * Returns the mean value of a range excluding some percentage of the range on the high and low ends of the range.
682 * @param range - Array or range to consider.
683 * @param percent - The portion of the data to exclude on both ends of the range.
684 * @returns {number}
685 * @constructor
686 */
687let TRIMMEAN = function (range, percent) {
688 ArgsChecker.checkLength(arguments, 2, "TRIMMEAN");
689 let p = TypeConverter.firstValueAsNumber(percent);
690 if (p < 0) {
691 throw new NumError("Function TRIMMEAN parameter 2 value is " + p + ". It should be greater than or equal to 0.");
692 }
693 if (p >= 1) {
694 throw new NumError("Function TRIMMEAN parameter 2 value is " + p + ". It should be less than 1.");
695 }
696 let data = Filter.flattenAndThrow(range).sort(function (a, b) {
697 return a - b;
698 }).map(function (value) {
699 return TypeConverter.valueToNumber(value);
700 });
701
702 if (data.length === 0) {
703 throw new RefError("TRIMMEAN has no valid input data.");
704 }
705
706 let trim = FLOOR(data.length * p, 2) / 2;
707 let tmp = data.slice(trim, data.length);
708 return mean(tmp.slice(0, tmp.length - trim));
709};
710
711
712/**
713 * Returns the slope of the line calculated from linear regression of a range. Any text values passed in will be ignored
714 * @param rangeY - The range or array representing the dependent data.
715 * @param rangeX - The range or array representing the independent data.
716 * @constructor
717 */
718let SLOPE = function (rangeY, rangeX) {
719 ArgsChecker.checkLength(arguments, 2, "SLOPE");
720 let dataX = Filter.flattenAndThrow(rangeX).filter(function (value) {
721 return typeof value !== "string";
722 }).map(function (value) {
723 return TypeConverter.valueToNumber(value);
724 });
725 let dataY = Filter.flattenAndThrow(rangeY).filter(function (value) {
726 return typeof value !== "string";
727 }).map(function (value) {
728 return TypeConverter.valueToNumber(value);
729 });
730 if (dataX.length !== dataY.length) {
731 throw new NAError("SLOPE has mismatched argument count " + dataX.length + " vs " + dataY.length + ".");
732 }
733 let xmean = mean(dataX);
734 let ymean = mean(dataY);
735 let n = dataX.length;
736 let num = 0;
737 let den = 0;
738 for (let i = 0; i < n; i++) {
739 num += (dataX[i] - xmean) * (dataY[i] - ymean);
740 den += Math.pow(dataX[i] - xmean, 2);
741 }
742 if (den === 0) {
743 throw new DivZeroError("Evaluation of function SLOPE caused a divide by zero error.");
744 }
745 return num / den;
746};
747
748
749/**
750 * Returns the normalized equivalent of a random variable given mean and standard deviation of the distribution.
751 * @param value - Value to be standardized.
752 * @param meanValue - Arithmetic mean of the distribution
753 * @param std - The standard deviation of the distribution or range.
754 * @returns {number}
755 * @constructor
756 */
757let STANDARDIZE = function (value, meanValue, std) {
758 ArgsChecker.checkLength(arguments, 3, "STANDARDIZE");
759 value = TypeConverter.firstValueAsNumber(value);
760 meanValue = TypeConverter.firstValueAsNumber(meanValue);
761 std = TypeConverter.firstValueAsNumber(std);
762 if (std <= 0) {
763 throw new NumError("Function STANDARDIZE parameter 3 value is " + std + ". It should be greater than 0.");
764 }
765 return (value - meanValue) / std;
766};
767
768
769/**
770 * Returns the Nth smallest value in the range, ignoring text values.
771 * @param range - Range or data-set to consider.
772 * @param n - N in 'Nth'.
773 * @constructor
774 */
775let SMALL = function (range, n) {
776 ArgsChecker.checkLength(arguments, 2, "SMALL");
777 let data = Filter.flattenAndThrow(range).filter(function (value) {
778 return typeof value != "string";
779 }).map(function (value) {
780 return TypeConverter.valueToNumber(value);
781 }).sort(function (a, b) {
782 return a - b;
783 });
784 if (n > data.length || n < 1) {
785 throw new NumError("Function SMALL parameter 2 value " + n + " is out of range.");
786 }
787 return data[n - 1];
788};
789
790
791/**
792 * Returns the Nth largest value in the range, ignoring text values.
793 * @param range - Range or data-set to consider.
794 * @param n - N in 'Nth'.
795 * @constructor
796 */
797let LARGE = function (range, n) {
798 ArgsChecker.checkLength(arguments, 2, "LARGE");
799 let data = Filter.flattenAndThrow(range).filter(function (value) {
800 return typeof value != "string";
801 }).map(function (value) {
802 return TypeConverter.valueToNumber(value);
803 }).sort(function (a, b) {
804 return b - a;
805 });
806 if (n > data.length || n < 1) {
807 throw new NumError("Function LARGE parameter 2 value " + n + " is out of range.");
808 }
809 return data[n - 1];
810};
811
812
813/**
814 * Returns the kurtosis of a data set or range. Ignores text values.
815 * @param values - data set or range to calculate. Must be at least 4 values.
816 * @returns {number}
817 * @constructor
818 */
819let KURT = function (...values) {
820 ArgsChecker.checkAtLeastLength(values, 4, "KURT");
821 let range = Filter.flattenAndThrow(values).filter(function (value) {
822 return typeof value !== "string";
823 }).map(function (value) {
824 return TypeConverter.valueToNumber(value);
825 });
826 if (range.length < 4) {
827 throw new DivZeroError("KURT requires more values in range. Expected: 4, found: " + range.length + ".");
828 }
829 let m = mean(range);
830 let n = range.length;
831 let sigma = 0;
832 for (let i = 0; i < n; i++) {
833 sigma += Math.pow(range[i] - m, 4);
834 }
835 sigma = sigma / Math.pow(stdev(range, true), 4);
836 return ((n * (n + 1)) / ((n - 1) * (n - 2) * (n - 3))) * sigma - 3 * (n - 1) * (n - 1) / ((n - 2) * (n - 3));
837};
838
839
840/**
841 * Calculates the y-value at which a line will intersect the y-axis by using known x-values and y-values. Any text
842 * values will be ignored.
843 * @param rangeY - Dependent range of values.
844 * @param rangeX - Independent range of values.
845 * @returns {number}
846 * @constructor
847 */
848let INTERCEPT = function (rangeY, rangeX) {
849 ArgsChecker.checkLength(arguments, 2, "INTERCEPT");
850 let dataX = Filter.flattenAndThrow(rangeX).filter(function (value) {
851 return typeof value !== "string";
852 }).map(function (value) {
853 return TypeConverter.valueToNumber(value);
854 });
855 let dataY = Filter.flattenAndThrow(rangeY).filter(function (value) {
856 return typeof value !== "string";
857 }).map(function (value) {
858 return TypeConverter.valueToNumber(value);
859 });
860
861 if (dataX.length !== dataY.length) {
862 throw new NAError("INTERCEPT has mismatched argument count " + dataX.length + " vs " + dataY.length + ".");
863 }
864
865 let xMean = mean(dataX);
866 let yMean = mean(dataY);
867 let n = dataX.length;
868 let num = 0;
869 let den = 0;
870 for (let i = 0; i < n; i++) {
871 num += (dataX[i] - xMean) * (dataY[i] - yMean);
872 den += Math.pow(dataX[i] - xMean, 2);
873 }
874 if (den === 0) {
875 throw new DivZeroError("Evaluation of function INTERCEPT caused a divide by zero error.");
876 }
877 let b = num / den;
878 return yMean - b * xMean;
879};
880
881
882/**
883 * Calculates the a future value using existing x-values and y-values. Any text values will be ignored.
884 * @param x - The data point for which you would like to predict the value.
885 * @param rangeY - Dependent range of values.
886 * @param rangeX - Independent range of values.
887 * @returns {number}
888 * @constructor
889 * TODO: This formula will fail to parse since the first argument is followed by an argument that is an array.
890 * TODO (continued) This is a known issue.
891 */
892let FORECAST = function (x, rangeY, rangeX) {
893 ArgsChecker.checkLength(arguments, 3, "FORECAST");
894 x = TypeConverter.firstValueAsNumber(x);
895 let dataX = Filter.flattenAndThrow(rangeX).filter(function (value) {
896 return typeof value !== "string";
897 }).map(function (value) {
898 return TypeConverter.valueToNumber(value);
899 });
900 let dataY = Filter.flattenAndThrow(rangeY).filter(function (value) {
901 return typeof value !== "string";
902 }).map(function (value) {
903 return TypeConverter.valueToNumber(value);
904 });
905
906 if (dataX.length !== dataY.length) {
907 throw new NAError("FORECAST has mismatched argument count " + dataX.length + " vs " + dataY.length + ".");
908 }
909
910 let xMean = mean(dataX);
911 let yMean = mean(dataY);
912 let n = dataX.length;
913 let num = 0;
914 let den = 0;
915 for (let i = 0; i < n; i++) {
916 num += (dataX[i] - xMean) * (dataY[i] - yMean);
917 den += Math.pow(dataX[i] - xMean, 2);
918 }
919 if (den === 0) {
920 throw new DivZeroError("Evaluation of function FORECAST caused a divide by zero error.");
921 }
922 let b = num / den;
923 let a = yMean - b * xMean;
924 return a + b * x;
925};
926
927
928/**
929 * Returns the Poisson distribution for the given number. Functions the same as POISSON.DIST.
930 * @param x - Number to use.
931 * @param meanValue - The middle value for the Poisson distribution.
932 * @param cumulative - [OPTIONAL] - 0 calculates the density function, 1 calculates the distribution. Defaults to 0.
933 * @returns {number}
934 * @constructor
935 */
936let POISSON = function (x, meanValue, cumulative?) {
937 ArgsChecker.checkLengthWithin(arguments, 2, 3, "POISSON");
938 x = TypeConverter.firstValueAsNumber(x);
939 meanValue = TypeConverter.firstValueAsNumber(meanValue);
940 cumulative = (cumulative === undefined) ? 0 : TypeConverter.firstValueAsNumber(cumulative);
941
942 if (x < 0) {
943 throw new NumError("Function POISSON parameter 1 value is " + x + ". It should be greater than or equal to 0.");
944 }
945 if (meanValue < 0) {
946 throw new NumError("Function POISSON parameter 2 value is " + x + ". It should be greater than or equal to 0.");
947 }
948
949 function factorial(n) {
950 return n < 0 ? NaN : gammafn(n + 1);
951 }
952 function poissonPDF(k, l) {
953 return Math.pow(l, k) * Math.exp(-l) / factorial(k);
954 }
955 function poissonCDF(x, l) {
956 let sumarr = [],
957 k = 0;
958 if (x < 0) return 0;
959 for (; k <= x; k++) {
960 sumarr.push(poissonPDF(k, l));
961 }
962 return sum(sumarr);
963 };
964
965 return (cumulative) ? poissonCDF(x, meanValue) : poissonPDF(x, meanValue);
966};
967
968
969/**
970 * Returns the percentage rank (percentile) of the given value in a sample. Functions the same as PERCENTRANK.INC.
971 * @param data - The array or range of data in the sample.
972 * @param x - The value.
973 * @param significance - [OPTIONAL] - The number of significant digits to use in the calculation. Defaults to 3.
974 * @returns {number}
975 * @constructor
976 */
977let PERCENTRANK = function (data, x, significance?) {
978 ArgsChecker.checkLengthWithin(arguments, 2, 3, "PERCENTRANK");
979 data = Filter.flattenAndThrow(data).map(TypeConverter.valueToNumber).sort(function (a, b) {
980 return a - b;
981 });
982 x = TypeConverter.firstValueAsNumber(x);
983 let uniques = Filter.unique(data);
984 let n = data.length;
985 let m = uniques.length;
986 if (x < uniques[0] || x > uniques[m - 1]) {
987 throw new NAError("PERCENTRANK does not have valid input data.");
988 }
989 if (m === 1 && uniques[0] === x) {
990 return 1;
991 }
992 significance = (typeof significance === 'undefined') ? 3 : TypeConverter.firstValueAsNumber(significance);
993 let power = Math.pow(10, significance);
994 let result = 0;
995 let match = false;
996 let i = 0;
997 while (!match && i < m) {
998 if (x === uniques[i]) {
999 result = data.indexOf(uniques[i]) / (n - 1);
1000 match = true;
1001 } else if (x >= uniques[i] && (x < uniques[i + 1] || i === m - 1)) {
1002 result = (data.indexOf(uniques[i]) + (x - uniques[i]) / (uniques[i + 1] - uniques[i])) / (n - 1);
1003 match = true;
1004 }
1005 i++;
1006 }
1007 let v = Math.floor(result * power) / power;
1008 if (isNaN(v)) {
1009 throw new NAError("PERCENTRANK does not have valid input data.");
1010 }
1011 return v;
1012};
1013
1014
1015/**
1016 * Returns the percentage rank (percentile) from 0 to 1 exclusive for a value in a sample.
1017 * @param data - The array or range of data in the sample.
1018 * @param x - The value
1019 * @param significance - [OPTIONAL] - The number of significant digits to use in the calculation. Defaults to 3.
1020 * @returns {number}
1021 * @constructor
1022 */
1023let PERCENTRANK$EXC = function (data, x, significance?) {
1024 ArgsChecker.checkLengthWithin(arguments, 2, 3, "PERCENTRANK.EXC");
1025 data = Filter.flattenAndThrow(data).map(TypeConverter.valueToNumber).sort(function (a, b) {
1026 return a - b;
1027 });
1028 x = TypeConverter.firstValueAsNumber(x);
1029 let uniques = Filter.unique(data);
1030 let n = data.length;
1031 let m = uniques.length;
1032 if (x < uniques[0] || x > uniques[m - 1]) {
1033 throw new NAError("PERCENTRANK.EXC does not have valid input data.");
1034 }
1035 if (m === 1 && uniques[0] === x) {
1036 return 1;
1037 }
1038 significance = (typeof significance === 'undefined') ? 3 : TypeConverter.firstValueAsNumber(significance);
1039 let power = Math.pow(10, significance);
1040 let result = 0;
1041 let match = false;
1042 let i = 0;
1043 while (!match && i < m) {
1044 if (x === uniques[i]) {
1045 result = (data.indexOf(uniques[i]) + 1) / (n + 1);
1046 match = true;
1047 } else if (x >= uniques[i] && (x < uniques[i + 1] || i === m - 1)) {
1048 result = (data.indexOf(uniques[i]) + 1 + (x - uniques[i]) / (uniques[i + 1] - uniques[i])) / (n + 1);
1049 match = true;
1050 }
1051 i++;
1052 }
1053 let v = Math.floor(result * power) / power;
1054 if (isNaN(v)) {
1055 throw new NAError("PERCENTRANK.EXC does not have valid input data.");
1056 }
1057 return v;
1058};
1059
1060
1061/**
1062 * Returns the inverse of the standard normal distribution for the given number.
1063 * @param probability - The probability value.
1064 * @returns {number}
1065 * @constructor
1066 */
1067let NORMSINV = function (probability) {
1068 ArgsChecker.checkLength(arguments, 1, "NORMSINV");
1069 probability = TypeConverter.firstValueAsNumber(probability);
1070 function erfc(x) {
1071 return 1 - erf(x);
1072 }
1073 function erfcinv(p) {
1074 let j = 0;
1075 let x, err, t, pp;
1076 if (p >= 2)
1077 return -100;
1078 if (p <= 0)
1079 return 100;
1080 pp = (p < 1) ? p : 2 - p;
1081 t = Math.sqrt(-2 * Math.log(pp / 2));
1082 x = -0.70711 * ((2.30753 + t * 0.27061) /
1083 (1 + t * (0.99229 + t * 0.04481)) - t);
1084 for (; j < 2; j++) {
1085 err = erfc(x) - pp;
1086 x += err / (1.12837916709551257 * Math.exp(-x * x) - x * err);
1087 }
1088 return (p < 1) ? x : -x;
1089 }
1090 function inv(p, mean, std) {
1091 return -1.41421356237309505 * std * erfcinv(2 * p) + mean;
1092 }
1093 if (probability <= 0 || probability >= 1) {
1094 throw new NumError("Function NORMSINV parameter 1 value is " + probability +
1095 ". Valid values are between 0 and 1 exclusive.");
1096 }
1097 return inv(probability, 0, 1);
1098};
1099
1100
1101function _cdf(x, mValue, stdVal) {
1102 return 0.5 * (1 + erf((x - mValue) / Math.sqrt(2 * stdVal * stdVal)));
1103}
1104
1105function _pdf(x, meanVal, std) {
1106 return Math.exp(-0.5 * Math.log(2 * Math.PI) -
1107 Math.log(std) - Math.pow(x - meanVal, 2) / (2 * std * std));
1108}
1109
1110/**
1111 * Returns the standard normal cumulative distribution for the given number.
1112 * @param z - Value to use in calculation.
1113 * @returns {number}
1114 * @constructor
1115 */
1116let NORMSDIST = function (z) {
1117 ArgsChecker.checkLength(arguments, 1, "NORMSDIST");
1118 z = TypeConverter.firstValueAsNumber(z);
1119 return _cdf(z, 0, 1);
1120};
1121
1122
1123/**
1124 * Returns the normal distribution for the given number in the distribution.
1125 * @param x - Value to use.
1126 * @param meanValue - The mean value of the distribution.
1127 * @param standDev - The standard deviation of the distribution.
1128 * @param cumulative - 0 calculates the density function, 1 calculates the distribution.
1129 * @returns {number}
1130 * @constructor
1131 */
1132let NORMDIST = function (x, meanValue, standDev, cumulative) {
1133 ArgsChecker.checkLength(arguments, 4, "NORMDIST");
1134 x = TypeConverter.firstValueAsNumber(x);
1135 meanValue = TypeConverter.firstValueAsNumber(meanValue);
1136 standDev = TypeConverter.firstValueAsNumber(standDev);
1137 cumulative = TypeConverter.firstValueAsNumber(cumulative);
1138 if (standDev <= 0) {
1139 throw new NumError("Function NORMDIST parameter 3 value should be greater than 0. It is " + standDev + ".");
1140 }
1141 return (cumulative === 0) ? _pdf(x, meanValue, standDev) : _cdf(x, meanValue, standDev);
1142};
1143
1144/**
1145 * Returns the inverse of the normal distribution for the given number in the distribution.
1146 * @param probability - Number in the distribution.
1147 * @param meanVal - The mean value in the normal distribution.
1148 * @param standDev - The standard deviation of the normal distribution.
1149 * @returns {number}
1150 * @constructor
1151 */
1152let NORMINV = function (probability, meanVal, standDev) {
1153 ArgsChecker.checkLength(arguments, 3, "NORMINV");
1154 function erf(x) {
1155 let cof = [-1.3026537197817094, 6.4196979235649026e-1, 1.9476473204185836e-2,
1156 -9.561514786808631e-3, -9.46595344482036e-4, 3.66839497852761e-4,
1157 4.2523324806907e-5, -2.0278578112534e-5, -1.624290004647e-6,
1158 1.303655835580e-6, 1.5626441722e-8, -8.5238095915e-8,
1159 6.529054439e-9, 5.059343495e-9, -9.91364156e-10,
1160 -2.27365122e-10, 9.6467911e-11, 2.394038e-12,
1161 -6.886027e-12, 8.94487e-13, 3.13092e-13,
1162 -1.12708e-13, 3.81e-16, 7.106e-15,
1163 -1.523e-15, -9.4e-17, 1.21e-16,
1164 -2.8e-17];
1165 let j = cof.length - 1;
1166 let isneg = false;
1167 let d = 0;
1168 let dd = 0;
1169 let t, ty, tmp, res;
1170
1171 if (x < 0) {
1172 x = -x;
1173 isneg = true;
1174 }
1175
1176 t = 2 / (2 + x);
1177 ty = 4 * t - 2;
1178
1179 for(; j > 0; j--) {
1180 tmp = d;
1181 d = ty * d - dd + cof[j];
1182 dd = tmp;
1183 }
1184
1185 res = t * Math.exp(-x * x + 0.5 * (cof[0] + ty * d) - dd);
1186 return isneg ? res - 1 : 1 - res;
1187 }
1188 function erfc(x) {
1189 return 1 - erf(x);
1190 }
1191 function erfcinv(p) {
1192 let j = 0;
1193 let x, err, t, pp;
1194 if (p >= 2)
1195 return -100;
1196 if (p <= 0)
1197 return 100;
1198 pp = (p < 1) ? p : 2 - p;
1199 t = Math.sqrt(-2 * Math.log(pp / 2));
1200 x = -0.70711 * ((2.30753 + t * 0.27061) /
1201 (1 + t * (0.99229 + t * 0.04481)) - t);
1202 for (; j < 2; j++) {
1203 err = erfc(x) - pp;
1204 x += err / (1.12837916709551257 * Math.exp(-x * x) - x * err);
1205 }
1206 return (p < 1) ? x : -x;
1207 }
1208 function inv(p, meanVal ,std) {
1209 return -1.41421356237309505 * std * erfcinv(2 * p) + meanVal;
1210 }
1211 probability = TypeConverter.firstValueAsNumber(probability);
1212 meanVal = TypeConverter.firstValueAsNumber(meanVal);
1213 standDev = TypeConverter.firstValueAsNumber(standDev);
1214 if (probability <= 0 || probability >= 1) {
1215 throw new NumError("Function NORMINV parameter 1 value is " + probability +
1216 ". Valid values are between 0 and 1 exclusive.");
1217 }
1218 if (standDev <= 0) {
1219 throw new NumError("Function NORMINV parameter 3 value is " + standDev + ". It should be greater than 0.");
1220 }
1221 return inv(probability, meanVal, standDev);
1222};
1223
1224
1225/**
1226 * Returns the negative binomial distribution.
1227 * @param k - The value returned for unsuccessful tests.
1228 * @param r - The value returned for successful tests.
1229 * @param p - The probability of the success of an attempt, between 0 and 1 inclusively.
1230 * @returns {number}
1231 * @constructor
1232 */
1233let NEGBINOMDIST = function (k, r, p) {
1234 ArgsChecker.checkLength(arguments, 3, "NEGBINOMDIST");
1235 function _gammaln(x) {
1236 let j = 0;
1237 let cof = [
1238 76.18009172947146, -86.50532032941677, 24.01409824083091,
1239 -1.231739572450155, 0.1208650973866179e-2, -0.5395239384953e-5
1240 ];
1241 let ser = 1.000000000190015;
1242 let xx, y, tmp;
1243 tmp = (y = xx = x) + 5.5;
1244 tmp -= (xx + 0.5) * Math.log(tmp);
1245 for (; j < 6; j++)
1246 ser += cof[j] / ++y;
1247 return Math.log(2.5066282746310005 * ser / xx) - tmp;
1248 }
1249 function _combinationln(n, m) {
1250 return _factorialln(n) - _factorialln(m) - _factorialln(n - m);
1251 }
1252 function _factorialln(n) {
1253 return n < 0 ? NaN : _gammaln(n + 1);
1254 }
1255 function _factorial(n) {
1256 return n < 0 ? NaN : gammafn(n + 1);
1257 }
1258 function _combination(n, m) {
1259 return (n > 170 || m > 170)
1260 ? Math.exp(_combinationln(n, m))
1261 : (_factorial(n) / _factorial(m)) / _factorial(n - m);
1262 }
1263 function _pdf(k, r, p) {
1264 return k !== (k | 0)
1265 ? 0
1266 : k < 0
1267 ? 0
1268 : _combination(k + r - 1, r - 1) * Math.pow(1 - p, k) * Math.pow(p, r);
1269 }
1270 k = TypeConverter.firstValueAsNumber(k);
1271 r = TypeConverter.firstValueAsNumber(r);
1272 p = TypeConverter.firstValueAsNumber(p);
1273 if (k < 1) {
1274 throw new NumError("Function NEGBINOMDIST parameter 1 value is " + k + ". Should be greater than 0.");
1275 }
1276 if (r < 1) {
1277 throw new NumError("Function NEGBINOMDIST parameter 2 value is " + r + ". Should be greater than 0.");
1278 }
1279 if (p < 0 || p > 1) {
1280 throw new NumError("Function NEGBINOMDIST parameter 3 value is " + p +
1281 ". Valid values are between 0 and 1 inclusive.");
1282 }
1283 return _pdf(k, r, p);
1284};
1285
1286
1287/**
1288 * Returns the geometric mean of a sample.
1289 * @param values - The numerical arguments or ranges that represent a random sample.
1290 * @returns {number}
1291 * @constructor
1292 */
1293let GEOMEAN = function (...values) {
1294 ArgsChecker.checkAtLeastLength(arguments, 1, "GEOMEAN");
1295 function _product(arr) {
1296 let prod = 1;
1297 let i = arr.length;
1298 while (--i >= 0) {
1299 prod *= arr[i];
1300 }
1301 return prod;
1302 }
1303 values = Filter.flattenAndThrow(values).map(TypeConverter.valueToNumber).map(function (value) {
1304 if (value <=0) {
1305 throw new NumError("GEOMEAN requires inputs greater than 0, but one of the values entered is " + value + ".");
1306 }
1307 return value;
1308 });
1309 return Math.pow(_product(values), 1 / values.length);
1310};
1311
1312
1313/**
1314 * Returns the harmonic mean of a data set.
1315 * @param values - The numerical arguments or ranges that represent a sample.
1316 * @returns {number}
1317 * @constructor
1318 */
1319let HARMEAN = function (...values) {
1320 ArgsChecker.checkAtLeastLength(arguments, 1, "HARMEAN");
1321 let range = Filter.flattenAndThrow(values).map(TypeConverter.valueToNumber).map(function (value) {
1322 if (value <=0) {
1323 throw new NumError("HARMEAN requires inputs greater than 0, but one of the values entered is " + value + ".");
1324 }
1325 return value;
1326 });
1327 let n = range.length;
1328 let den = 0;
1329 for (let i = 0; i < n; i++) {
1330 den += 1 / range[i];
1331 }
1332 return n / den;
1333};
1334
1335
1336/**
1337 * Returns the (1-alpha) confidence interval for a normal distribution.
1338 * @param alpha - The level of the confidence interval
1339 * @param standDev - The standard deviation for the total population
1340 * @param size - The size of the population.
1341 * @returns {number}
1342 * @constructor
1343 */
1344let CONFIDENCE = function (alpha, standDev, size) {
1345 ArgsChecker.checkLength(arguments, 3, "CONFIDENCE");
1346 alpha = TypeConverter.firstValueAsNumber(alpha);
1347 standDev = TypeConverter.firstValueAsNumber(standDev);
1348 size = TypeConverter.firstValueAsNumber(size);
1349 if (alpha <= 0 || alpha >= 1) {
1350 throw new NumError("Function CONFIDENCE parameter 1 value is " + alpha
1351 + ". Valid values are between 0 and 1 exclusively.");
1352 }
1353 if (standDev <= 0) {
1354 throw new NumError("Function CONFIDENCE parameter 2 value is " + standDev + ". It should be greater than 0.");
1355 }
1356 if (size <= 0) {
1357 throw new NumError("Function CONFIDENCE parameter 3 value is " + size +". It should be at least 1.");
1358 }
1359 function _erfc(x) {
1360 return 1 - erf(x);
1361 }
1362 function _erfcinv(p) {
1363 let j = 0;
1364 let x, err, t, pp;
1365 if (p >= 2)
1366 return -100;
1367 if (p <= 0)
1368 return 100;
1369 pp = (p < 1) ? p : 2 - p;
1370 t = Math.sqrt(-2 * Math.log(pp / 2));
1371 x = -0.70711 * ((2.30753 + t * 0.27061) /
1372 (1 + t * (0.99229 + t * 0.04481)) - t);
1373 for (; j < 2; j++) {
1374 err = _erfc(x) - pp;
1375 x += err / (1.12837916709551257 * Math.exp(-x * x) - x * err);
1376 }
1377 return (p < 1) ? x : -x;
1378 }
1379 function _normalInv(p, m, std) {
1380 return -1.41421356237309505 * std * _erfcinv(2 * p) + m;
1381 }
1382 function _sumsqerr(arr) {
1383 let m = mean(arr);
1384 let sum = 0;
1385 let i = arr.length;
1386 let tmp;
1387 while (--i >= 0) {
1388 tmp = arr[i] - m;
1389 sum += tmp * tmp;
1390 }
1391 return sum;
1392 }
1393 function _variance(arr, flag?) {
1394 return _sumsqerr(arr) / (arr.length - (flag ? 1 : 0));
1395 }
1396 function _normalci(...values) {
1397 let ans = new Array(2);
1398 let change;
1399 if (values.length === 4) {
1400 change = Math.abs(_normalInv(values[1] / 2, 0, 1) *
1401 values[2] / Math.sqrt(values[3]));
1402 } else {
1403 change = Math.abs(_normalInv(values[1] / 2, 0, 1) *
1404 Math.sqrt(_variance(arguments[2])) / Math.sqrt(values[2].length));
1405 }
1406 ans[0] = values[0] - change;
1407 ans[1] = values[0] + change;
1408 return ans;
1409 }
1410 return _normalci(1, alpha, standDev, size)[1] - 1;
1411};
1412
1413
1414/**
1415 * Returns the individual term binomial distribution probability.
1416 * @param successes - The number of successes in a set of trials.
1417 * @param trials - The number of independent trials.
1418 * @param probability - The probability of success on each trial.
1419 * @param cumulative - 0 calculates the probability of a single event, 1 calculates the cumulative probability.
1420 * @returns {number}
1421 * @constructor
1422 */
1423let BINOMDIST = function (successes, trials, probability, cumulative) {
1424 ArgsChecker.checkLength(arguments, 4, "BINOMDIST");
1425 successes = TypeConverter.firstValueAsNumber(successes);
1426 trials = TypeConverter.firstValueAsNumber(trials);
1427 probability = TypeConverter.firstValueAsNumber(probability);
1428 cumulative = TypeConverter.firstValueAsNumber(cumulative);
1429 function _binomialCDF(x, n, p) {
1430 let binomarr = [],
1431 k = 0;
1432 if (x < 0) {
1433 return 0;
1434 }
1435 if (x < n) {
1436 for (; k <= x; k++) {
1437 binomarr[ k ] = _binomialPDF(k, n, p);
1438 }
1439 return sum(binomarr);
1440 }
1441 return 1;
1442 }
1443 function _combination(n, m) {
1444 // make sure n or m don't exceed the upper limit of usable values
1445 return (n > 170 || m > 170)
1446 ? Math.exp(_combinationln(n, m))
1447 : (_factorial(n) / _factorial(m)) / _factorial(n - m);
1448 }
1449 function _factorial(n) {
1450 return n < 0 ? NaN : gammafn(n + 1);
1451 }
1452 function _factorialln(n) {
1453 return n < 0 ? NaN : gammaln(n + 1);
1454 }
1455 function _combinationln(n, m) {
1456 return _factorialln(n) - _factorialln(m) - _factorialln(n - m);
1457 }
1458 function _binomialPDF(k, n, p) {
1459 return (p === 0 || p === 1) ?
1460 ((n * p) === k ? 1 : 0) :
1461 _combination(n, k) * Math.pow(p, k) * Math.pow(1 - p, n - k);
1462 }
1463 if (trials < 0) {
1464 throw new NumError("Function BINOMDIST parameter 2 value is " + trials + ", but should be greater than 0.");
1465 }
1466 if (trials < successes) {
1467 throw new NumError("Function BINOMDIST parameter 1 value is " + trials
1468 + ". It should be less than or equal to value of Function BINOMDIST parameter 2 with " + successes + ".");
1469 }
1470 if (probability > 1 || probability < 0) {
1471 throw new NumError("Function BINOMDIST parameter 3 value is " + probability
1472 + ", but should be between 0 and 1 inclusive.");
1473 }
1474 return (cumulative) ? _binomialCDF(successes, trials, probability) : _binomialPDF(successes, trials, probability);
1475};
1476
1477
1478/**
1479 * Returns the covariance of the product of paired deviations.
1480 * @param dataY - The first range of data.
1481 * @param dataX - The second range of data.
1482 * @returns {number}
1483 * @constructor
1484 */
1485let COVAR = function (dataY, dataX) {
1486 ArgsChecker.checkLength(arguments, 2, "COVAR");
1487 dataY = Filter.flattenAndThrow(dataY).map(TypeConverter.valueToNumber);
1488 dataX = Filter.flattenAndThrow(dataX).map(TypeConverter.valueToNumber);
1489 if (dataX.length !== dataY.length) {
1490 throw new NAError("COlet has mismatched argument count " + dataY.length + " vs " + dataX.length + ".");
1491 }
1492 let mean1 = mean(dataY);
1493 let mean2 = mean(dataX);
1494 let result = 0;
1495 let n = dataY.length;
1496 for (let i = 0; i < n; i++) {
1497 result += (dataY[i] - mean1) * (dataX[i] - mean2);
1498 }
1499 return result / n;
1500};
1501
1502
1503/**
1504 * Returns the values of the Weibull distribution for the given number.
1505 * @param x - Number to use in calculation.
1506 * @param shape - The Alpha parameter of the Weibull distribution. Should be greater than 0.
1507 * @param scale - The Beta parameter of the Weibull distribution. Should be greater than 0.
1508 * @param cumulative - Indicates the type of function: If 0 the form of the function is calculated, if 1 then the
1509 * distribution is calculated.
1510 * @returns {number}
1511 * @constructor
1512 */
1513let WEIBULL = function (x, shape, scale, cumulative) {
1514 ArgsChecker.checkLength(arguments, 4, "WEIBULL");
1515 x = TypeConverter.firstValueAsNumber(x);
1516 if (x < 0) {
1517 throw new NumError("Function WEIBULL parameter 1 value is " + x + ", but should be greater than or equal to 0.");
1518 }
1519 shape = TypeConverter.firstValueAsNumber(shape);
1520 if (shape <= 0) {
1521 throw new NumError("Function WEIBULL parameter 2 value is " + shape + ", but should be greater than 0.");
1522 }
1523 scale = TypeConverter.firstValueAsNumber(scale);
1524 if (scale <= 0) {
1525 throw new NumError("Function WEIBULL parameter 2 value is " + scale + ", but should be greater than 0.");
1526 }
1527 cumulative = TypeConverter.firstValueAsNumber(cumulative);
1528 return (cumulative) ? 1 - Math.exp(-Math.pow(x / scale, shape)) : Math.pow(x, shape - 1)
1529 * Math.exp(-Math.pow(x / scale, shape)) * shape / Math.pow(scale, shape);
1530};
1531
1532
1533/**
1534 * Estimate the variance based on the entire population. Text will be converted to numbers, if possible.
1535 * @param values - Values of population.
1536 * @returns {number}
1537 * @constructor
1538 */
1539let VARPA = function (...values) {
1540 ArgsChecker.checkAtLeastLength(arguments, 1, "VARPA");
1541 let range = Filter.flattenAndThrow(values).map(TypeConverter.valueToNumber);
1542 let n = range.length;
1543 if (n < 2) {
1544 throw new DivZeroError("Evaluation of function VARP caused a divide by zero error.");
1545 }
1546 let sigma = 0;
1547 let count = 0;
1548 let mean = AVERAGEA(range);
1549 for (let i = 0; i < n; i++) {
1550 let el = range[i];
1551 if (typeof el === 'number') {
1552 sigma += Math.pow(el - mean, 2);
1553 } else if (el === true) {
1554 sigma += Math.pow(1 - mean, 2);
1555 } else {
1556 sigma += Math.pow(0 - mean, 2);
1557 }
1558
1559 if (el !== null) {
1560 count++;
1561 }
1562 }
1563 return sigma / count;
1564};
1565
1566
1567/**
1568 * Estimate the variance based on the entire population.
1569 * @param values - Values of entire population.
1570 * @returns {number}
1571 * @constructor
1572 */
1573let VARP = function (...values) {
1574 ArgsChecker.checkAtLeastLength(arguments, 1, "VARP");
1575 let range = Filter.flattenAndThrow(values).map(TypeConverter.valueToNumber);
1576 let n = range.length;
1577 if (n < 2) {
1578 throw new DivZeroError("Evaluation of function VARP caused a divide by zero error.");
1579 }
1580 let sigma = 0;
1581 let count = 0;
1582 let mean = AVERAGE(range);
1583 for (let i = 0; i < n; i++) {
1584 sigma += Math.pow(range[i] - mean, 2);
1585 count++;
1586 }
1587 return sigma / count;
1588};
1589
1590
1591/**
1592 * Estimate the variance based on a sample.
1593 * @param values
1594 * @returns {number}
1595 * @constructor
1596 */
1597let VARA = function (...values) {
1598 ArgsChecker.checkAtLeastLength(arguments, 1, "VARA");
1599 let range = Filter.flattenAndThrow(values).map(TypeConverter.valueToNumber);
1600 let n = range.length;
1601 if (n < 2) {
1602 throw new DivZeroError("Evaluation of function VARA caused a divide by zero error.");
1603 }
1604 let sigma = 0;
1605 let count = 0;
1606 let mean = AVERAGEA(range);
1607 for (let i = 0; i < n; i++) {
1608 let el = range[i];
1609 if (typeof el === 'number') {
1610 sigma += Math.pow(el - mean, 2);
1611 } else if (el === true) {
1612 sigma += Math.pow(1 - mean, 2);
1613 } else {
1614 sigma += Math.pow(0 - mean, 2);
1615 }
1616
1617 if (el !== null) {
1618 count++;
1619 }
1620 }
1621 return sigma / (count - 1);
1622};
1623
1624
1625/**
1626 * Estimate the variance based on a sample.
1627 * @param values - Values in sample.
1628 * @constructor
1629 */
1630let VAR = function (...values) {
1631 ArgsChecker.checkAtLeastLength(arguments, 1, "VAR");
1632 let range = Filter.flattenAndThrow(values).map(TypeConverter.valueToNumber);
1633 let n = range.length;
1634 if (n < 2) {
1635 throw new DivZeroError("Evaluation of function let caused a divide by zero error.");
1636 }
1637 let sigma = 0;
1638 let count = 0;
1639 let mean = AVERAGE(range);
1640 for (let i = 0; i < n; i++) {
1641 sigma += Math.pow(range[i] - mean, 2);
1642 count++;
1643 }
1644 return sigma / (count - 1);
1645};
1646
1647
1648/**
1649 * Returns the number of permutations for a given number of objects.
1650 * @param total - The total number of objects
1651 * @param objects - The number of objects in each permutation.
1652 * @returns {number}
1653 * @constructor
1654 */
1655let PERMUT = function (total, objects) {
1656 ArgsChecker.checkLength(arguments, 2, "PERMUT");
1657 total = TypeConverter.firstValueAsNumber(total);
1658 objects = TypeConverter.firstValueAsNumber(objects);
1659 if (total < objects) {
1660 throw new NumError("Function PERMUT parameter 2 value is " + objects +
1661 ", should be less than or equal to value of Function PERMUT parameter 1 of " + objects + ".");
1662 }
1663 let memoizeFact = [];
1664 function _fact(value) {
1665 let n = Math.floor(value);
1666 if (n === 0 || n === 1) {
1667 return 1;
1668 } else if (memoizeFact[n] > 0) {
1669 return memoizeFact[n];
1670 } else {
1671 memoizeFact[n] = _fact(n - 1) * n;
1672 return memoizeFact[n];
1673 }
1674 }
1675 return _fact(total) / _fact(total - objects);
1676};
1677
1678
1679/**
1680 * Returns the square of the Pearson correlation coefficient based on the given values.
1681 * @param rangeY - An array or range of data points.
1682 * @param rangeX - An array or range of data points.
1683 * @returns {number}
1684 * @constructor
1685 */
1686let RSQ = function (rangeY, rangeX) {
1687 ArgsChecker.checkLength(arguments, 2, "RSQ");
1688 if (!Array.isArray(rangeY)) {
1689 rangeY = [rangeY];
1690 }
1691 if (!Array.isArray(rangeX)) {
1692 rangeX = [rangeX];
1693 }
1694 let dataX = Filter.flattenAndThrow(rangeX).map(TypeConverter.valueToNumber);
1695 let dataY = Filter.flattenAndThrow(rangeY).map(TypeConverter.valueToNumber);
1696 if (dataX.length !== dataY.length) {
1697 throw new NAError("SLOPE has mismatched argument count " + dataX.length + " vs " + dataY.length + ".");
1698 }
1699 if (dataY.length === 1 && dataX.length === 1) {
1700 throw new DivZeroError("Evaluation of function RSQ caused a divide by zero error.");
1701 }
1702 return Math.pow(PEARSON(dataX, dataY), 2);
1703};
1704
1705
1706/**
1707 * Returns the skewness of a distribution.
1708 * @param values - The numerical values or range.
1709 * @returns {number}
1710 * @constructor
1711 */
1712let SKEW = function (...values) {
1713 ArgsChecker.checkAtLeastLength(arguments, 1, "SKEW");
1714 let range = Filter.flattenAndThrow(values).map(TypeConverter.valueToNumber);
1715 let n = range.length;
1716 if (n < 3) {
1717 throw new DivZeroError("SKEW requires at least 3 data points.");
1718 }
1719 let meanValue = mean(range);
1720 let sigma = 0;
1721 for (let i = 0; i < n; i++) {
1722 sigma += Math.pow(range[i] - meanValue, 3);
1723 }
1724 let d = ((n - 1) * (n - 2) * Math.pow(stdev(range, true), 3));
1725 if (d === 0) {
1726 throw new DivZeroError("Evaluation of function SKEW caused a divide by zero error.");
1727 }
1728 return n * sigma / d;
1729};
1730
1731
1732/**
1733 * Returns the standard error of the predicted y value for each x in the regression. Text values will be ignored.
1734 * @param rangeY - An array or range of data points.
1735 * @param rangeX - An array or range of data points.
1736 * @returns {number}
1737 * @constructor
1738 */
1739let STEYX = function (rangeY, rangeX) {
1740 ArgsChecker.checkLength(arguments, 2, "STEYX");
1741 if (!Array.isArray(rangeY)) {
1742 rangeY = [rangeY];
1743 }
1744 if (!Array.isArray(rangeX)) {
1745 rangeX = [rangeX];
1746 }
1747 let dataX = Filter.flattenAndThrow(rangeX).filter(function (value) {
1748 return typeof value !== "string";
1749 }).map(TypeConverter.valueToNumber);
1750 let dataY = Filter.flattenAndThrow(rangeY).filter(function (value) {
1751 return typeof value !== "string";
1752 }).map(TypeConverter.valueToNumber);
1753 if (dataX.length !== dataY.length) {
1754 throw new NAError("STEYX has mismatched argument count " + dataX.length + " vs " + dataY.length + ".");
1755 }
1756 if (dataY.length === 2 && dataX.length === 2) {
1757 throw new DivZeroError("Evaluation of function STEYX caused a divide by zero error.");
1758 }
1759 let xmean = mean(dataX);
1760 let ymean = mean(dataY);
1761 let n = dataX.length;
1762 let lft = 0;
1763 let num = 0;
1764 let den = 0;
1765 for (let i = 0; i < n; i++) {
1766 lft += Math.pow(dataY[i] - ymean, 2);
1767 num += (dataX[i] - xmean) * (dataY[i] - ymean);
1768 den += Math.pow(dataX[i] - xmean, 2);
1769 }
1770 return Math.sqrt((lft - num * num / den) / (n - 2));
1771};
1772
1773
1774/**
1775 * Returns the probability that values in a range are between two limits. Data is the array or range of data in the
1776 * sample.
1777 * @param range - The array or range of data in the sample.
1778 * @param probability - The array or range of the corresponding probabilities
1779 * @param start - The start value of the interval whose probabilities are to be summed.
1780 * @param end - [OPTIONAL] - The end value of the interval whose probabilities are to be summed. If this parameter is
1781 * missing, the probability for the start value is calculated
1782 * @returns {number}
1783 * @constructor
1784 */
1785let PROB = function (range, probability, start, end?) {
1786 ArgsChecker.checkLengthWithin(arguments, 3, 4, "PROB");
1787 range = Filter.flattenAndThrow(range);
1788 probability = Filter.flattenAndThrow(probability);
1789 if (range.length !== probability.length) {
1790 throw new NAError("PROB has mismatched argument count " + range.length + " vs " + probability.length + ".");
1791 }
1792 let sum = SUM(probability);
1793 if (sum <=0 || sum > 1) {
1794 throw new ValueError("Function PROB parameter 2 should sum to 1, but sums to " + sum + ".");
1795 }
1796 start = TypeConverter.firstValueAsNumber(start);
1797 end = (end === undefined) ? start : TypeConverter.firstValueAsNumber(end);
1798 if (start === end) {
1799 return (range.indexOf(start) >= 0) ? probability[range.indexOf(start)] : 0;
1800 }
1801 let sorted = range.sort(function (a, b) {
1802 return a - b;
1803 });
1804 let n = sorted.length;
1805 let result = 0;
1806 for (let i = 0; i < n; i++) {
1807 if (sorted[i] >= start && sorted[i] <= end) {
1808 result += probability[range.indexOf(sorted[i])];
1809 }
1810 }
1811 return result;
1812};
1813
1814
1815/**
1816 * Returns the most commonly occurring value in a range.
1817 * @param values - Range(s) or values to consider.
1818 * @returns {number}
1819 * @constructor
1820 */
1821let MODE = function (...values) {
1822 ArgsChecker.checkAtLeastLength(arguments, 1, "MODE");
1823 let range = Filter.flattenAndThrow(values).map(TypeConverter.valueToNumber);
1824 let n = range.length;
1825 let count = {};
1826 let maxItems = [];
1827 let max = 0;
1828 let currentItem;
1829 for (let i = 0; i < n; i++) {
1830 currentItem = range[i];
1831 count[currentItem] = count[currentItem] ? count[currentItem] + 1 : 1;
1832 if (count[currentItem] > max) {
1833 max = count[currentItem];
1834 maxItems = [];
1835 }
1836 if (count[currentItem] === max) {
1837 maxItems[maxItems.length] = currentItem;
1838 }
1839 }
1840 if (max === 1 && range.length !== 1) {
1841 throw new NAError("MODE cannot produce a result because no values occur more than once.");
1842 }
1843 return maxItems[0];
1844};
1845
1846
1847/**
1848 * Returns the position of a given entry in the entire list, measured either from top to bottom or bottom to top.
1849 * @param value - Value to find the rank of.
1850 * @param data - Values or range of the data-set.
1851 * @param isAscending - [OPTIONAL] The type of rank: 0 to rank from the highest, 1 to rank from the lowest. Defaults to
1852 * 0.
1853 * @returns {number}
1854 * @constructor
1855 */
1856let RANK = function (value, data, isAscending?) {
1857 ArgsChecker.checkLengthWithin(arguments, 2, 3, "RANK");
1858 value = TypeConverter.firstValueAsNumber(value);
1859 let range = Filter.flattenAndThrow(data).map(TypeConverter.valueToNumber);
1860 isAscending = (typeof isAscending === 'undefined') ? false : isAscending;
1861 let sort = (isAscending) ? function (a, b) {
1862 return a - b;
1863 } : function (a, b) {
1864 return b - a;
1865 };
1866 range = range.sort(sort);
1867 let rangeIndex = range.indexOf(value);
1868 if (rangeIndex === -1) {
1869 throw new NAError("RANK can't produce a result because parameter 1 is not in the dataset.");
1870 }
1871 return range.indexOf(value) + 1;
1872};
1873
1874
1875/**
1876 * Returns the position of a given entry in the entire list, measured either from top to bottom or bottom to top. If
1877 * more than one value exists in the same data-set, the average range of the values will be returned.
1878 * @param value - Value to find the rank of.
1879 * @param data - Values or range of the data-set.
1880 * @param isAscending - [OPTIONAL] The type of rank: 0 to rank from the highest, 1 to rank from the lowest. Defaults to
1881 * 0.
1882 * @returns {number}
1883 * @constructor
1884 */
1885let RANK$AVG = function (value, data, isAscending?) {
1886 ArgsChecker.checkLengthWithin(arguments, 2, 3, "RANK.AVG");
1887 value = TypeConverter.firstValueAsNumber(value);
1888 let range = Filter.flattenAndThrow(data).map(TypeConverter.valueToNumber)
1889
1890 function _countIn(range, value) {
1891 let result = 0;
1892 for (let i = 0; i < range.length; i++) {
1893 if (range[i] === value) {
1894 result++;
1895 }
1896 }
1897 return result;
1898 }
1899
1900 isAscending = (typeof isAscending === 'undefined') ? false : isAscending;
1901 let sort = (isAscending) ? function (a, b) {
1902 return a - b;
1903 } : function (a, b) {
1904 return b - a;
1905 };
1906 range = range.sort(sort);
1907 let rangeIndex = range.indexOf(value);
1908 if (rangeIndex === -1) {
1909 throw new NAError("RANK.AVG can't produce a result because parameter 1 is not in the dataset.");
1910 }
1911 let count = _countIn(range, value);
1912 return (count > 1) ? (2 * rangeIndex + count + 1) / 2 : rangeIndex + 1;
1913};
1914
1915
1916/**
1917 * Returns the position of a given entry in the entire list, measured either from top to bottom or bottom to top. If
1918 * there is more than one entry of the same value in the dataset, the top rank of the entries will be returned.
1919 * @param value - Value to find the rank of.
1920 * @param data - Values or range of the data-set.
1921 * @param isAscending - [OPTIONAL] The type of rank: 0 to rank from the highest, 1 to rank from the lowest. Defaults to
1922 * 0.
1923 * @returns {number}
1924 * @constructor
1925 */
1926let RANK$EQ = function (value, data, isAscending?) {
1927 ArgsChecker.checkLengthWithin(arguments, 2, 3, "RANK.EQ");
1928 value = TypeConverter.firstValueAsNumber(value);
1929 let range = Filter.flattenAndThrow(data).map(TypeConverter.valueToNumber);
1930 isAscending = (typeof isAscending === 'undefined') ? false : isAscending;
1931 let sort = (isAscending) ? function (a, b) {
1932 return a - b;
1933 } : function (a, b) {
1934 return b - a;
1935 };
1936 range = range.sort(sort);
1937 let rangeIndex = range.indexOf(value);
1938 if (rangeIndex === -1) {
1939 throw new NAError("RANK.EQ can't produce a result because parameter 1 is not in the dataset.");
1940 }
1941 return range.indexOf(value) + 1;
1942};
1943
1944/**
1945 * Returns the cumulative lognormal distribution for the given number.
1946 * @param x - The probability value.
1947 * @param meanValue - The mean value of the standard logarithmic distribution.
1948 * @param standardDev - The standard deviation of the standard logarithmic distribution.
1949 * @returns {number}
1950 * @constructor
1951 */
1952let LOGNORMDIST = function (x, meanValue, standardDev) {
1953 ArgsChecker.checkLength(arguments, 3, "LOGNORMDIST");
1954 x = TypeConverter.firstValueAsNumber(x);
1955 meanValue = TypeConverter.firstValueAsNumber(meanValue);
1956 standardDev = TypeConverter.firstValueAsNumber(standardDev);
1957 if (x <= 0) {
1958 throw new NumError("Function LOGNORMDIST parameter 1 value is " + x + ", but should be greater than 0.");
1959 }
1960 if (standardDev <= 0) {
1961 throw new NumError("Function LOGNORMDIST parameter 3 value is " + standardDev + ", but should be greater than 0.");
1962 }
1963 let a = (Math.log(x) - meanValue)/Math.sqrt(2 * standardDev * standardDev);
1964 return 0.5 + 0.5 * erf(a);
1965};
1966
1967
1968/**
1969 * Returns the t-distribution for the given number.
1970 * @param x - Value to use in calculation.
1971 * @param degreesOfFreedom - The number of degrees of freedom for the t-distribution.
1972 * @param tails - 1 returns the one-tailed test, 2 returns the two-tailed test.
1973 * @returns {number}
1974 * @constructor
1975 */
1976let TDIST = function (x, degreesOfFreedom, tails) {
1977 ArgsChecker.checkLength(arguments, 3, "TDIST");
1978 x = TypeConverter.firstValueAsNumber(x);
1979 degreesOfFreedom = TypeConverter.firstValueAsNumber(degreesOfFreedom);
1980 tails = TypeConverter.firstValueAsNumber(tails);
1981 if (tails < 1 || tails > 2) {
1982 throw new NumError("Function TDIST parameter 3 value is " + tails +
1983 ", but valid values are between 1 and 2, inclusively.");
1984 }
1985 if (degreesOfFreedom < 1) {
1986 throw new NumError("Function TDIST parameter 2 value is " + degreesOfFreedom +
1987 ", but it should be greater than or equal to 1.");
1988 }
1989 if (x < 0) {
1990 throw new NumError("Function TDIST parameter 1 value is " + x + ", but it should be greater than or equal to 0.");
1991 }
1992 function _betacf(x, a, b) {
1993 let fpmin = 1e-30;
1994 let m = 1;
1995 let qab = a + b;
1996 let qap = a + 1;
1997 let qam = a - 1;
1998 let c = 1;
1999 let d = 1 - qab * x / qap;
2000 let m2, aa, del, h;
2001
2002 if (Math.abs(d) < fpmin)
2003 d = fpmin;
2004 d = 1 / d;
2005 h = d;
2006
2007 for (; m <= 100; m++) {
2008 m2 = 2 * m;
2009 aa = m * (b - m) * x / ((qam + m2) * (a + m2));
2010 d = 1 + aa * d;
2011 if (Math.abs(d) < fpmin)
2012 d = fpmin;
2013 c = 1 + aa / c;
2014 if (Math.abs(c) < fpmin)
2015 c = fpmin;
2016 d = 1 / d;
2017 h *= d * c;
2018 aa = -(a + m) * (qab + m) * x / ((a + m2) * (qap + m2));
2019 d = 1 + aa * d;
2020 if (Math.abs(d) < fpmin)
2021 d = fpmin;
2022 c = 1 + aa / c;
2023 if (Math.abs(c) < fpmin)
2024 c = fpmin;
2025 d = 1 / d;
2026 del = d * c;
2027 h *= del;
2028 if (Math.abs(del - 1.0) < 3e-7)
2029 break;
2030 }
2031
2032 return h;
2033 }
2034 function _ibeta(x, a, b) {
2035 let bt = (x === 0 || x === 1) ? 0 :
2036 Math.exp(gammaln(a + b) - gammaln(a) -
2037 gammaln(b) + a * Math.log(x) + b *
2038 Math.log(1 - x));
2039 if (x < 0 || x > 1)
2040 return 0;
2041 if (x < (a + 1) / (a + b + 2))
2042 return bt * _betacf(x, a, b) / a;
2043 return 1 - bt * _betacf(1 - x, b, a) / b;
2044 }
2045 function _studenttCDF(x, dof) {
2046 let dof2 = dof / 2;
2047 return _ibeta((x + Math.sqrt(x * x + dof)) /
2048 (2 * Math.sqrt(x * x + dof)), dof2, dof2);
2049 }
2050 return tails * (1 - _studenttCDF(x, degreesOfFreedom));
2051};
2052
2053/**
2054 * Returns the hypergeometric distribution. X is the number of results achieved in the random sample.
2055 * @param numberOfSuccesses - The number of results achieved in the random sample.
2056 * @param numberOfDraws - The size of the random sample.
2057 * @param successesInPop - The number of possible results in the total population.
2058 * @param populationSize - The size of the total population.
2059 * @returns {number}
2060 * @constructor
2061 */
2062let HYPGEOMDIST = function (numberOfSuccesses, numberOfDraws, successesInPop, populationSize) {
2063 ArgsChecker.checkLength(arguments, 4, "HYPGEOMDIST");
2064 numberOfSuccesses = TypeConverter.firstValueAsNumber(numberOfSuccesses);
2065 numberOfDraws = TypeConverter.firstValueAsNumber(numberOfDraws);
2066 if (numberOfSuccesses > numberOfDraws) {
2067 throw new NumError("HYPGEOMDIST parameter 1 value is " + numberOfSuccesses
2068 + ", but should be less than or equal to parameter 2 with " + numberOfDraws + ".");
2069 }
2070 if (numberOfSuccesses < 0) {
2071 throw new NumError("HYPGEOMDIST parameter 1 value is " + numberOfSuccesses
2072 + ", but should be greater than or equal to 0.");
2073 }
2074 if (numberOfSuccesses < (numberOfDraws + successesInPop - populationSize)) {
2075 throw new NumError("HYPGEOMDIST parameter 1 value is " + numberOfSuccesses
2076 + ", but should be greater than or equal to " + (numberOfDraws + successesInPop - populationSize) + ".");
2077 }
2078 successesInPop = TypeConverter.firstValueAsNumber(successesInPop);
2079 populationSize = TypeConverter.firstValueAsNumber(populationSize);
2080 return COMBIN(successesInPop, numberOfSuccesses) *
2081 COMBIN(populationSize - successesInPop, numberOfDraws - numberOfSuccesses) /
2082 COMBIN(populationSize, numberOfDraws);
2083};
2084
2085/**
2086 * Returns the two-tailed P value of a z test with standard distribution.
2087 * @param range - Te array of the data.
2088 * @param value - The value to be tested.
2089 * @param stdDev - [OPTIONAL] The standard deviation of the total population. If this argument is missing, the standard
2090 * deviation of the sample is processed.
2091 * @returns {number}
2092 * @constructor
2093 */
2094let ZTEST = function (range, value, stdDev?) {
2095 ArgsChecker.checkLengthWithin(arguments, 2, 3, "ZTEST");
2096 range = Filter.flattenAndThrow(range);
2097 value = TypeConverter.firstValueAsNumber(value);
2098 let sd = isUndefined(stdDev) ? STDEV(range) : TypeConverter.firstValueAsNumber(stdDev);
2099 return 1 - NORMSDIST((AVERAGE(range) - value) / (sd / Math.sqrt(range.length)));
2100};
2101
2102
2103export {
2104 AVERAGE,
2105 AVERAGEA,
2106 AVERAGEIF,
2107 AVEDEV,
2108 CORREL,
2109 COUNT,
2110 COUNTA,
2111 PEARSON,
2112 MEDIAN,
2113 DEVSQ,
2114 EXPONDIST,
2115 FDIST$LEFTTAILED,
2116 FINV,
2117 FISHER,
2118 FISHERINV,
2119 MAX,
2120 MAXA,
2121 MIN,
2122 MINA,
2123 QUARTILE,
2124 PERCENTILE,
2125 STDEV,
2126 STDEVA,
2127 STDEVP,
2128 STDEVPA,
2129 TRIMMEAN,
2130 SLOPE,
2131 STANDARDIZE,
2132 SMALL,
2133 LARGE,
2134 KURT,
2135 INTERCEPT,
2136 FORECAST,
2137 POISSON,
2138 PERCENTRANK,
2139 PERCENTRANK$EXC,
2140 NORMSINV,
2141 NORMSDIST,
2142 NORMDIST,
2143 NORMINV,
2144 NEGBINOMDIST,
2145 GEOMEAN,
2146 HARMEAN,
2147 CONFIDENCE,
2148 BINOMDIST,
2149 COVAR,
2150 WEIBULL,
2151 VARPA,
2152 VARP,
2153 VARA,
2154 VAR,
2155 PERMUT,
2156 RSQ,
2157 SKEW,
2158 STEYX,
2159 PROB,
2160 MODE,
2161 RANK,
2162 RANK$AVG,
2163 RANK$EQ,
2164 LOGNORMDIST,
2165 TDIST,
2166 HYPGEOMDIST,
2167 ZTEST
2168}