spreadsheet
typeScript/javascript spreadsheet parser, with formulas.
git clone https://git.vogt.world/spreadsheet.git
Log | Files | README.md
← Commit log
commit
message
Refactring some functions/formulas into Math.ts
author
Ben Vogt <[email protected]>
date
2017-02-19 20:44:22
stats
2 file(s) changed, 361 insertions(+), 456 deletions(-)
files
src/RawFormulas/Math.ts
src/RawFormulas/RawFormulas.ts
  1diff --git a/src/RawFormulas/Math.ts b/src/RawFormulas/Math.ts
  2index 5118f85..55ef2d8 100644
  3--- a/src/RawFormulas/Math.ts
  4+++ b/src/RawFormulas/Math.ts
  5@@ -2,7 +2,8 @@ import {
  6   ArgsChecker,
  7   CriteriaFunctionFactory,
  8   Filter,
  9-  TypeCaster,
 10+  Serializer,
 11+  TypeCaster
 12 } from "./Utils";
 13 import { CellError } from "../Errors";
 14 import * as ERRORS from "../Errors";
 15@@ -1308,6 +1309,344 @@ var FDIST$LEFTTAILED = function (...values) : number|undefined|boolean {
 16   return (cumulative) ? cdf(x, d1, d2) : pdf(x, d1, d2);
 17 };
 18 
 19+/**
 20+ * Returns the complementary Gauss error function of a value.
 21+ * @param values[0] The number for which to calculate the complementary Gauss error function.
 22+ * @returns {number} complementary Gauss error function of a value
 23+ * @constructor
 24+ */
 25+var ERFC = function (...values) {
 26+  ArgsChecker.checkLength(values, 1);
 27+  var v = TypeCaster.firstValueAsNumber(values[0]);
 28+  return v === 0 ? 1 : 1 - erf(v);
 29+};
 30+
 31+
 32+/**
 33+ * Returns the error function integrated between lower_limit and upper_limit.
 34+ * @param values[0] lower_limit - The lower bound for integrating ERF.
 35+ * @param values[1] upper_limit - [Optional]. The upper bound for integrating ERF. If omitted, ERF integrates between
 36+ * zero and lower_limit.
 37+ * @returns {number} error function integrated between lower_limit and upper_limit
 38+ * @constructor
 39+ */
 40+var ERF = function (...values) : number {
 41+  ArgsChecker.checkLengthWithin(values, 1, 2);
 42+  var lower = TypeCaster.firstValueAsNumber(values[0]);
 43+  var upper = values.length === 2 ? TypeCaster.firstValueAsNumber(values[1]) : 0;
 44+  return values.length === 1 ? erf(lower) : erf(upper) - erf(lower);
 45+};
 46+
 47+// erf function from jStat [http://www.jstat.org/]
 48+function erf(x) {
 49+  var cof = [-1.3026537197817094, 6.4196979235649026e-1, 1.9476473204185836e-2,
 50+    -9.561514786808631e-3, -9.46595344482036e-4, 3.66839497852761e-4,
 51+    4.2523324806907e-5, -2.0278578112534e-5, -1.624290004647e-6,
 52+    1.303655835580e-6, 1.5626441722e-8, -8.5238095915e-8,
 53+    6.529054439e-9, 5.059343495e-9, -9.91364156e-10,
 54+    -2.27365122e-10, 9.6467911e-11, 2.394038e-12,
 55+    -6.886027e-12, 8.94487e-13, 3.13092e-13,
 56+    -1.12708e-13, 3.81e-16, 7.106e-15,
 57+    -1.523e-15, -9.4e-17, 1.21e-16,
 58+    -2.8e-17];
 59+  var j = cof.length - 1;
 60+  var isneg = false;
 61+  var d = 0;
 62+  var dd = 0;
 63+  var t, ty, tmp, res;
 64+
 65+  if (x < 0) {
 66+    x = -x;
 67+    isneg = true;
 68+  }
 69+
 70+  t = 2 / (2 + x);
 71+  ty = 4 * t - 2;
 72+
 73+  for(; j > 0; j--) {
 74+    tmp = d;
 75+    d = ty * d - dd + cof[j];
 76+    dd = tmp;
 77+  }
 78+
 79+  res = t * Math.exp(-x * x + 0.5 * (cof[0] + ty * d) - dd);
 80+  return isneg ? res - 1 : 1 - res;
 81+}
 82+
 83+
 84+
 85+/**
 86+ * Calculates the depreciation of an asset for a specified period using the double-declining balance method.
 87+ * @param values[0] cost - The initial cost of the asset.
 88+ * @param values[1] salvage - The value of the asset at the end of depreciation.
 89+ * @param values[2] life - The number of periods over which the asset is depreciated.
 90+ * @param values[3] period - The single period within life for which to calculate depreciation.
 91+ * @param values[4] factor - [ OPTIONAL - 2 by default ] - The factor by which depreciation decreases.
 92+ * @returns {number} depreciation of an asset for a specified period
 93+ * @constructor
 94+ */
 95+var DDB = function (...values) : number {
 96+  ArgsChecker.checkLengthWithin(values, 4, 5);
 97+  var cost = TypeCaster.firstValueAsNumber(values[0]);
 98+  var salvage = TypeCaster.firstValueAsNumber(values[1]);
 99+  var life = TypeCaster.firstValueAsNumber(values[2]);
100+  var period = TypeCaster.firstValueAsNumber(values[3]);
101+  var factor = values.length === 5 ? TypeCaster.firstValueAsNumber(values[4]) : 2;
102+
103+  if (cost < 0) {
104+    throw new CellError(ERRORS.NUM_ERROR, "Function DDB parameter 1 value is "
105+      + cost + ". It should be greater than or equal to 0.");
106+  }
107+  if (salvage < 0) {
108+    throw new CellError(ERRORS.NUM_ERROR, "Function DDB parameter 2 value is "
109+      + salvage + ". It should be greater than or equal to 0.");
110+  }
111+  if (life < 0) {
112+    throw new CellError(ERRORS.NUM_ERROR, "Function DDB parameter 3 value is "
113+      + life + ". It should be greater than or equal to 0.");
114+  }
115+  if (period < 0) {
116+    throw new CellError(ERRORS.NUM_ERROR, "Function DDB parameter 4 value is "
117+      + period + ". It should be greater than or equal to 0.");
118+  }
119+  if (period > life) {
120+    throw new CellError(ERRORS.NUM_ERROR, "Function DDB parameter 4 value is "
121+      + life + ". It should be less than or equal to value of Function DB parameter 3 with "+ period +".");
122+  }
123+  if (salvage >= cost) {
124+    return 0;
125+  }
126+
127+  var total = 0;
128+  var current = 0;
129+  for (var i = 1; i <= period; i++) {
130+    current = Math.min((cost - total) * (factor / life), (cost - salvage - total));
131+    total += current;
132+  }
133+  return current;
134+};
135+
136+
137+/**
138+ * Calculates the depreciation of an asset for a specified period using the arithmetic declining balance method.
139+ * @param values[0] cost - The initial cost of the asset.
140+ * @param values[1] salvage - The value of the asset at the end of depreciation.
141+ * @param values[2] life - The number of periods over which the asset is depreciated.
142+ * @param values[3] period - The single period within life for which to calculate depreciation.
143+ * @param values[4] month - [ OPTIONAL - 12 by default ] - The number of months in the first year of depreciation.
144+ * @returns {number} depreciated value
145+ * @constructor
146+ */
147+var DB = function (...values) : number {
148+  ArgsChecker.checkLengthWithin(values, 4, 5);
149+  var cost = TypeCaster.firstValueAsNumber(values[0]);
150+  var salvage = TypeCaster.firstValueAsNumber(values[1]);
151+  var life = TypeCaster.firstValueAsNumber(values[2]);
152+  var period = TypeCaster.firstValueAsNumber(values[3]);
153+  var month = values.length === 5 ? Math.floor(TypeCaster.firstValueAsNumber(values[4])) : 12;
154+  if (cost < 0) {
155+    throw new CellError(ERRORS.NUM_ERROR, "Function DB parameter 1 value is "
156+      + cost + ". It should be greater than or equal to 0.");
157+  }
158+  if (salvage < 0) {
159+    throw new CellError(ERRORS.NUM_ERROR, "Function DB parameter 2 value is "
160+      + salvage + ". It should be greater than or equal to 0.");
161+  }
162+  if (life < 0) {
163+    throw new CellError(ERRORS.NUM_ERROR, "Function DB parameter 3 value is "
164+      + life + ". It should be greater than or equal to 0.");
165+  }
166+  if (period < 0) {
167+    throw new CellError(ERRORS.NUM_ERROR, "Function DB parameter 4 value is "
168+      + period + ". It should be greater than or equal to 0.");
169+  }
170+  if (month > 12 || month < 1) {
171+    throw new CellError(ERRORS.NUM_ERROR, "Function DB parameter 5 value is "
172+      + month + ". Valid values are between 1 and 12 inclusive.");
173+  }
174+  if (period > life) {
175+    throw new CellError(ERRORS.NUM_ERROR, "Function DB parameter 4 value is "
176+      + life + ". It should be less than or equal to value of Function DB parameter 3 with "+ period +".");
177+  }
178+  if (salvage >= cost) {
179+    return 0;
180+  }
181+  var rate = (1 - Math.pow(salvage / cost, 1 / life));
182+  var initial = cost * rate * month / 12;
183+  var total = initial;
184+  var current = 0;
185+  var ceiling = (period === life) ? life - 1 : period;
186+  for (var i = 2; i <= ceiling; i++) {
187+    current = (cost - total) * rate;
188+    total += current;
189+  }
190+  if (period === 1) {
191+    return initial;
192+  } else if (period === life) {
193+    return (cost - total) * rate;
194+  } else {
195+    return current;
196+  }
197+};
198+
199+
200+
201+/**
202+ * Calculates the sum of the sums of the squares of values in two arrays.
203+ * @param values[0] array_x - The array or range of values whose squares will be added to the squares of corresponding
204+ * entries in array_y and added together.
205+ * @param values[1] array_y - The array or range of values whose squares will be added to the squares of corresponding
206+ * entries in array_x and added together.
207+ * @returns {number} sum of the sums of the squares
208+ * @constructor
209+ */
210+var SUMX2PY2 = function (...values) : number {
211+  ArgsChecker.checkLength(values, 2);
212+  var arrOne = Filter.flattenAndThrow(values[0]);
213+  var arrTwo = Filter.flattenAndThrow(values[1]);
214+  if (arrOne.length !== arrTwo.length) {
215+    throw new CellError(ERRORS.NA_ERROR, "Array arguments to SUMX2PY2 are of different size.");
216+  }
217+  var result = 0;
218+  for (var i = 0; i < arrOne.length; i++) {
219+    // If either values at this index are anything but numbers, skip them. This is the behavior in GS at least.
220+    if (typeof arrOne[i] === "number" && typeof arrTwo[i] === "number") {
221+      result += arrOne[i] * arrOne[i] + arrTwo[i] * arrTwo[i];
222+    }
223+  }
224+  return result;
225+};
226+
227+/**
228+ * Calculates the sum of the differences of the squares of values in two arrays.
229+ * @param values[0] array_x - The array or range of values whose squares will be reduced by the squares of corresponding
230+ * entries in array_y and added together.
231+ * @param values[1] array_y - The array or range of values whose squares will be subtracted from the squares of
232+ * corresponding entries in array_x and added together.
233+ * @returns {number} sum of the differences of the squares
234+ * @constructor
235+ */
236+var SUMX2MY2 = function (...values) : number {
237+  ArgsChecker.checkLength(values, 2);
238+  var arrOne = Filter.flattenAndThrow(values[0]);
239+  var arrTwo = Filter.flattenAndThrow(values[1]);
240+  if (arrOne.length !== arrTwo.length) {
241+    throw new CellError(ERRORS.NA_ERROR, "Array arguments to SUMX2MY2 are of different size.");
242+  }
243+  var result = 0;
244+  for (var i = 0; i < arrOne.length; i++) {
245+    // If either values at this index are anything but numbers, skip them. This is the behavior in GS at least.
246+    if (typeof arrOne[i] === "number" && typeof arrTwo[i] === "number") {
247+      result += arrOne[i] * arrOne[i] - arrTwo[i] * arrTwo[i];
248+    }
249+  }
250+  return result;
251+};
252+
253+
254+/**
255+ * Counts the number of unique values in a list of specified values and ranges.
256+ * @param values The values or ranges to consider for uniqueness. Supports an arbitrary number of arguments for this
257+ * function.
258+ * @returns {number} of unique values passed in.
259+ * @constructor
260+ */
261+var COUNTUNIQUE = function (...values) : number {
262+  ArgsChecker.checkAtLeastLength(values, 1);
263+
264+  // Private function that will recursively generate an array of the unique primatives
265+  var countUniquePrivate = function (values: Array<any>) : Object {
266+    var uniques = {};
267+    for (var i = 0; i < values.length; i++) {
268+      if (Array.isArray(values[i])) {
269+        // For some reasons an empty range is converted to a range with a single empty string in it.
270+        if (values[i].length === 0) {
271+          values[i] = [""];
272+        }
273+        var uniquesOfArray = countUniquePrivate(values[i]);
274+        for (var key in uniquesOfArray) {
275+          uniques[key] = true;
276+        }
277+      } else {
278+        uniques[Serializer.serialize(values[i])] = true;
279+      }
280+    }
281+    return uniques;
282+  };
283+
284+  var uniques = countUniquePrivate(values);
285+  return Object.keys(uniques).length;
286+};
287+
288+
289+/**
290+ * Calculates the sum of the products of corresponding entries in two equal-sized arrays or ranges.
291+ * @param values Arrays or ranges whose entries will be multiplied with corresponding entries in the second such array
292+ * or range.
293+ * @returns {number} sum of the products
294+ * @constructor
295+ */
296+var SUMPRODUCT = function (...values) : number {
297+  ArgsChecker.checkAtLeastLength(values, 1);
298+  // Ensuring that all values are array values
299+  for (var x = 0; x < values.length; x++) {
300+    if (!Array.isArray(values[x])) {
301+      values[x] = [values[x]];
302+    }
303+  }
304+
305+  // Flatten any nested ranges (arrays) and check for mismatched range sizes
306+  var flattenedValues = [Filter.flattenAndThrow(values[0])];
307+  for (var x = 1; x < values.length; x++) {
308+    flattenedValues.push(Filter.flattenAndThrow(values[x]));
309+    if (flattenedValues[x].length !== flattenedValues[0].length) {
310+      throw new CellError(ERRORS.VALUE_ERROR, "SUMPRODUCT has mismatched range sizes. Expected count: "
311+        + flattenedValues[0].length + ". Actual count: " + flattenedValues[0].length + ".");
312+    }
313+  }
314+
315+  // Do the actual math
316+  var result = 0;
317+  for (var i = 0; i < flattenedValues[0].length; i++) {
318+    var product = 1;
319+    for (var x = 0; x < flattenedValues.length; x++) {
320+      product *= TypeCaster.valueToNumberGracefully(flattenedValues[x][i]);
321+    }
322+    result += product;
323+  }
324+  return result;
325+};
326+
327+
328+
329+/**
330+ * Returns the Fisher transformation of a specified value.
331+ * @param values[0] value - The value for which to calculate the Fisher transformation.
332+ * @returns {number} Fisher transformation
333+ * @constructor
334+ */
335+var FISHER = function (...values) : number {
336+  ArgsChecker.checkLength(values, 1);
337+  var x = TypeCaster.firstValueAsNumber(values[0]);
338+  if (x <= -1 || x >= 1) {
339+    throw new CellError(ERRORS.NUM_ERROR, "Function FISHER parameter 1 value is " + x + ". Valid values are between -1 and 1 exclusive.");
340+  }
341+  return Math.log((1 + x) / (1 - x)) / 2;
342+};
343+
344+/**
345+ * Returns the inverse Fisher transformation of a specified value.
346+ * @param values[0] value - The value for which to calculate the inverse Fisher transformation.
347+ * @returns {number} inverse Fisher transformation
348+ * @constructor
349+ */
350+var FISHERINV = function (...values) : number {
351+  ArgsChecker.checkLength(values, 1);
352+  var y = TypeCaster.firstValueAsNumber(values[0]);
353+  var e2y = Math.exp(2 * y);
354+  return (e2y - 1) / (e2y + 1);
355+};
356+
357 
358 export {
359   ABS,
360@@ -1327,9 +1666,16 @@ export {
361   COTH,
362   COSH,
363   COS,
364+  COUNTUNIQUE,
365   DEVSQ,
366+  DB,
367+  DDB,
368   EVEN,
369+  ERF,
370+  ERFC,
371   FDIST$LEFTTAILED,
372+  FISHER,
373+  FISHERINV,
374   INT,
375   ISEVEN,
376   ISODD,
377@@ -1356,7 +1702,11 @@ export {
378   ROUND,
379   ROUNDDOWN,
380   ROUNDUP,
381+  SUMPRODUCT,
382   SUMIF,
383+  SUMSQ,
384+  SUMX2MY2,
385+  SUMX2PY2,
386   FLOOR,
387   IF,
388   DELTA,
389@@ -1365,7 +1715,6 @@ export {
390   COUNTIF,
391   COUNTIFS,
392   CEILING,
393-  SUMSQ,
394   TRUNC,
395   RADIANS,
396   DEGREES
397diff --git a/src/RawFormulas/RawFormulas.ts b/src/RawFormulas/RawFormulas.ts
398index c98e1c2..28896e6 100644
399--- a/src/RawFormulas/RawFormulas.ts
400+++ b/src/RawFormulas/RawFormulas.ts
401@@ -19,9 +19,16 @@ import {
402   COTH,
403   COSH,
404   COS,
405+  COUNTUNIQUE,
406   DEVSQ,
407+  DB,
408+  DDB,
409   EVEN,
410+  ERF,
411+  ERFC,
412   FDIST$LEFTTAILED,
413+  FISHER,
414+  FISHERINV,
415   INT,
416   ISEVEN,
417   ISODD,
418@@ -48,7 +55,11 @@ import {
419   ROUND,
420   ROUNDDOWN,
421   ROUNDUP,
422+  SUMPRODUCT,
423   SUMIF,
424+  SUMSQ,
425+  SUMX2MY2,
426+  SUMX2PY2,
427   FLOOR,
428   IF,
429   DELTA,
430@@ -57,7 +68,6 @@ import {
431   COUNTIF,
432   COUNTIFS,
433   CEILING,
434-  SUMSQ,
435   TRUNC,
436   RADIANS,
437   DEGREES
438@@ -92,7 +102,6 @@ import {
439 } from "./Utils";
440 import {CellError, NUM_ERROR} from "../Errors"
441 import * as ERRORS from "../Errors"
442-import {Cell} from "../Cell";
443 
444 var ACCRINT = Formula["ACCRINT"];
445 var COMBIN = Formula["COMBIN"];
446@@ -128,347 +137,6 @@ var __COMPLEX = {
447 var YEARFRAC = Formula["YEARFRAC"];
448 
449 
450-/**
451- * Returns the complementary Gauss error function of a value.
452- * @param values[0] The number for which to calculate the complementary Gauss error function.
453- * @returns {number} complementary Gauss error function of a value
454- * @constructor
455- */
456-var ERFC = function (...values) {
457-  ArgsChecker.checkLength(values, 1);
458-  var v = TypeCaster.firstValueAsNumber(values[0]);
459-  return v === 0 ? 1 : 1 - erf(v);
460-};
461-
462-
463-
464-/**
465- * Returns the error function integrated between lower_limit and upper_limit.
466- * @param values[0] lower_limit - The lower bound for integrating ERF.
467- * @param values[1] upper_limit - [Optional]. The upper bound for integrating ERF. If omitted, ERF integrates between
468- * zero and lower_limit.
469- * @returns {number} error function integrated between lower_limit and upper_limit
470- * @constructor
471- */
472-var ERF = function (...values) : number {
473-  ArgsChecker.checkLengthWithin(values, 1, 2);
474-  var lower = TypeCaster.firstValueAsNumber(values[0]);
475-  var upper = values.length === 2 ? TypeCaster.firstValueAsNumber(values[1]) : 0;
476-  return values.length === 1 ? erf(lower) : erf(upper) - erf(lower);
477-};
478-
479-// erf function from jStat [http://www.jstat.org/]
480-function erf(x) {
481-  var cof = [-1.3026537197817094, 6.4196979235649026e-1, 1.9476473204185836e-2,
482-    -9.561514786808631e-3, -9.46595344482036e-4, 3.66839497852761e-4,
483-    4.2523324806907e-5, -2.0278578112534e-5, -1.624290004647e-6,
484-    1.303655835580e-6, 1.5626441722e-8, -8.5238095915e-8,
485-    6.529054439e-9, 5.059343495e-9, -9.91364156e-10,
486-    -2.27365122e-10, 9.6467911e-11, 2.394038e-12,
487-    -6.886027e-12, 8.94487e-13, 3.13092e-13,
488-    -1.12708e-13, 3.81e-16, 7.106e-15,
489-    -1.523e-15, -9.4e-17, 1.21e-16,
490-    -2.8e-17];
491-  var j = cof.length - 1;
492-  var isneg = false;
493-  var d = 0;
494-  var dd = 0;
495-  var t, ty, tmp, res;
496-
497-  if (x < 0) {
498-    x = -x;
499-    isneg = true;
500-  }
501-
502-  t = 2 / (2 + x);
503-  ty = 4 * t - 2;
504-
505-  for(; j > 0; j--) {
506-    tmp = d;
507-    d = ty * d - dd + cof[j];
508-    dd = tmp;
509-  }
510-
511-  res = t * Math.exp(-x * x + 0.5 * (cof[0] + ty * d) - dd);
512-  return isneg ? res - 1 : 1 - res;
513-}
514-
515-
516-
517-/**
518- * Calculates the depreciation of an asset for a specified period using the double-declining balance method.
519- * @param values[0] cost - The initial cost of the asset.
520- * @param values[1] salvage - The value of the asset at the end of depreciation.
521- * @param values[2] life - The number of periods over which the asset is depreciated.
522- * @param values[3] period - The single period within life for which to calculate depreciation.
523- * @param values[4] factor - [ OPTIONAL - 2 by default ] - The factor by which depreciation decreases.
524- * @returns {number} depreciation of an asset for a specified period
525- * @constructor
526- */
527-var DDB = function (...values) : number {
528-  ArgsChecker.checkLengthWithin(values, 4, 5);
529-  var cost = TypeCaster.firstValueAsNumber(values[0]);
530-  var salvage = TypeCaster.firstValueAsNumber(values[1]);
531-  var life = TypeCaster.firstValueAsNumber(values[2]);
532-  var period = TypeCaster.firstValueAsNumber(values[3]);
533-  var factor = values.length === 5 ? TypeCaster.firstValueAsNumber(values[4]) : 2;
534-
535-  if (cost < 0) {
536-    throw new CellError(ERRORS.NUM_ERROR, "Function DDB parameter 1 value is "
537-      + cost + ". It should be greater than or equal to 0.");
538-  }
539-  if (salvage < 0) {
540-    throw new CellError(ERRORS.NUM_ERROR, "Function DDB parameter 2 value is "
541-      + salvage + ". It should be greater than or equal to 0.");
542-  }
543-  if (life < 0) {
544-    throw new CellError(ERRORS.NUM_ERROR, "Function DDB parameter 3 value is "
545-      + life + ". It should be greater than or equal to 0.");
546-  }
547-  if (period < 0) {
548-    throw new CellError(ERRORS.NUM_ERROR, "Function DDB parameter 4 value is "
549-      + period + ". It should be greater than or equal to 0.");
550-  }
551-  if (period > life) {
552-    throw new CellError(ERRORS.NUM_ERROR, "Function DDB parameter 4 value is "
553-      + life + ". It should be less than or equal to value of Function DB parameter 3 with "+ period +".");
554-  }
555-  if (salvage >= cost) {
556-    return 0;
557-  }
558-
559-  var total = 0;
560-  var current = 0;
561-  for (var i = 1; i <= period; i++) {
562-    current = Math.min((cost - total) * (factor / life), (cost - salvage - total));
563-    total += current;
564-  }
565-  return current;
566-};
567-
568-
569-/**
570- * Calculates the depreciation of an asset for a specified period using the arithmetic declining balance method.
571- * @param values[0] cost - The initial cost of the asset.
572- * @param values[1] salvage - The value of the asset at the end of depreciation.
573- * @param values[2] life - The number of periods over which the asset is depreciated.
574- * @param values[3] period - The single period within life for which to calculate depreciation.
575- * @param values[4] month - [ OPTIONAL - 12 by default ] - The number of months in the first year of depreciation.
576- * @returns {number} depreciated value
577- * @constructor
578- */
579-var DB = function (...values) : number {
580-  ArgsChecker.checkLengthWithin(values, 4, 5);
581-  var cost = TypeCaster.firstValueAsNumber(values[0]);
582-  var salvage = TypeCaster.firstValueAsNumber(values[1]);
583-  var life = TypeCaster.firstValueAsNumber(values[2]);
584-  var period = TypeCaster.firstValueAsNumber(values[3]);
585-  var month = values.length === 5 ? Math.floor(TypeCaster.firstValueAsNumber(values[4])) : 12;
586-  if (cost < 0) {
587-    throw new CellError(ERRORS.NUM_ERROR, "Function DB parameter 1 value is "
588-      + cost + ". It should be greater than or equal to 0.");
589-  }
590-  if (salvage < 0) {
591-    throw new CellError(ERRORS.NUM_ERROR, "Function DB parameter 2 value is "
592-      + salvage + ". It should be greater than or equal to 0.");
593-  }
594-  if (life < 0) {
595-    throw new CellError(ERRORS.NUM_ERROR, "Function DB parameter 3 value is "
596-      + life + ". It should be greater than or equal to 0.");
597-  }
598-  if (period < 0) {
599-    throw new CellError(ERRORS.NUM_ERROR, "Function DB parameter 4 value is "
600-      + period + ". It should be greater than or equal to 0.");
601-  }
602-  if (month > 12 || month < 1) {
603-    throw new CellError(ERRORS.NUM_ERROR, "Function DB parameter 5 value is "
604-      + month + ". Valid values are between 1 and 12 inclusive.");
605-  }
606-  if (period > life) {
607-    throw new CellError(ERRORS.NUM_ERROR, "Function DB parameter 4 value is "
608-      + life + ". It should be less than or equal to value of Function DB parameter 3 with "+ period +".");
609-  }
610-  if (salvage >= cost) {
611-    return 0;
612-  }
613-  var rate = (1 - Math.pow(salvage / cost, 1 / life));
614-  var initial = cost * rate * month / 12;
615-  var total = initial;
616-  var current = 0;
617-  var ceiling = (period === life) ? life - 1 : period;
618-  for (var i = 2; i <= ceiling; i++) {
619-    current = (cost - total) * rate;
620-    total += current;
621-  }
622-  if (period === 1) {
623-    return initial;
624-  } else if (period === life) {
625-    return (cost - total) * rate;
626-  } else {
627-    return current;
628-  }
629-};
630-
631-
632-
633-/**
634- * Calculates the sum of the sums of the squares of values in two arrays.
635- * @param values[0] array_x - The array or range of values whose squares will be added to the squares of corresponding
636- * entries in array_y and added together.
637- * @param values[1] array_y - The array or range of values whose squares will be added to the squares of corresponding
638- * entries in array_x and added together.
639- * @returns {number} sum of the sums of the squares
640- * @constructor
641- */
642-var SUMX2PY2 = function (...values) : number {
643-  ArgsChecker.checkLength(values, 2);
644-  var arrOne = Filter.flattenAndThrow(values[0]);
645-  var arrTwo = Filter.flattenAndThrow(values[1]);
646-  if (arrOne.length !== arrTwo.length) {
647-    throw new CellError(ERRORS.NA_ERROR, "Array arguments to SUMX2PY2 are of different size.");
648-  }
649-  var result = 0;
650-  for (var i = 0; i < arrOne.length; i++) {
651-    // If either values at this index are anything but numbers, skip them. This is the behavior in GS at least.
652-    if (typeof arrOne[i] === "number" && typeof arrTwo[i] === "number") {
653-      result += arrOne[i] * arrOne[i] + arrTwo[i] * arrTwo[i];
654-    }
655-  }
656-  return result;
657-};
658-
659-/**
660- * Calculates the sum of the differences of the squares of values in two arrays.
661- * @param values[0] array_x - The array or range of values whose squares will be reduced by the squares of corresponding
662- * entries in array_y and added together.
663- * @param values[1] array_y - The array or range of values whose squares will be subtracted from the squares of
664- * corresponding entries in array_x and added together.
665- * @returns {number} sum of the differences of the squares
666- * @constructor
667- */
668-var SUMX2MY2 = function (...values) : number {
669-  ArgsChecker.checkLength(values, 2);
670-  var arrOne = Filter.flattenAndThrow(values[0]);
671-  var arrTwo = Filter.flattenAndThrow(values[1]);
672-  if (arrOne.length !== arrTwo.length) {
673-    throw new CellError(ERRORS.NA_ERROR, "Array arguments to SUMX2MY2 are of different size.");
674-  }
675-  var result = 0;
676-  for (var i = 0; i < arrOne.length; i++) {
677-    // If either values at this index are anything but numbers, skip them. This is the behavior in GS at least.
678-    if (typeof arrOne[i] === "number" && typeof arrTwo[i] === "number") {
679-      result += arrOne[i] * arrOne[i] - arrTwo[i] * arrTwo[i];
680-    }
681-  }
682-  return result;
683-};
684-
685-
686-/**
687- * Counts the number of unique values in a list of specified values and ranges.
688- * @param values The values or ranges to consider for uniqueness. Supports an arbitrary number of arguments for this
689- * function.
690- * @returns {number} of unique values passed in.
691- * @constructor
692- */
693-var COUNTUNIQUE = function (...values) : number {
694-  ArgsChecker.checkAtLeastLength(values, 1);
695-
696-  // Private function that will recursively generate an array of the unique primatives
697-  var countUniquePrivate = function (values: Array<any>) : Object {
698-    var uniques = {};
699-    for (var i = 0; i < values.length; i++) {
700-      if (Array.isArray(values[i])) {
701-        // For some reasons an empty range is converted to a range with a single empty string in it.
702-        if (values[i].length === 0) {
703-          values[i] = [""];
704-        }
705-        var uniquesOfArray = countUniquePrivate(values[i]);
706-        for (var key in uniquesOfArray) {
707-          uniques[key] = true;
708-        }
709-      } else {
710-        uniques[Serializer.serialize(values[i])] = true;
711-      }
712-    }
713-    return uniques;
714-  };
715-
716-  var uniques = countUniquePrivate(values);
717-  return Object.keys(uniques).length;
718-};
719-
720-
721-/**
722- * Calculates the sum of the products of corresponding entries in two equal-sized arrays or ranges.
723- * @param values Arrays or ranges whose entries will be multiplied with corresponding entries in the second such array
724- * or range.
725- * @returns {number} sum of the products
726- * @constructor
727- */
728-var SUMPRODUCT = function (...values) : number {
729-  ArgsChecker.checkAtLeastLength(values, 1);
730-  // Ensuring that all values are array values
731-  for (var x = 0; x < values.length; x++) {
732-    if (!Array.isArray(values[x])) {
733-      values[x] = [values[x]];
734-    }
735-  }
736-
737-  // Flatten any nested ranges (arrays) and check for mismatched range sizes
738-  var flattenedValues = [Filter.flattenAndThrow(values[0])];
739-  for (var x = 1; x < values.length; x++) {
740-    flattenedValues.push(Filter.flattenAndThrow(values[x]));
741-    if (flattenedValues[x].length !== flattenedValues[0].length) {
742-      throw new CellError(ERRORS.VALUE_ERROR, "SUMPRODUCT has mismatched range sizes. Expected count: "
743-        + flattenedValues[0].length + ". Actual count: " + flattenedValues[0].length + ".");
744-    }
745-  }
746-
747-  // Do the actual math
748-  var result = 0;
749-  for (var i = 0; i < flattenedValues[0].length; i++) {
750-    var product = 1;
751-    for (var x = 0; x < flattenedValues.length; x++) {
752-      product *= TypeCaster.valueToNumberGracefully(flattenedValues[x][i]);
753-    }
754-    result += product;
755-  }
756-  return result;
757-};
758-
759-
760-
761-/**
762- * Returns the Fisher transformation of a specified value.
763- * @param values[0] value - The value for which to calculate the Fisher transformation.
764- * @returns {number} Fisher transformation
765- * @constructor
766- */
767-var FISHER = function (...values) : number {
768-  ArgsChecker.checkLength(values, 1);
769-  var x = TypeCaster.firstValueAsNumber(values[0]);
770-  if (x <= -1 || x >= 1) {
771-    throw new CellError(ERRORS.NUM_ERROR, "Function FISHER parameter 1 value is " + x + ". Valid values are between -1 and 1 exclusive.");
772-  }
773-  return Math.log((1 + x) / (1 - x)) / 2;
774-};
775-
776-/**
777- * Returns the inverse Fisher transformation of a specified value.
778- * @param values[0] value - The value for which to calculate the inverse Fisher transformation.
779- * @returns {number} inverse Fisher transformation
780- * @constructor
781- */
782-var FISHERINV = function (...values) : number {
783-  ArgsChecker.checkLength(values, 1);
784-  var y = TypeCaster.firstValueAsNumber(values[0]);
785-  var e2y = Math.exp(2 * y);
786-  return (e2y - 1) / (e2y + 1);
787-};
788-
789-
790-
791 
792 export {
793   __COMPLEX,