spreadsheet
typeScript/javascript spreadsheet parser, with formulas.
git clone https://git.vogt.world/spreadsheet.git
Log | Files | README.md
← All files
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}