spreadsheet
typeScript/javascript spreadsheet parser, with formulas.
git clone https://git.vogt.world/spreadsheet.git
Log | Files | README.md
← All files
name: src/Formulas/Math.ts
-rw-r--r--
48930
   1import {
   2  ArgsChecker
   3} from "../Utilities/ArgsChecker";
   4import {
   5  TypeConverter
   6} from "../Utilities/TypeConverter";
   7import {
   8  Filter
   9} from "../Utilities/Filter";
  10import {
  11  Serializer
  12} from "../Utilities/Serializer";
  13import {
  14  CriteriaFunctionFactory
  15} from "../Utilities/CriteriaFunctionFactory";
  16import {
  17  NumError,
  18  DivZeroError,
  19  RefError,
  20  ValueError,
  21  NAError
  22} from "../Errors";
  23import {
  24  erf, gammaln
  25} from "../Utilities/MathHelpers";
  26import {
  27  AVERAGE,
  28  COUNT,
  29  COUNTA,
  30  MAX,
  31  MIN,
  32  STDEV,
  33  STDEVP,
  34  VAR,
  35  VARP
  36} from "./Statistical";
  37
  38
  39/**
  40 * Returns the greatest common divisor of one or more integers.
  41 * @param values - The values or ranges whose factors to consider in a calculation to find the greatest common divisor.
  42 * @returns {number} greatest common divisor.
  43 * @constructor
  44 */
  45let GCD = function (...values) {
  46  ArgsChecker.checkAtLeastLength(arguments, 1, "ABS");
  47  // Credits: Andrew Pociu
  48  for (var r, a, i = values.length - 1, result = values[i]; i;) {
  49    for (a = values[--i]; (r = a % result); a = result, result = r) {
  50      //empty
  51    }
  52  }
  53  return result;
  54};
  55
  56
  57/**
  58 * Returns the least common multiple of one or more integers.
  59 * @param values - The values or range whose factors to consider in a calculation to find the least common multiple.
  60 * @returns {number}
  61 * @constructor
  62 */
  63let LCM =  function (...values) {
  64  ArgsChecker.checkAtLeastLength(arguments, 1, "LCM");
  65  // Credits: Jonas Raoni Soares Silva
  66  let o = Filter.flatten(values);
  67  for (var i, j, n, d, r = 1; (n = o.pop()) !== undefined;) {
  68    while (n > 1) {
  69      if (n % 2) {
  70        for (i = 3, j = Math.floor(Math.sqrt(n)); i <= j && n % i; i += 2) {}
  71        d = (i <= j) ? i : n;
  72      } else {
  73        d = 2;
  74      }
  75      for (n /= d, r *= d, i = o.length; i; (o[--i] % d) === 0 && (o[i] /= d) === 1 && o.splice(i, 1)) {}
  76    }
  77  }
  78  return r;
  79};
  80
  81/**
  82 * Returns the the logarithm of a specified Gamma function, base e (Euler's number).
  83 * @param value - The input number. The natural logarithm of Gamma (value) will be returned. Must be positive.
  84 * @returns {number}
  85 * @constructor
  86 */
  87let GAMMALN = function (value) {
  88  ArgsChecker.checkLength(arguments, 1, "GAMMALN");
  89  let x =  TypeConverter.firstValueAsNumber(value);
  90  if (x <= 0) {
  91    throw new NumError("Function GAMMALN parameter 1 value is " + x + ". It should be greater than 0.");
  92  }
  93  return gammaln(x);
  94};
  95
  96/**
  97 * Returns the absolute value of a number.
  98 * @param value to get the absolute value of.
  99 * @returns {number} absolute value
 100 * @constructor
 101 */
 102let ABS = function (value) {
 103  ArgsChecker.checkLength(arguments, 1, "ABS");
 104  let v = TypeConverter.valueToNumber(value);
 105  return Math.abs(v);
 106};
 107
 108/**
 109 * Returns the inverse cosine of a value, in radians.
 110 * @param value The value for which to calculate the inverse cosine. Must be between -1 and 1, inclusive.
 111 * @returns {number} inverse cosine of value
 112 * @constructor
 113 */
 114let ACOS = function (value) {
 115  ArgsChecker.checkLength(arguments, 1, "ACOS");
 116  value = TypeConverter.valueToNumber(value);
 117  if (value === -1) {
 118    return Math.PI;
 119  } else if (value > 1 || value < -1) {
 120    throw new NumError("Function ACOS parameter 1 value is " + value + ". Valid values are between -1 and 1 inclusive.");
 121  }
 122  return Math.acos(value);
 123};
 124
 125/**
 126 * Returns the inverse hyperbolic cosine of a number.
 127 * @param value The value for which to calculate the inverse hyperbolic cosine. Must be greater than or equal to 1.
 128 * @returns {number} to find the inverse hyperbolic cosine for.
 129 * @constructor
 130 */
 131let ACOSH = function (value) {
 132  ArgsChecker.checkLength(arguments, 1, "ACOSH");
 133  value = TypeConverter.valueToNumber(value);
 134  if (value < 1) {
 135    throw new NumError("Function ACOSH parameter 1 value is " + value + ". It should be greater than or equal to 1.");
 136  }
 137  return Math.log(value + Math.sqrt(value * value - 1));
 138};
 139
 140/**
 141 * Calculate the hyperbolic arc-cotangent of a value
 142 * @param value number not between -1 and 1 inclusively.
 143 * @returns {number} hyperbolic arc-cotangent
 144 * @constructor
 145 */
 146let ACOTH = function (value) {
 147  ArgsChecker.checkLength(arguments, 1, "ACOTH");
 148  value = TypeConverter.valueToNumber(value);
 149  if (value <= 1 && value >= -1) {
 150    throw new NumError("Function ACOTH parameter 1 value is " + value + ". Valid values cannot be between -1 and 1 inclusive.")
 151  }
 152  return 0.5 * Math.log((value + 1) / (value - 1));
 153};
 154
 155/**
 156 * Returns the inverse sine of a value, in radians.
 157 * @param value The value for which to calculate the inverse sine. Must be between -1 and 1, inclusive.
 158 * @returns {number} inverse sine of input value
 159 * @constructor
 160 */
 161let ASIN = function (value) {
 162  ArgsChecker.checkLength(arguments, 1, "ASIN");
 163  value = TypeConverter.valueToNumber(value);
 164  if (value === -1) {
 165    return Math.PI;
 166  } else if (value > 1 || value < -1) {
 167    throw new NumError("Function ASIN parameter 1 value is " + value + ". Valid values are between -1 and 1 inclusive.");
 168  }
 169  return Math.asin(value);
 170};
 171
 172/**
 173 * Returns the inverse hyperbolic sine of a number.
 174 * @param value The value for which to calculate the inverse hyperbolic sine.
 175 * @returns {number} inverse hyperbolic sine of input
 176 * @constructor
 177 */
 178let ASINH = function (value) {
 179  ArgsChecker.checkLength(arguments, 1, "ASINH");
 180  value = TypeConverter.valueToNumber(value);
 181  return Math.log(value + Math.sqrt(value * value + 1));
 182};
 183
 184
 185/**
 186 * Returns the inverse tangent of a value, in radians.
 187 * @param value The value for which to calculate the inverse tangent.
 188 * @returns {number} inverse tangent of input value
 189 * @constructor
 190 */
 191let ATAN = function (value) {
 192  ArgsChecker.checkLength(arguments, 1, "ATAN");
 193  value = TypeConverter.valueToNumber(value);
 194  if (value === -1) {
 195    return Math.PI;
 196  } else if (value > 1 || value < -1) {
 197    throw new NumError("Function ATAN parameter 1 value is " + value + ". Valid values are between -1 and 1 inclusive.");
 198  }
 199  return Math.atan(value);
 200};
 201
 202
 203/**
 204 * Returns the angle between the x-axis and a line segment from the origin (0,0) to specified coordinate pair (x,y), in radians.
 205 * @param x The x coordinate of the endpoint of the line segment for which to calculate the angle from the x-axis.
 206 * @param y The y coordinate of the endpoint of the line segment for which to calculate the angle from the x-axis.
 207 * @returns {number} angle in radians
 208 * @constructor
 209 */
 210let ATAN2 = function (x, y) {
 211  ArgsChecker.checkLength(arguments, 2, "ATAN2");
 212  x = TypeConverter.valueToNumber(x);
 213  y = TypeConverter.valueToNumber(y);
 214  if (x === 0 && y === 0) {
 215    throw new DivZeroError("Evaluation of function ATAN2 caused a divide by zero error.");
 216  }
 217  return Math.atan2(y, x);
 218};
 219
 220
 221/**
 222 * Returns the inverse hyperbolic tangent of a number.
 223 * @param value The value for which to calculate the inverse hyperbolic tangent. Must be between -1 and 1, exclusive.
 224 * @returns {number} inverse hyperbolic tangent of input
 225 * @constructor
 226 */
 227let ATANH = function (value) : number {
 228  ArgsChecker.checkLength(arguments, 1, "ATANH");
 229  value = TypeConverter.valueToNumber(value);
 230  if (value >= 1 || value <= -1) {
 231    throw new NumError("Function ATANH parameter 1 value is " + value + ". Valid values are between -1 and 1 exclusive.");
 232  }
 233  if (Math.abs(value) < 1) {
 234
 235  }
 236  return Math["atanh"](value);
 237};
 238
 239/**
 240 * Rounds a number up to the nearest even integer.
 241 * @param value The value to round to the next greatest even number.
 242 * @returns {number} next greatest even number
 243 * @constructor
 244 */
 245let EVEN = function (value) : number {
 246  ArgsChecker.checkLength(arguments, 1, "EVEN");
 247  let X = TypeConverter.firstValueAsNumber(value);
 248  return X % 2 === 1 ? X + 1 : X;
 249};
 250
 251/**
 252 * Returns the result of the modulo operator, the remainder after a division operation.
 253 * @param dividend The number to be divided to find the remainder.
 254 * @param divisor The number to divide by.
 255 * @returns {number}
 256 * @constructor
 257 */
 258let MOD = function (dividend, divisor) : number {
 259  ArgsChecker.checkLength(arguments, 2, "MOD");
 260  let oneN = TypeConverter.valueToNumber(dividend);
 261  let twoN =  TypeConverter.valueToNumber(divisor);
 262  if (twoN === 0) {
 263    throw new DivZeroError("Function MOD parameter 2 cannot be zero.");
 264  }
 265  return oneN % twoN;
 266};
 267
 268
 269/**
 270 * Rounds a number up to the nearest odd integer.
 271 * @param value The value to round to the next greatest odd number.
 272 * @returns {number} value to round up to next greatest odd number.
 273 * @constructor
 274 */
 275let ODD = function (value) : number {
 276  ArgsChecker.checkLength(arguments, 1, "ODD");
 277  let X = TypeConverter.firstValueAsNumber(value);
 278  return X % 2 === 1 ? X : X + 1;
 279};
 280
 281/**
 282 * Returns a number raised to a power.
 283 * @param base - The number to raise to the exponent power.
 284 * @param exponent - The exponent to raise base to.
 285 * @returns {number} resulting number
 286 * @constructor
 287 */
 288let POWER = function (base, exponent) : number {
 289  ArgsChecker.checkLength(arguments, 2, "POWER");
 290  let n = TypeConverter.firstValueAsNumber(base);
 291  let p = TypeConverter.firstValueAsNumber(exponent);
 292  return Math.pow(n, p);
 293};
 294
 295/**
 296 * Returns the sum of a series of numbers and/or cells.
 297 * @param values The first number or range to add together.
 298 * @returns {number} The sum of the series
 299 * @constructor
 300 */
 301let SUM = function (...values) : number {
 302  ArgsChecker.checkAtLeastLength(values, 1, "SUM");
 303  let result = 0;
 304  for (let i = 0; i < values.length; i++) {
 305    if (values[i] instanceof Array) {
 306      result = result + SUM.apply(this, values[i]);
 307    } else {
 308      if (values[i] === "") {
 309        throw new ValueError("Function SUM parameter "+i+" expects number values. But '"+values[i]+"' is a text and cannot be coerced to a number.");
 310      }
 311      result = result + TypeConverter.valueToNumber(values[i]);
 312    }
 313  }
 314  return result;
 315};
 316
 317/**
 318 * Returns the positive square root of a positive number.
 319 * @param value - The number for which to calculate the positive square root.
 320 * @returns {number} square root
 321 * @constructor
 322 */
 323let SQRT = function (value) : number {
 324  ArgsChecker.checkLength(arguments, 1, "SQRT");
 325  let x = TypeConverter.firstValueAsNumber(value);
 326  if (x < 0) {
 327    throw new ValueError("Function SQRT parameter 1 value is " + x + ". It should be greater than or equal to 0.");
 328  }
 329  return Math.sqrt(x);
 330};
 331
 332/**
 333 * Returns the positive square root of the product of Pi and the given positive number.
 334 * @param value - The number which will be multiplied by Pi and have the product's square root returned
 335 * @returns {number} the positive square root of the product of Pi and the given positive number.
 336 * @constructor
 337 */
 338let SQRTPI = function (value) : number{
 339  ArgsChecker.checkLength(arguments, 1, "SQRTPI");
 340  let n = TypeConverter.firstValueAsNumber(value);
 341  if (n < 0) {
 342    throw new NumError("Function SQRTPI parameter 1 value is " + n + ". It should be greater than or equal to 0.");
 343  }
 344  return Math.sqrt(n * Math.PI);
 345};
 346
 347/**
 348 * Returns the cosine of an angle provided in radians.
 349 * @param value - The angle to find the cosine of, in radians.
 350 * @returns {number} cosine of angle
 351 * @constructor
 352 */
 353let COS = function (value) : number {
 354  ArgsChecker.checkLength(arguments, 1, "COS");
 355  let r = TypeConverter.firstValueAsNumber(value);
 356  return Math.cos(r);
 357};
 358
 359/**
 360 * Returns the hyperbolic cosine of any real number.
 361 * @param value - Any real value to calculate the hyperbolic cosine of.
 362 * @returns {number} the hyperbolic cosine of the input
 363 * @constructor
 364 */
 365let COSH = function (value) : number {
 366  ArgsChecker.checkLength(arguments, 1, "COSH");
 367  let r = TypeConverter.firstValueAsNumber(value);
 368  return Math["cosh"](r);
 369};
 370
 371/**
 372 * Returns the cotangent of any real number. Defined as cot(x) = 1 / tan(x).
 373 * @param value - number to calculate the cotangent for
 374 * @returns {number} cotangent
 375 * @constructor
 376 */
 377let COT = function (value) : number {
 378  ArgsChecker.checkLength(arguments, 1, "COT");
 379  let x = TypeConverter.firstValueAsNumber(value);
 380  if (x === 0) {
 381    throw new DivZeroError("Evaluation of function COT caused a divide by zero error.");
 382  }
 383  return 1 / Math.tan(x);
 384};
 385
 386/**
 387 * Return the hyperbolic cotangent of a value, defined as coth(x) = 1 / tanh(x).
 388 * @param value - value to calculate the hyperbolic cotangent value of
 389 * @returns {number} hyperbolic cotangent
 390 * @constructor
 391 */
 392let COTH = function (value) : number {
 393  ArgsChecker.checkLength(arguments, 1, "COTH");
 394  let x = TypeConverter.firstValueAsNumber(value);
 395  if (x === 0) {
 396    throw new DivZeroError("Evaluation of function COTH caused a divide by zero error.");
 397  }
 398  return 1 / Math["tanh"](x);
 399};
 400
 401/**
 402 * Rounds a number down to the nearest integer that is less than or equal to it.
 403 * @param value -  The value to round down to the nearest integer.
 404 * @returns {number} Rounded number
 405 * @constructor
 406 */
 407let INT = function (value) : number {
 408  ArgsChecker.checkLength(arguments, 1, "INT");
 409  let x = TypeConverter.firstValueAsNumber(value);
 410  return Math.floor(x);
 411};
 412
 413
 414/**
 415 * Checks whether the provided value is even.
 416 * @param value - The value to be verified as even.
 417 * @returns {boolean} whether this value is even or not
 418 * @constructor
 419 */
 420let ISEVEN = function (value) : boolean {
 421  ArgsChecker.checkLength(arguments, 1, "ISEVEN");
 422  if (value === "") {
 423    throw new ValueError("Function ISEVEN parameter 1 expects boolean values. But '" + value + "' is a text and cannot be coerced to a boolean.");
 424  }
 425  let x = TypeConverter.firstValueAsNumber(value);
 426  return Math.floor(x) % 2 === 0;
 427};
 428
 429
 430/**
 431 * Checks whether the provided value is odd.
 432 * @param value - The value to be verified as odd.
 433 * @returns {boolean} whether this value is odd or not
 434 * @constructor
 435 */
 436let ISODD = function (value) : boolean {
 437  ArgsChecker.checkLength(arguments, 1, "ISODD");
 438  if (value === "") {
 439    throw new ValueError("Function ISODD parameter 1 expects boolean values. But '" + value + "' is a text and cannot be coerced to a boolean.");
 440  }
 441  let x = TypeConverter.firstValueAsNumber(value);
 442  return Math.floor(x) % 2 === 1;
 443};
 444
 445/**
 446 * Returns the sine of an angle provided in radians.
 447 * @param value - The angle to find the sine of, in radians.
 448 * @returns {number} Sine of angle.
 449 * @constructor
 450 */
 451let SIN = function (value) {
 452  ArgsChecker.checkLength(arguments, 1, "SIN");
 453  let rad = TypeConverter.firstValueAsNumber(value);
 454  return rad === Math.PI ? 0 : Math.sin(rad);
 455};
 456
 457/**
 458 * Returns the hyperbolic sine of any real number.
 459 * @param value - real number to find the hyperbolic sine of
 460 * @returns {number} hyperbolic sine
 461 * @constructor
 462 */
 463let SINH = function (value) : number {
 464  ArgsChecker.checkLength(arguments, 1, "SINH");
 465  let rad = TypeConverter.firstValueAsNumber(value);
 466  return Math["sinh"](rad);
 467};
 468
 469/**
 470 * The value Pi.
 471 * @returns {number} Pi.
 472 * @constructor
 473 */
 474let PI = function () {
 475  ArgsChecker.checkLength(arguments, 0, "SINH");
 476  return Math.PI;
 477};
 478
 479/**
 480 * Returns the the logarithm of a number, base 10.
 481 * @param value - The value for which to calculate the logarithm, base 10.
 482 * @returns {number} logarithm of the number, in base 10.
 483 * @constructor
 484 */
 485let LOG10 = function (value) : number {
 486  ArgsChecker.checkLength(arguments, 1, "LOG10");
 487  let n = TypeConverter.firstValueAsNumber(value);
 488  if (n < 1) {
 489    throw new NumError("Function LOG10 parameter 1 value is " + n + ". It should be greater than 0.");
 490  }
 491  let ln = Math.log(n);
 492  let lb = Math.log(10);
 493  return ln / lb;
 494};
 495
 496/**
 497 * Returns the the logarithm of a number given a base.
 498 * @param value - The value for which to calculate the logarithm given base.
 499 * @param base - The base to use for calculation of the logarithm. Defaults to 10.
 500 * @returns {number}
 501 * @constructor
 502 */
 503let LOG = function (value, base) : number {
 504  ArgsChecker.checkAtLeastLength(arguments, 2, "LOG");
 505  let n = TypeConverter.firstValueAsNumber(value);
 506  let b = TypeConverter.firstValueAsNumber(base);
 507  if (b < 1) {
 508    throw new NumError("Function LOG parameter 2 value is " + b + ". It should be greater than 0.");
 509  }
 510  if (b < 2) {
 511    throw new DivZeroError("Evaluation of function LOG caused a divide by zero error.");
 512  }
 513  let ln = Math.log(n);
 514  let lb = Math.log(b);
 515  if (lb === 0) {
 516    throw new DivZeroError("Evaluation of function LOG caused a divide by zero error.");
 517  }
 518  return ln / lb;
 519};
 520
 521/**
 522 * Returns the logarithm of a number, base e (Euler's number).
 523 * @param value - The value for which to calculate the logarithm, base e.
 524 * @returns {number} logarithm calculated
 525 * @constructor
 526 */
 527let LN = function (value) : number {
 528  ArgsChecker.checkLength(arguments, 1, "LN");
 529  let n = TypeConverter.firstValueAsNumber(value);
 530  if (n < 1) {
 531    throw new NumError("Function LN parameter 1 value is " + n + ". It should be greater than 0.");
 532  }
 533  return Math.log(n);
 534};
 535
 536/**
 537 * Returns the tangent of an angle provided in radians.
 538 * @param value - The angle to find the tangent of, in radians.
 539 * @returns {number} tangent in radians
 540 * @constructor
 541 */
 542let TAN = function (value) : number {
 543  ArgsChecker.checkLength(arguments, 1, "TAN");
 544  let rad = TypeConverter.firstValueAsNumber(value);
 545  return rad === Math.PI ? 0 : Math.tan(rad);
 546};
 547
 548/**
 549 * Returns the hyperbolic tangent of any real number.
 550 * @param value - Any real value to calculate the hyperbolic tangent of.
 551 * @returns {number} hyperbolic tangent
 552 * @constructor
 553 */
 554let TANH = function (value) : number {
 555  ArgsChecker.checkLength(arguments, 1, "TANH");
 556  let rad = TypeConverter.firstValueAsNumber(value);
 557  return Math["tanh"](rad);
 558};
 559
 560/**
 561 * Rounds a number up to the nearest integer multiple of specified significance.
 562 * @param value The value to round up to the nearest integer multiple of factor.
 563 * @param factor - [ OPTIONAL ] The number to whose multiples value will be rounded.
 564 * @returns {number}
 565 * @constructor
 566 */
 567let CEILING = function (value, factor?) : number {
 568  ArgsChecker.checkLengthWithin(arguments, 1, 2, "CEILING");
 569  let num = TypeConverter.firstValueAsNumber(value);
 570  if (factor === undefined) {
 571    return Math.ceil(num);
 572  }
 573  let significance = TypeConverter.firstValueAsNumber(factor);
 574  if (significance === 0) {
 575    throw new DivZeroError("Function CEILING parameter 2 cannot be zero.");
 576  }
 577  let precision = -Math.floor(Math.log(significance) / Math.log(10));
 578  if (num >= 0) {
 579    return ROUND(Math.ceil(num / significance) * significance, precision);
 580  } else {
 581    return -ROUND(Math.floor(Math.abs(num) / significance) * significance, precision);
 582  }
 583};
 584
 585/**
 586 * Rounds a number down to the nearest integer multiple of specified significance.
 587 * @param value - The value to round down to the nearest integer multiple of factor.
 588 * @param factor - The number to whose multiples value will be rounded.
 589 * @returns {number}
 590 * @constructor
 591 */
 592let FLOOR = function (value, factor?) : number {
 593  ArgsChecker.checkLengthWithin(arguments, 1, 2, "FLOOR");
 594  let num = TypeConverter.firstValueAsNumber(value);
 595  if (factor === undefined) {
 596    return Math.floor(num);
 597  }
 598  let significance = TypeConverter.firstValueAsNumber(factor);
 599  if (significance === 0) {
 600    throw new DivZeroError("Function FLOOR parameter 2 cannot be zero.");
 601  }
 602  significance = significance ? Math.abs(significance) : 1;
 603  let precision = -Math.floor(Math.log(significance) / Math.log(10));
 604  if (num >= 0) {
 605    return ROUND(Math.floor(num / significance) * significance, precision);
 606  }
 607  return -ROUND(Math.floor(Math.abs(num) / significance) * significance, precision);
 608};
 609
 610/**
 611 * Returns one value if a logical expression is TRUE and another if it is FALSE.
 612 * @param logicalExpression - An expression or reference to a cell containing an expression that represents some logical value, i.e. TRUE or FALSE.
 613 * @param valueIfTrue - The value the function returns if logical_expression is TRUE
 614 * @param valueIfFalse - The value the function returns if logical_expression is FALSE.
 615 * @returns one value if a logical expression is TRUE and another if it is FALSE.
 616 * @constructor
 617 */
 618let IF = function (logicalExpression, valueIfTrue, valueIfFalse) : any {
 619  ArgsChecker.checkLength(arguments, 3, "IF");
 620  if (logicalExpression instanceof Array) {
 621    if (logicalExpression.length === 0) {
 622      throw new RefError("Reference does not exist.");
 623    }
 624    return IF(logicalExpression[0], valueIfTrue, valueIfFalse);
 625  } else if (logicalExpression === "") {
 626    return valueIfFalse;
 627  }
 628  return (TypeConverter.valueToBoolean(logicalExpression)) ? valueIfTrue : valueIfFalse;
 629};
 630
 631
 632/**
 633 * Returns a conditional count across a range.
 634 * @param range - The range that is tested against criterion., value[1];
 635 * @param criteria - The pattern or test to apply to range. If the range to check against contains text,
 636 * this must be a string. It can be a comparison based string (e.g. "=1", "<1", ">=1") or it can be a wild-card string,
 637 * in which * matches any number of characters, and ? matches the next character. Both ? and * can be escaped by placing
 638 * a ~ in front of them. If it is neither, it will compared with values in the range using equality comparison.
 639 * @returns {number}
 640 * @constructor
 641 */
 642let COUNTIF = function (range, criteria) {
 643  ArgsChecker.checkLength(arguments, 2, "COUNTIF");
 644  if (!(range instanceof Array)) {
 645    range = [range];
 646  }
 647  let criteriaEvaluation = CriteriaFunctionFactory.createCriteriaFunction(criteria);
 648
 649  let count = 0;
 650  for (let i = 0; i < range.length; i++) {
 651    let x = range[i];
 652    if (x instanceof Array) {
 653      count = count + COUNTIF.apply(this, [x, criteria]);
 654    } else if (criteriaEvaluation(x)) {
 655      count++;
 656    }
 657  }
 658  return count;
 659};
 660
 661/**
 662 * Returns the count of a range depending on multiple criteria.
 663 * @param values[0] criteria_range1 - The range to check against criterion1.
 664 * @param values[1] criterion1 - The pattern or test to apply to criteria_range1.
 665 * @param values[2...N] Repeated sets of ranges and criterion to check.
 666 * @returns {number} count
 667 * @constructor
 668 */
 669let COUNTIFS = function (...values) {
 670  ArgsChecker.checkAtLeastLength(values, 2, "COUNTIFS");
 671  let criteriaEvaluationFunctions = values.map(function (criteria, index) {
 672    if (index % 2 === 1) {
 673      return CriteriaFunctionFactory.createCriteriaFunction(criteria);
 674    } else {
 675      return function () {return false;}
 676    }
 677  });
 678  let filteredValues = [];
 679  // Flatten arrays/ranges
 680  for (let x = 0; x < values.length; x++) {
 681    // If this is an array/range parameter
 682    if (x % 2 === 0) {
 683      filteredValues.push(Filter.flatten(values[x]));
 684    } else {
 685      filteredValues.push(values[x]);
 686    }
 687  }
 688  let count = 0;
 689  // For every value in the range
 690  for (let i = 0; i < filteredValues[0].length; i++) {
 691    // Check for criteria eval for other ranges and other criteria pairs.
 692    let otherCriteriaEvaluationSuccessfulSoFar = true;
 693    for (let x = 0; x < filteredValues.length; x += 2) {
 694      if (filteredValues[x].length < filteredValues[0].length) {
 695        throw new ValueError("Array arguments to COUNTIFS are of different size.");
 696      }
 697      let criteriaEvaluation = criteriaEvaluationFunctions[x+1];
 698      if (otherCriteriaEvaluationSuccessfulSoFar) {
 699        if (!criteriaEvaluation(filteredValues[x][i])) { // evaluate THIS value with x+1 index, which is criteria.
 700          otherCriteriaEvaluationSuccessfulSoFar = false;
 701        }
 702      }
 703    }
 704    if (otherCriteriaEvaluationSuccessfulSoFar) {
 705      count++;
 706    }
 707  }
 708  return count;
 709};
 710
 711
 712/**
 713 * Rounds a number to a certain number of decimal places according to standard rules.
 714 * @param value - The value to round to places number of places.
 715 * @param places - The number of decimal places to which to round.
 716 * @returns {number}
 717 * @constructor
 718 */
 719let ROUND = function (value, places) {
 720  ArgsChecker.checkLength(arguments, 2, "ROUND");
 721  let n = TypeConverter.firstValueAsNumber(value);
 722  let d = TypeConverter.firstValueAsNumber(places);
 723  return Math.round(n * Math.pow(10, d)) / Math.pow(10, d);
 724};
 725
 726/**
 727 * Rounds a number to a certain number of decimal places, always rounding down to the next valid increment.
 728 * @param value - The value to round to places number of places, always rounding down.
 729 * @param places - (optional) The number of decimal places to which to round.
 730 * @returns {number}
 731 * @constructor
 732 */
 733let ROUNDDOWN = function (value, places?) {
 734  ArgsChecker.checkLengthWithin(arguments, 1, 2, "ROUNDDOWN");
 735  let n = TypeConverter.firstValueAsNumber(value);
 736  if (places === undefined) {
 737    return Math.floor(n);
 738  }
 739  let d = TypeConverter.firstValueAsNumber(places);
 740  return Math.floor(n * Math.pow(10, d)) / Math.pow(10, d);
 741};
 742
 743/**
 744 * Rounds a number to a certain number of decimal places, always rounding up to the next valid increment.
 745 * @param value - The value to round to places number of places, always rounding up.
 746 * @param places - (optional) The number of decimal places to which to round.
 747 * @returns {number}
 748 * @constructor
 749 */
 750let ROUNDUP = function (value, places?) {
 751  ArgsChecker.checkLengthWithin(arguments, 1, 2, "ROUNDUP");
 752  let n = TypeConverter.firstValueAsNumber(value);
 753  if (places === undefined) {
 754    return Math.ceil(n);
 755  }
 756  let d = TypeConverter.firstValueAsNumber(places);
 757  return Math.ceil(n * Math.pow(10, d)) / Math.pow(10, d);
 758};
 759
 760/**
 761 * Returns a conditional sum across a range.
 762 * @param range -  The range which is tested against criterion.
 763 * @param criteria - The pattern or test to apply to range. If the range to check against contains text, this must be a
 764 * string. It can be a comparison based string (e.g. "=1", "<1", ">=1") or it can be a wild-card string, in which *
 765 * matches any number of characters, and ? matches the next character. Both ? and * can be escaped by placing a ~ in
 766 * front of them.
 767 * @param sumRange - (optional) The range to be summed, if different from range.
 768 * @returns {number}
 769 * @constructor
 770 */
 771let SUMIF = function (range, criteria, sumRange?) {
 772  ArgsChecker.checkLengthWithin(arguments, 2, 3, "SUMIF");
 773
 774  let criteriaEvaluation = CriteriaFunctionFactory.createCriteriaFunction(criteria);
 775
 776  let sum = 0;
 777  for (let i = 0; i < range.length; i++) {
 778    let x = range[i];
 779    if (x instanceof Array) {
 780      sum += SUMIF.apply(this, [x, criteria]);
 781    } else {
 782      if (sumRange && i > sumRange.length-1) {
 783        continue;
 784      }
 785      if (arguments.length === 2 && TypeConverter.canCoerceToNumber(x) && criteriaEvaluation(x)) {
 786        sum = sum + TypeConverter.valueToNumber(x);
 787      } else if (arguments.length === 3 && TypeConverter.canCoerceToNumber(sumRange[i]) && criteriaEvaluation(x)) {
 788        sum = sum + TypeConverter.valueToNumber(sumRange[i]);
 789      }
 790    }
 791  }
 792  return sum;
 793};
 794
 795/**
 796 * Returns the sum of the squares of a series of numbers and/or cells.
 797 * @param values  The values or range(s) whose squares to add together.
 798 * @returns {number} the sum of the squares if the input.
 799 * @constructor
 800 */
 801let SUMSQ = function (...values) {
 802  ArgsChecker.checkAtLeastLength(values, 1, "SUMSQ");
 803  let result = 0;
 804  for (let i = 0; i < values.length; i++) {
 805    if (values[i] instanceof Array) {
 806      if (values[i].length === 0) {
 807        throw new RefError("Reference does not exist.");
 808      }
 809      result = result + SUMSQ.apply(this, Filter.filterOutNonNumberValues(values[i]));
 810    } else {
 811      let n = TypeConverter.valueToNumber(values[i]);
 812      result = result + (n * n);
 813    }
 814  }
 815  return result;
 816};
 817
 818
 819/**
 820 * Returns the product of two numbers. Equivalent to the `*` operator.
 821 * @param factor1 - The first multiplicand.
 822 * @param factor2 - The second multiplicand.
 823 * @constructor
 824 */
 825let MULTIPLY = function (factor1, factor2) {
 826  ArgsChecker.checkLength(arguments, 2, "MULTIPLY");
 827  let x = TypeConverter.firstValueAsNumber(factor1);
 828  let y = TypeConverter.firstValueAsNumber(factor2);
 829  return x * y;
 830};
 831
 832
 833/**
 834 * Returns the result of the first number minus the second number. Equivalent to the `-` operator.
 835 * @param one - The first number.
 836 * @param two - the second number.
 837 * @returns {number}
 838 * @constructor
 839 */
 840let MINUS = function (one, two) {
 841  ArgsChecker.checkLength(arguments, 2, "MINUS");
 842  let x = TypeConverter.firstValueAsNumber(one);
 843  let y = TypeConverter.firstValueAsNumber(two);
 844  return x - y;
 845};
 846
 847
 848/**
 849 * Returns true if two specified values are equal and true otherwise. Equivalent to the "=" operator.
 850 * @param one - First value to check.
 851 * @param two - Second value to check.
 852 * @returns {boolean} true if values are equal, false if they are not equal.
 853 * @constructor
 854 */
 855let EQ = function (one, two) {
 856  ArgsChecker.checkLength(arguments, 2, "EQ");
 857  let x = TypeConverter.firstValue(one);
 858  let y = TypeConverter.firstValue(two);
 859  return x === y;
 860};
 861
 862
 863/**
 864 * Returns true if the first argument is strictly greater than the second, and false otherwise. Equivalent to the `>`
 865 * operator.
 866 * @param one - The value to test as being greater than `two`.
 867 * @param two - The second value.
 868 * @returns {boolean}
 869 * @constructor
 870 */
 871let GT = function (one, two) {
 872  ArgsChecker.checkLength(arguments, 2, "GT");
 873  let x = TypeConverter.firstValue(one);
 874  let y = TypeConverter.firstValue(two);
 875  return x > y;
 876};
 877
 878
 879/**
 880 * Returns true if the first argument is greater than or equal to the second, and false otherwise. Equivalent to the
 881 * `>=` operator.
 882 * @param one - The value to test as being greater than or equal to `two`.
 883 * @param two -The second value.
 884 * @returns {boolean}
 885 * @constructor
 886 */
 887let GTE = function (one, two) {
 888  ArgsChecker.checkLength(arguments, 2, "GTE");
 889  let x = TypeConverter.firstValue(one);
 890  let y = TypeConverter.firstValue(two);
 891  return x >= y;
 892};
 893
 894
 895/**
 896 * Returns true if the first argument is strictly less than the second, and false otherwise. Equivalent to the `<`
 897 * operator.
 898 * @param one - The value to test as being less than `two`.
 899 * @param two - The second value.
 900 * @returns {boolean}
 901 * @constructor
 902 */
 903let LT = function (one, two) {
 904  ArgsChecker.checkLength(arguments, 2, "LT");
 905  let x = TypeConverter.firstValue(one);
 906  let y = TypeConverter.firstValue(two);
 907  return x < y;
 908};
 909
 910
 911/**
 912 * Returns true if the first argument is less than or equal to the second, and true otherwise. Equivalent to the
 913 * `<=` operator.
 914 * @param one - The value to test as being less than or equal to `two`.
 915 * @param two - The second value.
 916 * @constructor
 917 */
 918let LTE = function (one, two) {
 919  ArgsChecker.checkLength(arguments, 2, "LTE");
 920  let x = TypeConverter.firstValue(one);
 921  let y = TypeConverter.firstValue(two);
 922  return x <= y;
 923};
 924
 925
 926/**
 927 * Returns "TRUE" if two specified values are not equal and "FALSE" otherwise. Equivalent to the "<>" operator.
 928 * @param one - The value to test as being not equal to `two`.
 929 * @param two - The second valud.
 930 * @returns {boolean}
 931 * @constructor
 932 */
 933let NE =  function (one, two) {
 934  ArgsChecker.checkLength(arguments, 2, "NE");
 935  let x = TypeConverter.firstValue(one);
 936  let y = TypeConverter.firstValue(two);
 937  return x !== y;
 938};
 939
 940
 941/**
 942 * Returns one number divided by another. Equivalent to the `/` operator.
 943 * @param dividend - The number to be divided.
 944 * @param divisor - The number to divide by, cannot be 0.
 945 * @returns {number} result of dividend / divisor.
 946 * @constructor
 947 */
 948let DIVIDE = function (dividend, divisor) {
 949  ArgsChecker.checkLength(arguments, 2, "DIVIDE");
 950  let x = TypeConverter.firstValueAsNumber(dividend);
 951  let y = TypeConverter.firstValueAsNumber(divisor);
 952  if (y < 0) {
 953    throw new DivZeroError("Function DIVIDE parameter 2 cannot be zero.");
 954  }
 955  let result = x / y;
 956  if (result == Infinity) {
 957    throw new DivZeroError("Evaluation caused divide by zero error.");
 958  } else if (isNaN(result)) {
 959    throw new DivZeroError("Evaluation caused divide by zero error.");
 960  }
 961  return result;
 962};
 963
 964
 965/**
 966 * Returns a random number between 0 inclusive and 1 exclusive.
 967 * @returns {number}
 968 * @constructor
 969 */
 970let RAND = function () {
 971  ArgsChecker.checkLength(arguments, 0, "RAND");
 972  return Math.random();
 973};
 974
 975
 976/**
 977 * Returns a uniformly random integer between two values, inclusive on high and low. Values with decimal parts may be
 978 * used for low and/or high; this will cause the least and greatest possible values to be the next integer greater than
 979 * low and/or the next integer less than high, respectively.
 980 * @param low - lowest value
 981 * @param high - highest value
 982 * @returns {number} between low and high.
 983 * @constructor
 984 */
 985let RANDBETWEEN = function (low, high) {
 986  ArgsChecker.checkLength(arguments, 2, "RAND");
 987  low = Math.floor(TypeConverter.firstValueAsNumber(low));
 988  high = Math.ceil(TypeConverter.firstValueAsNumber(high));
 989  if (low > high) {
 990    throw new NumError("Function RANDBETWEEN parameter 2 value is " + low + ". It should be greater than or equal to "
 991      + high + ".");
 992  }
 993  let diff = Math.abs(low - high);
 994  return Math.round(low + (Math.random() * diff));
 995};
 996
 997
 998/**
 999 * Given an input number, returns `-1` if it is negative, `1` if positive, and `0` if it is zero.
1000 * @param value - The value to check the sign for
1001 * @returns {number} `-1` if it is negative, `1` if positive, and `0` if it is zero.
1002 * @constructor
1003 */
1004let SIGN =  function (value) {
1005  ArgsChecker.checkLength(arguments, 1, "SIGN");
1006  let x = TypeConverter.firstValueAsNumber(value);
1007  if (x === 0) {
1008    return 0;
1009  }
1010  return x > 0 ? 1 : -1;
1011};
1012
1013
1014/**
1015 * Truncates a number to a certain number of significant digits by omitting less significant digits.
1016 * @param value - The value to be truncated.
1017 * @param places - [ OPTIONAL - 0 by default ] - The number of significant digits to the right of the decimal point to
1018 * retain. If places is greater than the number of significant digits in value, value is returned without modification.
1019 * places may be negative, in which case the specified number of digits to the left of the decimal place are changed to
1020 * zero. All digits to the right of the decimal place are discarded. If all digits of value are changed to zero, TRUNC
1021 * simply returns 0.
1022 * @returns {number} after truncation
1023 * @constructor
1024 */
1025let TRUNC = function (value, places?) : number {
1026  ArgsChecker.checkLengthWithin(arguments, 1, 2, "TRUNC");
1027  let n = TypeConverter.firstValueAsNumber(value);
1028  let digits = 0;
1029  if (places !== undefined) {
1030    digits = TypeConverter.firstValueAsNumber(places);
1031  }
1032  let sign = (n > 0) ? 1 : -1;
1033  return sign * (Math.floor(Math.abs(n) * Math.pow(10, digits))) / Math.pow(10, digits);
1034};
1035
1036
1037/**
1038 * Converts an angle value in degrees to radians.
1039 * @param angle - The angle to convert from degrees to radians.
1040 * @returns {number} radians
1041 * @constructor
1042 */
1043let RADIANS = function (angle) {
1044  ArgsChecker.checkLength(arguments, 1, "RADIANS");
1045  let d = TypeConverter.firstValueAsNumber(angle);
1046  return d * Math.PI / 180;
1047};
1048
1049/**
1050 * Converts an angle value in radians to degrees.
1051 * @param angle - The angle to convert from radians to degrees.
1052 * @returns {number} degrees
1053 * @constructor
1054 */
1055let DEGREES = function (angle) {
1056  ArgsChecker.checkLength(arguments, 1, "DEGREES");
1057  let r = TypeConverter.firstValueAsNumber(angle);
1058  return r * 180 / Math.PI;
1059};
1060
1061
1062/**
1063 * Returns the complementary Gauss error function of a value.
1064 * @param value - The number for which to calculate the complementary Gauss error function.
1065 * @returns {number} complementary Gauss error function of a value
1066 * @constructor
1067 */
1068let ERFC = function (value) {
1069  ArgsChecker.checkLength(arguments, 1, "ERFC");
1070  let v = TypeConverter.firstValueAsNumber(value);
1071  return v === 0 ? 1 : 1 - erf(v);
1072};
1073
1074
1075/**
1076 * Returns the error function integrated between lower_limit and upper_limit.
1077 * @param lowerLimit - The lower bound for integrating ERF.
1078 * @param upperLimit - [Optional]. The upper bound for integrating ERF. If omitted, ERF integrates between
1079 * zero and lower_limit.
1080 * @returns {number} error function integrated between lower_limit and upper_limit
1081 * @constructor
1082 */
1083let ERF = function (lowerLimit, upperLimit?) : number {
1084  ArgsChecker.checkLengthWithin(arguments, 1, 2, "ERF");
1085  let lower = TypeConverter.firstValueAsNumber(lowerLimit);
1086  let upper = upperLimit !== undefined ? TypeConverter.firstValueAsNumber(upperLimit) : 0;
1087  return upperLimit === undefined ? erf(lower) : erf(upper) - erf(lower);
1088};
1089
1090
1091/**
1092 * Calculates the sum of the sums of the squares of values in two arrays.
1093 * @param arrayX - The array or range of values whose squares will be added to the squares of corresponding
1094 * entries in arrayY and added together.
1095 * @param arrayY - The array or range of values whose squares will be added to the squares of corresponding
1096 * entries in arrayX and added together.
1097 * @returns {number} sum of the sums of the squares
1098 * @constructor
1099 */
1100let SUMX2PY2 = function (arrayX, arrayY) : number {
1101  ArgsChecker.checkLength(arguments, 2, "SUMX2PY2");
1102  let arrOne = Filter.flattenAndThrow(arrayX);
1103  let arrTwo = Filter.flattenAndThrow(arrayY);
1104  if (arrOne.length !== arrTwo.length) {
1105    throw new NAError("Array arguments to SUMX2PY2 are of different size.");
1106  }
1107  let result = 0;
1108  for (let i = 0; i < arrOne.length; i++) {
1109    // If either values at this index are anything but numbers, skip them. This is the behavior in GS at least.
1110    if (typeof arrOne[i] === "number" && typeof arrTwo[i] === "number") {
1111      result += arrOne[i] * arrOne[i] + arrTwo[i] * arrTwo[i];
1112    }
1113  }
1114  return result;
1115};
1116
1117/**
1118 * Calculates the sum of the differences of the squares of values in two arrays.
1119 * @param arrayX - The array or range of values whose squares will be reduced by the squares of corresponding
1120 * entries in array_y and added together.
1121 * @param arrayY - The array or range of values whose squares will be subtracted from the squares of
1122 * corresponding entries in array_x and added together.
1123 * @returns {number} sum of the differences of the squares
1124 * @constructor
1125 */
1126let SUMX2MY2 = function (arrayX, arrayY) : number {
1127  ArgsChecker.checkLength(arguments, 2, "SUMX2MY2");
1128  let arrOne = Filter.flattenAndThrow(arrayX);
1129  let arrTwo = Filter.flattenAndThrow(arrayY);
1130  if (arrOne.length !== arrTwo.length) {
1131    throw new NAError("Array arguments to SUMX2MY2 are of different size.");
1132  }
1133  let result = 0;
1134  for (let i = 0; i < arrOne.length; i++) {
1135    // If either values at this index are anything but numbers, skip them. This is the behavior in GS at least.
1136    if (typeof arrOne[i] === "number" && typeof arrTwo[i] === "number") {
1137      result += arrOne[i] * arrOne[i] - arrTwo[i] * arrTwo[i];
1138    }
1139  }
1140  return result;
1141};
1142
1143
1144// Private function that will recursively generate an array of the unique primitives
1145let _countUnique = function (values: Array<any>) : Object {
1146  let uniques = {};
1147  for (let i = 0; i < values.length; i++) {
1148    if (Array.isArray(values[i])) {
1149      // For some reasons an empty range is converted to a range with a single empty string in it.
1150      if (values[i].length === 0) {
1151        values[i] = [""];
1152      }
1153      let uniquesOfArray = _countUnique(values[i]);
1154      for (let key in uniquesOfArray) {
1155        uniques[key] = true;
1156      }
1157    } else {
1158      uniques[Serializer.serialize(values[i])] = true;
1159    }
1160  }
1161  return uniques;
1162};
1163
1164/**
1165 * Counts the number of unique values in a list of specified values and ranges.
1166 * @param values The values or ranges to consider for uniqueness. Supports an arbitrary number of arguments for this
1167 * function.
1168 * @returns {number} of unique values passed in.
1169 * @constructor
1170 */
1171let COUNTUNIQUE = function (...values) : number {
1172  ArgsChecker.checkAtLeastLength(values, 1, "COUNTUNIQUE");
1173
1174  let uniques = _countUnique(values);
1175  return Object.keys(uniques).length;
1176};
1177
1178
1179/**
1180 * Calculates the sum of the products of corresponding entries in two equal-sized arrays or ranges.
1181 * @param values Arrays or ranges whose entries will be multiplied with corresponding entries in the second such array
1182 * or range.
1183 * @returns {number} sum of the products
1184 * @constructor
1185 */
1186let SUMPRODUCT = function (...values) : number {
1187  ArgsChecker.checkAtLeastLength(values, 1, "SUMPRODUCT");
1188  // Ensuring that all values are array values
1189  for (let x = 0; x < values.length; x++) {
1190    if (!Array.isArray(values[x])) {
1191      values[x] = [values[x]];
1192    }
1193  }
1194
1195  // Flatten any nested ranges (arrays) and check for mismatched range sizes
1196  let flattenedValues = [Filter.flattenAndThrow(values[0])];
1197  for (let x = 1; x < values.length; x++) {
1198    flattenedValues.push(Filter.flattenAndThrow(values[x]));
1199    if (flattenedValues[x].length !== flattenedValues[0].length) {
1200      throw new ValueError("SUMPRODUCT has mismatched range sizes. Expected count: "
1201        + flattenedValues[0].length + ". Actual count: " + flattenedValues[0].length + ".");
1202    }
1203  }
1204
1205  // Do the actual math
1206  let result = 0;
1207  for (let i = 0; i < flattenedValues[0].length; i++) {
1208    let product = 1;
1209    for (let x = 0; x < flattenedValues.length; x++) {
1210      product *= TypeConverter.valueToNumberGracefully(flattenedValues[x][i]);
1211    }
1212    result += product;
1213  }
1214  return result;
1215};
1216
1217
1218/**
1219 * Returns the number of ways to choose some number of objects from a pool of a given size of objects.
1220 * @param m - The size of the pool of objects to choose from.
1221 * @param k - The number of objects to choose.
1222 * @returns {number} number of ways
1223 * @constructor
1224 */
1225let COMBIN = function (m, k) : number {
1226  ArgsChecker.checkLength(arguments, 2, "COMBIN");
1227
1228  let MEMOIZED_FACT = [];
1229  function fact(number) {
1230    let n = Math.floor(number);
1231    if (n === 0 || n === 1) {
1232      return 1;
1233    } else if (MEMOIZED_FACT[n] > 0) {
1234      return MEMOIZED_FACT[n];
1235    } else {
1236      MEMOIZED_FACT[n] = fact(n - 1) * n;
1237      return MEMOIZED_FACT[n];
1238    }
1239  }
1240  let n = TypeConverter.firstValueAsNumber(m);
1241  let c = TypeConverter.firstValueAsNumber(k);
1242  if (n < c) {
1243    throw new NumError("Function COMBIN parameter 2 value is "
1244      + c + ". It should be less than or equal to value of Function COMBIN parameter 1 with " + n + ".");
1245  }
1246  n = Math.floor(n);
1247  c = Math.floor(c);
1248  let div = fact(c) * fact(n - c);
1249  if (div === 0) {
1250    throw new DivZeroError("Evaluation of function COMBIN caused a divide by zero error.");
1251  }
1252  return fact(n) / div;
1253};
1254
1255/**
1256 * Multiply a series of numbers together.
1257 * @param values - values or range of values to multiply by each other.
1258 * @constructor
1259 */
1260let PRODUCT =  function (...values) {
1261  ArgsChecker.checkAtLeastLength(values, 2, "PRODUCT");
1262  let value = 1;
1263  let numbers = Filter.flattenAndThrow(values);
1264  for (let i = 0; i < numbers.length; i++) {
1265    value *= TypeConverter.valueToNumber(numbers[i]);
1266  }
1267  return value;
1268};
1269
1270
1271/**
1272 * Divide one number by another
1273 * @param dividend - number to be divided by the divisor.
1274 * @param divisor - number to divide the dividend.
1275 * @returns {number}
1276 * @constructor
1277 */
1278let QUOTIENT = function (dividend, divisor) {
1279  ArgsChecker.checkLength(arguments, 2, "QUOTIENT");
1280  let dv = TypeConverter.firstValueAsNumber(dividend);
1281  let ds = TypeConverter.firstValueAsNumber(divisor);
1282  if (ds === 0) {
1283    throw new DivZeroError("Function QUOTIENT parameter 2 cannot be zero.");
1284  }
1285  return dv / ds;
1286};
1287
1288
1289/**
1290 * Returns a value, but does nothing to it. If given a range, will return first value.
1291 * @param value to return
1292 * @returns any value
1293 * @constructor
1294 */
1295let UPLUS = function (value) : any {
1296  ArgsChecker.checkLength(arguments, 1, "UPLUS");
1297  return TypeConverter.firstValue(value);
1298};
1299
1300
1301/**
1302 * Returns the same number, but with the sign reversed.
1303 * @param value to reverse the sign on
1304 * @returns {number}
1305 * @constructor
1306 */
1307let UMINUS = function (value) {
1308  ArgsChecker.checkLength(arguments, 1, "UMINUS");
1309  let n = TypeConverter.firstValueAsNumber(value);
1310  return n * -1;
1311};
1312
1313
1314/**
1315 * Rounds a number to the nearest integer multiple of another.
1316 * @param value - value to round.
1317 * @param factor - multiple.
1318 * @returns {number}
1319 * @constructor
1320 */
1321let MROUND = function (value, factor) {
1322  ArgsChecker.checkLength(arguments, 2, "MROUND");
1323  let v = TypeConverter.firstValueAsNumber(value);
1324  let f = TypeConverter.firstValueAsNumber(factor);
1325  if (v * f < 0) {
1326    throw new NumError("Parameters of MROUND must have same signs (both positive or both negative).");
1327  }
1328  if (f === 0) {
1329    return 0;
1330  }
1331  return Math.round(v / f) * f;
1332};
1333
1334
1335/**
1336 * Calculates the double-factorial of a number.
1337 * @param value - value or reference to calculate.
1338 * @returns {number}
1339 * @constructor
1340 */
1341let FACTDOUBLE = function (value) {
1342  ArgsChecker.checkLength(arguments, 1, "FACTDOUBLE");
1343  let n = Math.floor(TypeConverter.firstValueAsNumber(value));
1344  function factDoublePrivate(n) {
1345    if (n <= 0) {
1346      return 1;
1347    } else {
1348      return n * factDoublePrivate(n - 2);
1349    }
1350  }
1351  if (n === 0) {
1352    return 0;
1353  } else if (n < 0) {
1354    throw new NumError("Function FACTDOUBLE parameter 1 value is '" + n
1355        + "'. It should be greater than or equal to 0.");
1356  } else {
1357    return factDoublePrivate(n);
1358  }
1359};
1360
1361/**
1362 * Returns a value as a percentage where 100 is 1.0, and 0 is 0.
1363 * @param value - To convert.
1364 * @returns {number}
1365 * @constructor
1366 */
1367let UNARY_PERCENT = function (value) {
1368  ArgsChecker.checkLength(arguments, 1, "UNARY_PERCENT");
1369  return TypeConverter.firstValueAsNumber(value) / 100;
1370};
1371
1372
1373/**
1374 * Returns the factorial of the sum of the arguments divided by the product of the factorials of the arguments.
1375 * @param values - Range of numbers.
1376 * @returns {number}
1377 * @constructor
1378 */
1379let MULTINOMIAL = function (...values) {
1380  ArgsChecker.checkAtLeastLength(values, 1, "MULTINOMIAL");
1381  values = Filter.flattenAndThrow(values).map(TypeConverter.valueToNumber);
1382  let memoizeFact = [];
1383  function _fact(value) {
1384    let n = Math.floor(value);
1385    if (n === 0 || n === 1) {
1386      return 1;
1387    } else if (memoizeFact[n] > 0) {
1388      return memoizeFact[n];
1389    } else {
1390      memoizeFact[n] = _fact(n - 1) * n;
1391      return memoizeFact[n];
1392    }
1393  }
1394  let sum = 0;
1395  let divisor = 1;
1396  for (let i = 0; i < values.length; i++) {
1397    sum += arguments[i];
1398    divisor *= _fact(values[i]);
1399  }
1400  return _fact(sum) / divisor;
1401};
1402
1403
1404/**
1405 * Returns a sum of powers of the number x in accordance with the following formula.
1406 * @param x - The number as an independent variable.
1407 * @param n - The starting power.
1408 * @param m - The number to increment by
1409 * @param coefficients - A series of coefficients. For each coefficient the series sum is extended by one section. You
1410 * can only enter coefficients using cell references.
1411 * @returns {number}
1412 * @constructor
1413 */
1414let SERIESSUM = function (x, n, m, coefficients) {
1415  ArgsChecker.checkLength(arguments, 4, "SERIESSUM");
1416  x = TypeConverter.firstValueAsNumber(x);
1417  n = TypeConverter.firstValueAsNumber(n);
1418  m = TypeConverter.firstValueAsNumber(m);
1419  coefficients =  Filter.flattenAndThrow(coefficients).map(TypeConverter.valueToNumber);
1420  let result = coefficients[0] * Math.pow(x, n);
1421  for (let i = 1; i < coefficients.length; i++) {
1422    result += coefficients[i] * Math.pow(x, n + i * m);
1423  }
1424  return result;
1425};
1426
1427
1428/**
1429 * Calculates subtotals. If a range already contains subtotals, these are not used for further calculations.
1430 * @param functionCode - A value that stands for another function: 1=AVERAGE, 2=COUNT, 3=COUNTA, 4=MAX, 5=MIN,
1431 * 6=PRODUCT, 7=STDEV, 8=STDEVP, 9=SUM, 10=VAR, 11=VARP.
1432 * @param values - The ranges whose cells are included.
1433 * @returns {Array}
1434 * @constructor
1435 */
1436let SUBTOTAL =  function (functionCode, ...values: Array<Array<any>>) {
1437  ArgsChecker.checkAtLeastLength(arguments, 2, "SUBTOTAL");
1438  functionCode = TypeConverter.firstValueAsNumber(functionCode);
1439  values = Filter.flattenAndThrow(values);
1440  switch (functionCode) {
1441    case 1:
1442      return AVERAGE(values);
1443    case 2:
1444      return COUNT(values);
1445    case 3:
1446      return COUNTA(values);
1447    case 4:
1448      return MAX(values);
1449    case 5:
1450      return MIN(values);
1451    case 6:
1452      return PRODUCT.apply(this, values);
1453    case 7:
1454      return STDEV(values);
1455    case 8:
1456      return STDEVP(values);
1457    case 9:
1458      return SUM(values);
1459    case 10:
1460      return VAR(values);
1461    case 11:
1462      return VARP(values);
1463    default:
1464      throw new ValueError("Value '" + functionCode +
1465          "' does not correspond to a function for use in SUBTOTAL. Value should be between 1 to 11.");
1466  }
1467};
1468
1469
1470export {
1471  ABS,
1472  ACOS,
1473  ACOSH,
1474  ACOTH,
1475  ASIN,
1476  ASINH,
1477  ATAN,
1478  ATAN2,
1479  ATANH,
1480  COT,
1481  COTH,
1482  COSH,
1483  COS,
1484  COUNTUNIQUE,
1485  EVEN,
1486  ERF,
1487  ERFC,
1488  INT,
1489  ISEVEN,
1490  ISODD,
1491  MOD,
1492  ODD,
1493  SIN,
1494  SINH,
1495  SUM,
1496  SQRT,
1497  SQRTPI,
1498  PI,
1499  POWER,
1500  LOG,
1501  LOG10,
1502  LN,
1503  MULTIPLY,
1504  MINUS,
1505  TAN,
1506  TANH,
1507  ROUND,
1508  ROUNDDOWN,
1509  ROUNDUP,
1510  SUMPRODUCT,
1511  SUMIF,
1512  SUMSQ,
1513  SUMX2MY2,
1514  SUMX2PY2,
1515  FLOOR,
1516  IF,
1517  COUNTIF,
1518  COUNTIFS,
1519  CEILING,
1520  TRUNC,
1521  RADIANS,
1522  DEGREES,
1523  COMBIN,
1524  RAND,
1525  RANDBETWEEN,
1526  SIGN,
1527  DIVIDE,
1528  EQ,
1529  GT,
1530  GTE,
1531  LT,
1532  LTE,
1533  NE,
1534  GCD,
1535  LCM,
1536  GAMMALN,
1537  PRODUCT,
1538  QUOTIENT,
1539  UPLUS,
1540  UMINUS,
1541  MROUND,
1542  FACTDOUBLE,
1543  UNARY_PERCENT,
1544  MULTINOMIAL,
1545  SERIESSUM,
1546  SUBTOTAL
1547}