commit
message
Refactoring formulas into files
author
Ben Vogt <[email protected]>
date
2017-02-16 01:29:57
stats
2 file(s) changed,
342 insertions(+),
419 deletions(-)
files
src/RawFormulas/Math.ts
src/RawFormulas/RawFormulas.ts
1diff --git a/src/RawFormulas/Math.ts b/src/RawFormulas/Math.ts
2index 7785894..2ae9e1e 100644
3--- a/src/RawFormulas/Math.ts
4+++ b/src/RawFormulas/Math.ts
5@@ -1,5 +1,5 @@
6 import { checkArgumentsLength, checkArgumentsAtLeastLength, valueToNumber, filterOutStringValues, flatten,
7- stringValuesToZeros, firstValueAsNumber, valueToBoolean} from "./Utils"
8+ stringValuesToZeros, firstValueAsNumber, valueToBoolean, checkArgumentsAtWithin, CriteriaFunctionFactory, valueCanCoerceToNumber} from "./Utils"
9 import { CellError } from "../Errors"
10 import * as ERRORS from "../Errors"
11
12@@ -711,6 +711,326 @@ var TANH = function (...values) : number {
13 return Math["tanh"](rad);
14 };
15
16+/**
17+ * Returns the average of a range depending on criteria.
18+ * @param values[0] criteria_range - The range to check against criterion.
19+ * @param values[1] criterion - The pattern or test to apply to criteria_range.
20+ * @param values[2] average_range - [optional] The range to average. If not included, criteria_range is used for the
21+ * average instead.
22+ * @returns {number}
23+ * @constructor
24+ * TODO: This needs to take nested range values.
25+ * TODO: This needs to also accept a third parameter "average_range"
26+ */
27+var AVERAGEIF = function (...values) {
28+ checkArgumentsLength(values, 2);
29+ var range = values[0];
30+ var criteriaEvaluation = CriteriaFunctionFactory.createCriteriaFunction(values[1]);
31+
32+ var result = 0;
33+ var count = 0;
34+ for (var i = 0; i < range.length; i++) {
35+ var val = valueToNumber(range[i]);
36+ if (criteriaEvaluation(val)) {
37+ result = result + val;
38+ count++;
39+ }
40+ }
41+ if (count === 0) {
42+ throw new CellError(ERRORS.DIV_ZERO_ERROR, "Evaluation of function AVERAGEIF caused a divide by zero error.");
43+ }
44+ return result / count;
45+};
46+
47+/**
48+ * Rounds a number up to the nearest integer multiple of specified significance.
49+ * @param values[0] The value to round up to the nearest integer multiple of factor.
50+ * @param values[1] The number to whose multiples value will be rounded.
51+ * @returns {number}
52+ * @constructor
53+ */
54+var CEILING = function (...values) : number {
55+ checkArgumentsAtWithin(values, 1, 2);
56+ var num = firstValueAsNumber(values[0]);
57+ if (values.length === 1) {
58+ return Math.ceil(num);
59+ }
60+ var significance = firstValueAsNumber(values[1]);
61+ if (significance === 0) {
62+ throw new CellError(ERRORS.DIV_ZERO_ERROR, "Function CEILING parameter 2 cannot be zero.");
63+ }
64+ var precision = -Math.floor(Math.log(significance) / Math.log(10));
65+ if (num >= 0) {
66+ return ROUND(Math.ceil(num / significance) * significance, precision);
67+ } else {
68+ return -ROUND(Math.floor(Math.abs(num) / significance) * significance, precision);
69+ }
70+};
71+
72+/**
73+ * Rounds a number down to the nearest integer multiple of specified significance.
74+ * @param values[0] The value to round down to the nearest integer multiple of factor.
75+ * @param values[1] The number to whose multiples value will be rounded.
76+ * @returns {number}
77+ * @constructor
78+ */
79+var FLOOR = function (...values) : number {
80+ checkArgumentsAtWithin(values, 1, 2);
81+ var num = firstValueAsNumber(values[0]);
82+ if (values.length === 1) {
83+ return Math.floor(num);
84+ }
85+ var significance = firstValueAsNumber(values[1]);
86+ if (significance === 0) {
87+ throw new CellError(ERRORS.DIV_ZERO_ERROR, "Function FLOOR parameter 2 cannot be zero.");
88+ }
89+ significance = significance ? Math.abs(significance) : 1;
90+ var precision = -Math.floor(Math.log(significance) / Math.log(10));
91+ if (num >= 0) {
92+ return ROUND(Math.floor(num / significance) * significance, precision);
93+ }
94+ return -ROUND(Math.floor(Math.abs(num) / significance) * significance, precision);
95+};
96+
97+/**
98+ * Returns one value if a logical expression is TRUE and another if it is FALSE.
99+ * @param values[0] An expression or reference to a cell containing an expression that represents some logical value, i.e. TRUE or FALSE.
100+ * @param values[1] The value the function returns if logical_expression is TRUE
101+ * @param values[2] The value the function returns if logical_expression is FALSE.
102+ * @returns one value if a logical expression is TRUE and another if it is FALSE.
103+ * @constructor
104+ */
105+var IF = function (...values) : any {
106+ checkArgumentsLength(values, 3);
107+ if (values[0] instanceof Array) {
108+ if (values[0].length === 0) {
109+ throw new CellError(ERRORS.REF_ERROR, "Reference does not exist.");
110+ }
111+ return IF(values[0][0], values[1], values[2]);
112+ } else if (values[0] === "") {
113+ return values[2];
114+ }
115+ return (valueToBoolean(values[0])) ? values[1] : values[2];
116+};
117+
118+/**
119+ * Returns the a count of the number of numeric values in a dataset.
120+ * @param values The values or ranges to consider when counting.
121+ * @returns {number} number of numeric values in a dataset.
122+ * @constructor
123+ */
124+var COUNT = function (...values) : number {
125+ checkArgumentsAtLeastLength(values, 1);
126+ var count = 0;
127+ for (var i = 0; i < values.length; i++) {
128+ if (values[i] instanceof Array) {
129+ if (values[i].length > 0) {
130+ count += COUNT.apply(this, values[i]);
131+ }
132+ } else if (valueCanCoerceToNumber(values[i])) {
133+ count++;
134+ }
135+ }
136+ return count;
137+};
138+
139+/**
140+ * Returns a conditional count across a range.
141+ * @param values[0] range - The range that is tested against criterion., value[1];
142+ * @param values[1] criterion - The pattern or test to apply to range. If the range to check against contains text, this must be a
143+ * string. It can be a comparison based string (e.g. "=1", "<1", ">=1") or it can be a wild-card string, in which *
144+ * matches any number of characters, and ? matches the next character. Both ? and * can be escaped by placing a ~ in
145+ * front of them. If it is neither, it will compared with values in the range using equality comparison.
146+ * @returns {number}
147+ * @constructor
148+ * TODO: This needs to take nested range values.
149+ */
150+var COUNTIF = function (...values) {
151+ checkArgumentsLength(values, 2);
152+ var range = values[0];
153+ var criteria = values[1];
154+
155+ var criteriaEvaluation = CriteriaFunctionFactory.createCriteriaFunction(criteria);
156+
157+ var count = 0;
158+ for (var i = 0; i < range.length; i++) {
159+ var x = range[i];
160+ if (criteriaEvaluation(x)) {
161+ count++;
162+ }
163+ }
164+ return count;
165+};
166+
167+/**
168+ * Returns the count of a range depending on multiple criteria.
169+ * @param values[0] criteria_range1 - The range to check against criterion1.
170+ * @param values[1] criterion1 - The pattern or test to apply to criteria_range1.
171+ * @param values[2...N] Repeated sets of ranges and criterion to check.
172+ * @returns {number} count
173+ * @constructor
174+ * TODO: This needs to take nested range values.
175+ */
176+var COUNTIFS = function (...values) {
177+ checkArgumentsAtLeastLength(values, 2);
178+ var criteriaEvaluationFunctions = values.map(function (criteria, index) {
179+ if (index % 2 === 1) {
180+ return CriteriaFunctionFactory.createCriteriaFunction(criteria);
181+ } else {
182+ return function () {return false;}
183+ }
184+ });
185+
186+ var count = 0;
187+ // For every value in the range
188+ for (var i = 0; i < values[0].length; i++) {
189+ // check for criteria eval for other ranges and other criteria pairs
190+ var otherCriteriaEvaluationSuccessfulSoFar = true;
191+ for (var x = 0; x < values.length; x += 2) {
192+ if (values[x].length < values[0].length) {
193+ throw new CellError(ERRORS.VALUE_ERROR, "Array arguments to COUNTIFS are of different size.");
194+ }
195+ var criteriaEvaluation = criteriaEvaluationFunctions[x+1];
196+ if (otherCriteriaEvaluationSuccessfulSoFar) {
197+ if (!criteriaEvaluation(values[x][i])) { // evaluate THIS value with x+1 index, which is criteria
198+ otherCriteriaEvaluationSuccessfulSoFar = false;
199+ }
200+ }
201+ }
202+ if (otherCriteriaEvaluationSuccessfulSoFar) {
203+ count++;
204+ }
205+ }
206+ return count;
207+};
208+
209+/**
210+ * Returns the a count of the number of values in a dataset.
211+ * @param values The values or ranges to consider when counting.
212+ * @returns {number} number of values in a dataset.
213+ * @constructor
214+ */
215+var COUNTA = function (...values) : number {
216+ checkArgumentsAtLeastLength(values, 1);
217+ var count = 0;
218+ for (var i = 0; i < values.length; i++) {
219+ if (values[i] instanceof Array) {
220+ if (values[i].length > 0) {
221+ count += COUNTA.apply(this, values[i]);
222+ } else {
223+ count++;
224+ }
225+ } else {
226+ count++;
227+ }
228+ }
229+ return count;
230+};
231+
232+/**
233+ * Compare two numeric values, returning 1 if they're equal.
234+ * @param values[0] The first number to compare.
235+ * @param values[1] The second number to compare.
236+ * @returns {number} 1 if they're equal, 0 if they're not equal.
237+ * @constructor
238+ */
239+var DELTA = function (...values) : number {
240+ checkArgumentsAtWithin(values, 1, 2);
241+ if (values.length === 1) {
242+ return valueToNumber(values[0]) === 0 ? 1 : 0;
243+ }
244+ return valueToNumber(values[0]) === valueToNumber(values[1]) ? 1 : 0;
245+};
246+
247+/**
248+ * Rounds a number to a certain number of decimal places according to standard rules.
249+ * @param values[0] The value to round to places number of places.
250+ * @param values[1] The number of decimal places to which to round.
251+ * @returns {number}
252+ * @constructor
253+ */
254+var ROUND = function (...values) {
255+ checkArgumentsAtWithin(values, 1, 2);
256+ var n = firstValueAsNumber(values[0]);
257+ if (values.length === 1) {
258+ return Math.round(n);
259+ }
260+ var d = firstValueAsNumber(values[1]);
261+ return Math.round(n * Math.pow(10, d)) / Math.pow(10, d);
262+};
263+
264+/**
265+ * Rounds a number to a certain number of decimal places, always rounding down to the next valid increment.
266+ * @param values[0] The value to round to places number of places, always rounding down.
267+ * @param values[1] (optional) The number of decimal places to which to round.
268+ * @returns {number}
269+ * @constructor
270+ */
271+var ROUNDDOWN = function (...values) {
272+ checkArgumentsAtWithin(values, 1, 2);
273+ var n = firstValueAsNumber(values[0]);
274+ if (values.length === 1) {
275+ return Math.floor(n);
276+ }
277+ var d = firstValueAsNumber(values[1]);
278+ return Math.floor(n * Math.pow(10, d)) / Math.pow(10, d);
279+};
280+
281+/**
282+ * Rounds a number to a certain number of decimal places, always rounding up to the next valid increment.
283+ * @param values[0] The value to round to places number of places, always rounding up.
284+ * @param values[1] (optional) The number of decimal places to which to round.
285+ * @returns {number}
286+ * @constructor
287+ */
288+var ROUNDUP = function (...values) {
289+ checkArgumentsAtWithin(values, 1, 2);
290+ var n = firstValueAsNumber(values[0]);
291+ if (values.length === 1) {
292+ return Math.ceil(n);
293+ }
294+ var d = firstValueAsNumber(values[1]);
295+ return Math.ceil(n * Math.pow(10, d)) / Math.pow(10, d);
296+};
297+
298+/**
299+ * Returns a conditional sum across a range.
300+ * @param values[0] The range which is tested against criterion.
301+ * @param values[1] The pattern or test to apply to range. If the range to check against contains text, this must be a
302+ * string. It can be a comparison based string (e.g. "=1", "<1", ">=1") or it can be a wild-card string, in which *
303+ * matches any number of characters, and ? matches the next character. Both ? and * can be escaped by placing a ~ in
304+ * front of them.
305+ * @param values[2] (optional) The range to be summed, if different from range.
306+ * @returns {number}
307+ * @constructor
308+ * TODO: This needs to take nested range values.
309+ */
310+var SUMIF = function (...values) {
311+ checkArgumentsAtWithin(values, 2, 3);
312+ var range = values[0];
313+ var criteria = values[1];
314+ var sumRange = null;
315+ if (values.length === 3) {
316+ sumRange = values[2];
317+ }
318+
319+ var criteriaEvaluation = CriteriaFunctionFactory.createCriteriaFunction(criteria);
320+
321+ var sum = 0;
322+ for (var i = 0; i < range.length; i++) {
323+ var x = range[i];
324+ if (sumRange && i > sumRange.length-1) {
325+ continue;
326+ }
327+ if (values.length === 2 && valueCanCoerceToNumber(x) && criteriaEvaluation(x)) {
328+ sum = sum + x;
329+ } else if (values.length === 3 && valueCanCoerceToNumber(sumRange[i]) && criteriaEvaluation(x)) {
330+ sum = sum + sumRange[i];
331+ }
332+ }
333+ return sum;
334+};
335+
336 export {
337 ABS,
338 ACOS,
339@@ -750,5 +1070,18 @@ export {
340 LOG10,
341 LN,
342 TAN,
343- TANH
344+ TANH,
345+ AVERAGEIF,
346+ ROUND,
347+ ROUNDDOWN,
348+ ROUNDUP,
349+ SUMIF,
350+ FLOOR,
351+ IF,
352+ DELTA,
353+ COUNT,
354+ COUNTA,
355+ COUNTIF,
356+ COUNTIFS,
357+ CEILING
358 }
359\ No newline at end of file
360diff --git a/src/RawFormulas/RawFormulas.ts b/src/RawFormulas/RawFormulas.ts
361index 37dccd7..9cfaa95 100644
362--- a/src/RawFormulas/RawFormulas.ts
363+++ b/src/RawFormulas/RawFormulas.ts
364@@ -40,7 +40,20 @@ import {
365 LOG10,
366 LN,
367 TAN,
368- TANH
369+ TANH,
370+ AVERAGEIF,
371+ ROUND,
372+ ROUNDDOWN,
373+ ROUNDUP,
374+ SUMIF,
375+ FLOOR,
376+ IF,
377+ DELTA,
378+ COUNT,
379+ COUNTA,
380+ COUNTIF,
381+ COUNTIFS,
382+ CEILING
383 } from "./Math";
384 import {
385 AND,
386@@ -129,326 +142,6 @@ var SUMX2PY2 = Formula["SUMX2PY2"];
387 var TRUNC = Formula["TRUNC"];
388 var YEARFRAC = Formula["YEARFRAC"];
389
390-/**
391- * Returns the average of a range depending on criteria.
392- * @param values[0] criteria_range - The range to check against criterion.
393- * @param values[1] criterion - The pattern or test to apply to criteria_range.
394- * @param values[2] average_range - [optional] The range to average. If not included, criteria_range is used for the
395- * average instead.
396- * @returns {number}
397- * @constructor
398- * TODO: This needs to take nested range values.
399- * TODO: This needs to also accept a third parameter "average_range"
400- */
401-var AVERAGEIF = function (...values) {
402- checkArgumentsLength(values, 2);
403- var range = values[0];
404- var criteriaEvaluation = CriteriaFunctionFactory.createCriteriaFunction(values[1]);
405-
406- var result = 0;
407- var count = 0;
408- for (var i = 0; i < range.length; i++) {
409- var val = valueToNumber(range[i]);
410- if (criteriaEvaluation(val)) {
411- result = result + val;
412- count++;
413- }
414- }
415- if (count === 0) {
416- throw new CellError(ERRORS.DIV_ZERO_ERROR, "Evaluation of function AVERAGEIF caused a divide by zero error.");
417- }
418- return result / count;
419-};
420-
421-/**
422- * Rounds a number up to the nearest integer multiple of specified significance.
423- * @param values[0] The value to round up to the nearest integer multiple of factor.
424- * @param values[1] The number to whose multiples value will be rounded.
425- * @returns {number}
426- * @constructor
427- */
428-var CEILING = function (...values) : number {
429- checkArgumentsAtWithin(values, 1, 2);
430- var num = firstValueAsNumber(values[0]);
431- if (values.length === 1) {
432- return Math.ceil(num);
433- }
434- var significance = firstValueAsNumber(values[1]);
435- if (significance === 0) {
436- throw new CellError(ERRORS.DIV_ZERO_ERROR, "Function CEILING parameter 2 cannot be zero.");
437- }
438- var precision = -Math.floor(Math.log(significance) / Math.log(10));
439- if (num >= 0) {
440- return ROUND(Math.ceil(num / significance) * significance, precision);
441- } else {
442- return -ROUND(Math.floor(Math.abs(num) / significance) * significance, precision);
443- }
444-};
445-
446-/**
447- * Rounds a number down to the nearest integer multiple of specified significance.
448- * @param values[0] The value to round down to the nearest integer multiple of factor.
449- * @param values[1] The number to whose multiples value will be rounded.
450- * @returns {number}
451- * @constructor
452- */
453-var FLOOR = function (...values) : number {
454- checkArgumentsAtWithin(values, 1, 2);
455- var num = firstValueAsNumber(values[0]);
456- if (values.length === 1) {
457- return Math.floor(num);
458- }
459- var significance = firstValueAsNumber(values[1]);
460- if (significance === 0) {
461- throw new CellError(ERRORS.DIV_ZERO_ERROR, "Function FLOOR parameter 2 cannot be zero.");
462- }
463- significance = significance ? Math.abs(significance) : 1;
464- var precision = -Math.floor(Math.log(significance) / Math.log(10));
465- if (num >= 0) {
466- return ROUND(Math.floor(num / significance) * significance, precision);
467- }
468- return -ROUND(Math.floor(Math.abs(num) / significance) * significance, precision);
469-};
470-
471-/**
472- * Returns one value if a logical expression is TRUE and another if it is FALSE.
473- * @param values[0] An expression or reference to a cell containing an expression that represents some logical value, i.e. TRUE or FALSE.
474- * @param values[1] The value the function returns if logical_expression is TRUE
475- * @param values[2] The value the function returns if logical_expression is FALSE.
476- * @returns one value if a logical expression is TRUE and another if it is FALSE.
477- * @constructor
478- */
479-var IF = function (...values) : any {
480- checkArgumentsLength(values, 3);
481- if (values[0] instanceof Array) {
482- if (values[0].length === 0) {
483- throw new CellError(ERRORS.REF_ERROR, "Reference does not exist.");
484- }
485- return IF(values[0][0], values[1], values[2]);
486- } else if (values[0] === "") {
487- return values[2];
488- }
489- return (valueToBoolean(values[0])) ? values[1] : values[2];
490-};
491-
492-/**
493- * Returns the a count of the number of numeric values in a dataset.
494- * @param values The values or ranges to consider when counting.
495- * @returns {number} number of numeric values in a dataset.
496- * @constructor
497- */
498-var COUNT = function (...values) : number {
499- checkArgumentsAtLeastLength(values, 1);
500- var count = 0;
501- for (var i = 0; i < values.length; i++) {
502- if (values[i] instanceof Array) {
503- if (values[i].length > 0) {
504- count += COUNT.apply(this, values[i]);
505- }
506- } else if (valueCanCoerceToNumber(values[i])) {
507- count++;
508- }
509- }
510- return count;
511-};
512-
513-/**
514- * Returns a conditional count across a range.
515- * @param values[0] range - The range that is tested against criterion., value[1];
516- * @param values[1] criterion - The pattern or test to apply to range. If the range to check against contains text, this must be a
517- * string. It can be a comparison based string (e.g. "=1", "<1", ">=1") or it can be a wild-card string, in which *
518- * matches any number of characters, and ? matches the next character. Both ? and * can be escaped by placing a ~ in
519- * front of them. If it is neither, it will compared with values in the range using equality comparison.
520- * @returns {number}
521- * @constructor
522- * TODO: This needs to take nested range values.
523- */
524-var COUNTIF = function (...values) {
525- checkArgumentsLength(values, 2);
526- var range = values[0];
527- var criteria = values[1];
528-
529- var criteriaEvaluation = CriteriaFunctionFactory.createCriteriaFunction(criteria);
530-
531- var count = 0;
532- for (var i = 0; i < range.length; i++) {
533- var x = range[i];
534- if (criteriaEvaluation(x)) {
535- count++;
536- }
537- }
538- return count;
539-};
540-
541-/**
542- * Returns the count of a range depending on multiple criteria.
543- * @param values[0] criteria_range1 - The range to check against criterion1.
544- * @param values[1] criterion1 - The pattern or test to apply to criteria_range1.
545- * @param values[2...N] Repeated sets of ranges and criterion to check.
546- * @returns {number} count
547- * @constructor
548- * TODO: This needs to take nested range values.
549- */
550-var COUNTIFS = function (...values) {
551- checkArgumentsAtLeastLength(values, 2);
552- var criteriaEvaluationFunctions = values.map(function (criteria, index) {
553- if (index % 2 === 1) {
554- return CriteriaFunctionFactory.createCriteriaFunction(criteria);
555- } else {
556- return function () {return false;}
557- }
558- });
559-
560- var count = 0;
561- // For every value in the range
562- for (var i = 0; i < values[0].length; i++) {
563- // check for criteria eval for other ranges and other criteria pairs
564- var otherCriteriaEvaluationSuccessfulSoFar = true;
565- for (var x = 0; x < values.length; x += 2) {
566- if (values[x].length < values[0].length) {
567- throw new CellError(ERRORS.VALUE_ERROR, "Array arguments to COUNTIFS are of different size.");
568- }
569- var criteriaEvaluation = criteriaEvaluationFunctions[x+1];
570- if (otherCriteriaEvaluationSuccessfulSoFar) {
571- if (!criteriaEvaluation(values[x][i])) { // evaluate THIS value with x+1 index, which is criteria
572- otherCriteriaEvaluationSuccessfulSoFar = false;
573- }
574- }
575- }
576- if (otherCriteriaEvaluationSuccessfulSoFar) {
577- count++;
578- }
579- }
580- return count;
581-};
582-
583-/**
584- * Returns the a count of the number of values in a dataset.
585- * @param values The values or ranges to consider when counting.
586- * @returns {number} number of values in a dataset.
587- * @constructor
588- */
589-var COUNTA = function (...values) : number {
590- checkArgumentsAtLeastLength(values, 1);
591- var count = 0;
592- for (var i = 0; i < values.length; i++) {
593- if (values[i] instanceof Array) {
594- if (values[i].length > 0) {
595- count += COUNTA.apply(this, values[i]);
596- } else {
597- count++;
598- }
599- } else {
600- count++;
601- }
602- }
603- return count;
604-};
605-
606-/**
607- * Compare two numeric values, returning 1 if they're equal.
608- * @param values[0] The first number to compare.
609- * @param values[1] The second number to compare.
610- * @returns {number} 1 if they're equal, 0 if they're not equal.
611- * @constructor
612- */
613-var DELTA = function (...values) : number {
614- checkArgumentsAtWithin(values, 1, 2);
615- if (values.length === 1) {
616- return valueToNumber(values[0]) === 0 ? 1 : 0;
617- }
618- return valueToNumber(values[0]) === valueToNumber(values[1]) ? 1 : 0;
619-};
620-
621-/**
622- * Rounds a number to a certain number of decimal places according to standard rules.
623- * @param values[0] The value to round to places number of places.
624- * @param values[1] The number of decimal places to which to round.
625- * @returns {number}
626- * @constructor
627- */
628-var ROUND = function (...values) {
629- checkArgumentsAtWithin(values, 1, 2);
630- var n = firstValueAsNumber(values[0]);
631- if (values.length === 1) {
632- return Math.round(n);
633- }
634- var d = firstValueAsNumber(values[1]);
635- return Math.round(n * Math.pow(10, d)) / Math.pow(10, d);
636-};
637-
638-/**
639- * Rounds a number to a certain number of decimal places, always rounding down to the next valid increment.
640- * @param values[0] The value to round to places number of places, always rounding down.
641- * @param values[1] (optional) The number of decimal places to which to round.
642- * @returns {number}
643- * @constructor
644- */
645-var ROUNDDOWN = function (...values) {
646- checkArgumentsAtWithin(values, 1, 2);
647- var n = firstValueAsNumber(values[0]);
648- if (values.length === 1) {
649- return Math.floor(n);
650- }
651- var d = firstValueAsNumber(values[1]);
652- return Math.floor(n * Math.pow(10, d)) / Math.pow(10, d);
653-};
654-
655-/**
656- * Rounds a number to a certain number of decimal places, always rounding up to the next valid increment.
657- * @param values[0] The value to round to places number of places, always rounding up.
658- * @param values[1] (optional) The number of decimal places to which to round.
659- * @returns {number}
660- * @constructor
661- */
662-var ROUNDUP = function (...values) {
663- checkArgumentsAtWithin(values, 1, 2);
664- var n = firstValueAsNumber(values[0]);
665- if (values.length === 1) {
666- return Math.ceil(n);
667- }
668- var d = firstValueAsNumber(values[1]);
669- return Math.ceil(n * Math.pow(10, d)) / Math.pow(10, d);
670-};
671-
672-/**
673- * Returns a conditional sum across a range.
674- * @param values[0] The range which is tested against criterion.
675- * @param values[1] The pattern or test to apply to range. If the range to check against contains text, this must be a
676- * string. It can be a comparison based string (e.g. "=1", "<1", ">=1") or it can be a wild-card string, in which *
677- * matches any number of characters, and ? matches the next character. Both ? and * can be escaped by placing a ~ in
678- * front of them.
679- * @param values[2] (optional) The range to be summed, if different from range.
680- * @returns {number}
681- * @constructor
682- * TODO: This needs to take nested range values.
683- */
684-var SUMIF = function (...values) {
685- checkArgumentsAtWithin(values, 2, 3);
686- var range = values[0];
687- var criteria = values[1];
688- var sumRange = null;
689- if (values.length === 3) {
690- sumRange = values[2];
691- }
692-
693- var criteriaEvaluation = CriteriaFunctionFactory.createCriteriaFunction(criteria);
694-
695- var sum = 0;
696- for (var i = 0; i < range.length; i++) {
697- var x = range[i];
698- if (sumRange && i > sumRange.length-1) {
699- continue;
700- }
701- if (values.length === 2 && valueCanCoerceToNumber(x) && criteriaEvaluation(x)) {
702- sum = sum + x;
703- } else if (values.length === 3 && valueCanCoerceToNumber(sumRange[i]) && criteriaEvaluation(x)) {
704- sum = sum + sumRange[i];
705- }
706- }
707- return sum;
708-};
709-
710 export {
711 __COMPLEX,
712