commit
message
[ArgsChecker] passing formula names into ArgsChecker functions to format NAErrors
author
Ben Vogt <[email protected]>
date
2017-05-13 20:31:52
stats
10 file(s) changed,
198 insertions(+),
146 deletions(-)
files
README.md
src/Formulas/Date.ts
src/Formulas/Engineering.ts
src/Formulas/Financial.ts
src/Formulas/Logical.ts
src/Formulas/Math.ts
src/Formulas/Statistical.ts
src/Formulas/Text.ts
src/Utilities/ArgsChecker.ts
tests/Utilities/ArgsCheckerTest.ts
1diff --git a/README.md b/README.md
2index fc59014..a7688b3 100644
3--- a/README.md
4+++ b/README.md
5@@ -25,10 +25,6 @@ http://stackoverflow.com/questions/3446170/escape-string-for-use-in-javascript-r
6 e.g. "SUM expects number values...", or "This function expects number values..."
7
8
9-### Error formatting
10-Pass name of calling formula into all functions that throw user-facing errors, or have some sort of error mapper.
11-
12-
13 ### Cells should have `formatAs` fields.
14 Instead of having non-primitives, (i.e. Date, DateTime, Time, Dollar), cells should have formats based on the
15 highest-order type that was used during the compilation and execution of a cell's dependency. For example, `DATE` might
16@@ -69,6 +65,13 @@ TypeConverter.
17 ### Test CriteriaFunctionFactory
18
19
20+### Use `arguments` instead of `...values` for performance reasons.
21+And use `.call()` when testing with weird param numbers.
22+
23+
24+### Pull static functions outside of formulas, declare once.
25+
26+
27 ### CONVERT could offer more accurate conversions for units in the same system
28 For example 64 tbs to a qt.
29
30diff --git a/src/Formulas/Date.ts b/src/Formulas/Date.ts
31index b09d4ed..2835662 100644
32--- a/src/Formulas/Date.ts
33+++ b/src/Formulas/Date.ts
34@@ -22,7 +22,7 @@ import {
35 */
36 var DATE = function (...values) : number {
37 const FIRST_YEAR = 1900;
38- ArgsChecker.checkLength(values, 3);
39+ ArgsChecker.checkLength(values, 3, "DATE");
40 var year = Math.abs(Math.floor(TypeConverter.firstValueAsNumber(values[0]))); // No negative values for year
41 var month = Math.floor(TypeConverter.firstValueAsNumber(values[1])) - 1; // Months are between 0 and 11.
42 var day = Math.floor(TypeConverter.firstValueAsNumber(values[2])) - 1; // Days are also zero-indexed.
43@@ -48,7 +48,7 @@ var DATE = function (...values) : number {
44 * @constructor
45 */
46 var DATEVALUE = function (...values) : number {
47- ArgsChecker.checkLength(values, 1);
48+ ArgsChecker.checkLength(values, 1, "DATEVALUE");
49 var dateString = TypeConverter.firstValueAsString(values[0]);
50 var dateAsNumber;
51 try {
52@@ -70,7 +70,7 @@ var DATEVALUE = function (...values) : number {
53 * @constructor
54 */
55 var EDATE = function (...values) : number {
56- ArgsChecker.checkLength(values, 2);
57+ ArgsChecker.checkLength(values, 2, "EDATE");
58 var startDateNumber = TypeConverter.firstValueAsDateNumber(values[0], true); // tell firstValueAsDateNumber to coerce boolean
59 if (startDateNumber < 0) {
60 throw new NumError("Function EDATE parameter 1 value is " + startDateNumber+ ". It should be greater than or equal to 0.");
61@@ -92,7 +92,7 @@ var EDATE = function (...values) : number {
62 * @constructor
63 */
64 var EOMONTH = function (...values) : number {
65- ArgsChecker.checkLength(values, 2);
66+ ArgsChecker.checkLength(values, 2, "EOMONTH");
67 var startDateNumber = TypeConverter.firstValueAsDateNumber(values[0], true); // tell firstValueAsDateNumber to coerce boolean
68 if (startDateNumber < 0) {
69 throw new NumError("Function EOMONTH parameter 1 value is " + startDateNumber + ". It should be greater than or equal to 0.");
70@@ -113,7 +113,7 @@ var EOMONTH = function (...values) : number {
71 * @constructor
72 */
73 var DAY = function (...values) : number {
74- ArgsChecker.checkLength(values, 1);
75+ ArgsChecker.checkLength(values, 1, "DAY");
76 var dateNumber = TypeConverter.firstValueAsDateNumber(values[0], true); // tell firstValueAsDateNumber to coerce boolean
77 if (dateNumber < 0) {
78 throw new NumError("Function DAY parameter 1 value is " + dateNumber + ". It should be greater than or equal to 0.");
79@@ -130,7 +130,7 @@ var DAY = function (...values) : number {
80 * @constructor
81 */
82 var DAYS = function (...values) : number {
83- ArgsChecker.checkLength(values, 2);
84+ ArgsChecker.checkLength(values, 2, "DAYS");
85 var end = TypeConverter.firstValueAsDateNumber(values[0], true); // tell firstValueAsDateNumber to coerce boolean
86 var start = TypeConverter.firstValueAsDateNumber(values[1], true); // tell firstValueAsDateNumber to coerce boolean
87 return end - start;
88@@ -154,7 +154,7 @@ var DAYS = function (...values) : number {
89 * @constructor
90 */
91 var DAYS360 = function (...values) : number {
92- ArgsChecker.checkLengthWithin(values, 2, 3);
93+ ArgsChecker.checkLengthWithin(values, 2, 3, "DAYS360");
94 var start = TypeConverter.numberToMoment(TypeConverter.firstValueAsDateNumber(values[0], true)); // tell firstValueAsDateNumber to coerce boolean
95 var end = TypeConverter.numberToMoment(TypeConverter.firstValueAsDateNumber(values[1], true)); // tell firstValueAsDateNumber to coerce boolean
96 var methodToUse = false;
97@@ -193,7 +193,7 @@ var DAYS360 = function (...values) : number {
98 * @constructor
99 */
100 var MONTH = function (...values) : number {
101- ArgsChecker.checkLength(values, 1);
102+ ArgsChecker.checkLength(values, 1, "MONTH");
103 var date = TypeConverter.firstValueAsDateNumber(values[0], true); // tell firstValueAsDateNumber to coerce boolean
104 if (date < 0) {
105 throw new NumError("Function MONTH parameter 1 value is " + date + ". It should be greater than or equal to 0.");
106@@ -210,7 +210,7 @@ var MONTH = function (...values) : number {
107 * @constructor
108 */
109 var YEAR = function (...values) : number {
110- ArgsChecker.checkLength(values, 1);
111+ ArgsChecker.checkLength(values, 1, "YEAR");
112 var date = TypeConverter.firstValueAsDateNumber(values[0], true); // tell firstValueAsDateNumber to coerce boolean
113 if (date < 0) {
114 throw new NumError("Function YEAR parameter 1 value is " + date + ". It should be greater than or equal to 0.");
115@@ -232,7 +232,7 @@ var YEAR = function (...values) : number {
116 * @constructor
117 */
118 var WEEKDAY = function (...values) : number {
119- ArgsChecker.checkLengthWithin(values, 1, 2);
120+ ArgsChecker.checkLengthWithin(values, 1, 2, "WEEKDAY");
121 var date = TypeConverter.firstValueAsDateNumber(values[0], true); // tell firstValueAsDateNumber to coerce boolean
122 var offsetType = values.length === 2 ? TypeConverter.firstValueAsNumber(values[1]) : 1;
123 if (date < 0) {
124@@ -291,7 +291,7 @@ function calculateWeekNum(dm : moment.Moment, shifterArray : Array<number>) : nu
125 * @constructor
126 */
127 var WEEKNUM = function (...values) : number {
128- ArgsChecker.checkLengthWithin(values, 1, 2);
129+ ArgsChecker.checkLengthWithin(values, 1, 2, "WEEKNUM");
130 var date = TypeConverter.firstValueAsDateNumber(values[0], true); // tell firstValueAsDateNumber to coerce boolean
131 var shiftType = values.length === 2 ? TypeConverter.firstValueAsNumber(values[1]) : 1;
132 if (date < 0) {
133@@ -363,7 +363,7 @@ var WEEKNUM = function (...values) : number {
134 * @constructor
135 */
136 var DATEDIF = function (...values) : number {
137- ArgsChecker.checkLength(values, 3);
138+ ArgsChecker.checkLength(values, 3, "DATEDIF");
139 var start = TypeConverter.firstValueAsDateNumber(values[0], true);
140 var end = TypeConverter.firstValueAsDateNumber(values[1], true);
141 var unit = TypeConverter.firstValueAsString(values[2]);
142@@ -432,7 +432,7 @@ var DATEDIF = function (...values) : number {
143 * @constructor
144 */
145 var YEARFRAC = function (...values) : number {
146- ArgsChecker.checkLengthWithin(values, 2, 3);
147+ ArgsChecker.checkLengthWithin(values, 2, 3, "YEARFRAC");
148 var start = TypeConverter.firstValueAsDateNumber(values[0], true);
149 var end = TypeConverter.firstValueAsDateNumber(values[1], true);
150 var basis = values.length === 2 ? 0 : TypeConverter.firstValueAsNumber(values[2]);
151@@ -527,7 +527,7 @@ var YEARFRAC = function (...values) : number {
152 * @constructor
153 */
154 var TIMEVALUE = function (...values) : number {
155- ArgsChecker.checkLength(values, 1);
156+ ArgsChecker.checkLength(values, 1, "TIMEVALUE");
157 var timeString = TypeConverter.firstValueAsString(values[0]);
158 try {
159 return TypeConverter.stringToTimeNumber(timeString);
160@@ -546,7 +546,7 @@ const MILLISECONDS_IN_DAY = 86400000;
161 * @constructor
162 */
163 var HOUR = function (...values) : number {
164- ArgsChecker.checkLength(values, 1);
165+ ArgsChecker.checkLength(values, 1, "HOUR");
166 var time = TypeConverter.firstValueAsTimestampNumber(values[0]);
167 if (time % 1 === 0) {
168 return 0;
169@@ -564,7 +564,7 @@ var HOUR = function (...values) : number {
170 * @constructor
171 */
172 var MINUTE = function (...values) : number {
173- ArgsChecker.checkLength(values, 1);
174+ ArgsChecker.checkLength(values, 1, "MINUTE");
175 var time = TypeConverter.firstValueAsTimestampNumber(values[0]);
176 if (time % 1 === 0) {
177 return 0;
178@@ -581,7 +581,7 @@ var MINUTE = function (...values) : number {
179 * @constructor
180 */
181 var SECOND = function (...values) : number {
182- ArgsChecker.checkLength(values, 1);
183+ ArgsChecker.checkLength(values, 1, "SECOND");
184 var time = TypeConverter.firstValueAsTimestampNumber(values[0]);
185 if (time % 1 === 0) {
186 return 0;
187@@ -603,7 +603,7 @@ var SECOND = function (...values) : number {
188 * @constructor
189 */
190 var NETWORKDAYS = function (...values) : number {
191- ArgsChecker.checkLengthWithin(values, 2, 3);
192+ ArgsChecker.checkLengthWithin(values, 2, 3, "NETWORKDAYS");
193 var start = TypeConverter.firstValueAsDateNumber(values[0], true);
194 var end = TypeConverter.firstValueAsDateNumber(values[1], true);
195 var hasHolidays = values.length === 3;
196@@ -669,7 +669,7 @@ var NETWORKDAYS = function (...values) : number {
197 * @constructor
198 */
199 var NETWORKDAYS$INTL = function (...values) : number {
200- ArgsChecker.checkLengthWithin(values, 2, 4);
201+ ArgsChecker.checkLengthWithin(values, 2, 4, "NETWORKDAYS$INTL");
202 var start = TypeConverter.firstValueAsDateNumber(values[0], true);
203 var end = TypeConverter.firstValueAsDateNumber(values[1], true);
204 var weekendDays = [];
205@@ -768,7 +768,7 @@ var NETWORKDAYS$INTL = function (...values) : number {
206 * @constructor
207 */
208 var NOW = function (...values) : number {
209- ArgsChecker.checkLength(values, 0);
210+ ArgsChecker.checkLength(values, 0, "NOW");
211 return TypeConverter.momentToNumber(moment.utc());
212 };
213
214@@ -778,7 +778,7 @@ var NOW = function (...values) : number {
215 * @constructor
216 */
217 var TODAY = function (...values) : number {
218- ArgsChecker.checkLength(values, 0);
219+ ArgsChecker.checkLength(values, 0, "TODAY");
220 return TypeConverter.momentToNumber(moment.utc().startOf("day"));
221 };
222
223@@ -793,7 +793,7 @@ var TODAY = function (...values) : number {
224 * @constructor
225 */
226 var TIME = function (...values) : number {
227- ArgsChecker.checkLength(values, 3);
228+ ArgsChecker.checkLength(values, 3, "TIME");
229 var hours = Math.floor(TypeConverter.firstValueAsNumber(values[0]));
230 var minutes = Math.floor(TypeConverter.firstValueAsNumber(values[1]));
231 var seconds = Math.floor(TypeConverter.firstValueAsNumber(values[2]));
232@@ -818,7 +818,7 @@ var TIME = function (...values) : number {
233 * @constructor
234 */
235 var WORKDAY = function (...values) : number {
236- ArgsChecker.checkLengthWithin(values, 2, 3);
237+ ArgsChecker.checkLengthWithin(values, 2, 3, "WORKDAY");
238 var start = TypeConverter.firstValueAsDateNumber(values[0], true);
239 var days = TypeConverter.firstValueAsNumber(values[1]);
240 var hasHolidays = values.length === 3;
241@@ -870,7 +870,7 @@ var WORKDAY = function (...values) : number {
242 * @constructor
243 */
244 var WORKDAY$INTL = function (...values) : number {
245- ArgsChecker.checkLengthWithin(values, 2, 3);
246+ ArgsChecker.checkLengthWithin(values, 2, 3, "WORKDAY$INTL");
247 var start = TypeConverter.firstValueAsDateNumber(values[0], true);
248 var days = TypeConverter.firstValueAsNumber(values[1]);
249 var weekendDays = [];
250diff --git a/src/Formulas/Engineering.ts b/src/Formulas/Engineering.ts
251index d78e0fa..b7e52d8 100644
252--- a/src/Formulas/Engineering.ts
253+++ b/src/Formulas/Engineering.ts
254@@ -18,7 +18,7 @@ import {
255 * @constructor
256 */
257 var BIN2DEC = function (...values) : number {
258- ArgsChecker.checkLength(values, 1);
259+ ArgsChecker.checkLength(values, 1, "BIN2DEC");
260 if (typeof TypeConverter.firstValue(values[0]) === "boolean") {
261 throw new ValueError("Function BIN2DEC parameter 1 expects text values. But '" + values[0] + "' is a boolean and cannot be coerced to a text.");
262 }
263@@ -44,7 +44,7 @@ var BIN2DEC = function (...values) : number {
264 * @constructor
265 */
266 var BIN2HEX = function (...values) : string {
267- ArgsChecker.checkLengthWithin(values, 1, 2);
268+ ArgsChecker.checkLengthWithin(values, 1, 2, "BIN2HEX");
269 if (typeof TypeConverter.firstValue(values[0]) === "boolean") {
270 throw new ValueError("Function BIN2HEX parameter 1 expects text values. But '" + values[0] + "' is a boolean and cannot be coerced to a text.");
271 }
272@@ -90,7 +90,7 @@ var BIN2HEX = function (...values) : string {
273 * @constructor
274 */
275 var BIN2OCT = function (...values) : string {
276- ArgsChecker.checkLengthWithin(values, 1, 2);
277+ ArgsChecker.checkLengthWithin(values, 1, 2, "BIN2OCT");
278 if (typeof TypeConverter.firstValue(values[0]) === "boolean") {
279 throw new ValueError("Function BIN2OCT parameter 1 expects text values. But '" + values[0] + "' is a boolean and cannot be coerced to a text.");
280 }
281@@ -135,7 +135,7 @@ var BIN2OCT = function (...values) : string {
282 * @constructor
283 */
284 var DEC2OCT = function (...values) : string {
285- ArgsChecker.checkLengthWithin(values, 1, 2);
286+ ArgsChecker.checkLengthWithin(values, 1, 2, "DEC2OCT");
287 var n = TypeConverter.firstValueAsNumber(values[0]);
288 if (n < 0) {
289 n = Math.ceil(n);
290@@ -183,7 +183,7 @@ var DEC2OCT = function (...values) : string {
291 * @constructor
292 */
293 var DEC2HEX = function (...values) : string {
294- ArgsChecker.checkLengthWithin(values, 1, 2);
295+ ArgsChecker.checkLengthWithin(values, 1, 2, "DEC2HEX");
296 var n = TypeConverter.firstValueAsNumber(values[0]);
297 if (n < 0) {
298 n = Math.ceil(n);
299@@ -231,7 +231,7 @@ var DEC2HEX = function (...values) : string {
300 * @constructor
301 */
302 var DEC2BIN = function (...values) : string {
303- ArgsChecker.checkLengthWithin(values, 1, 2);
304+ ArgsChecker.checkLengthWithin(values, 1, 2, "DEC2BIN");
305 var n = TypeConverter.firstValueAsNumber(values[0]);
306 if (n < 0) {
307 n = Math.ceil(n);
308@@ -299,7 +299,7 @@ var DEC2BIN = function (...values) : string {
309 * @constructor
310 */
311 var DELTA = function (...values) : number {
312- ArgsChecker.checkLengthWithin(values, 1, 2);
313+ ArgsChecker.checkLengthWithin(values, 1, 2, "DELTA");
314 if (values.length === 1) {
315 return TypeConverter.valueToNumber(values[0]) === 0 ? 1 : 0;
316 }
317diff --git a/src/Formulas/Financial.ts b/src/Formulas/Financial.ts
318index ed4cc64..1c2f28c 100644
319--- a/src/Formulas/Financial.ts
320+++ b/src/Formulas/Financial.ts
321@@ -25,7 +25,7 @@ import {
322 * @constructor
323 */
324 var DDB = function (...values) : number {
325- ArgsChecker.checkLengthWithin(values, 4, 5);
326+ ArgsChecker.checkLengthWithin(values, 4, 5, "DDB");
327 var cost = TypeConverter.firstValueAsNumber(values[0]);
328 var salvage = TypeConverter.firstValueAsNumber(values[1]);
329 var life = TypeConverter.firstValueAsNumber(values[2]);
330@@ -77,7 +77,7 @@ var DDB = function (...values) : number {
331 * @constructor
332 */
333 var DB = function (...values) : number {
334- ArgsChecker.checkLengthWithin(values, 4, 5);
335+ ArgsChecker.checkLengthWithin(values, 4, 5, "DB");
336 var cost = TypeConverter.firstValueAsNumber(values[0]);
337 var salvage = TypeConverter.firstValueAsNumber(values[1]);
338 var life = TypeConverter.firstValueAsNumber(values[2]);
339@@ -140,7 +140,7 @@ var DB = function (...values) : number {
340 * @constructor
341 */
342 var DOLLAR = function (...values) : number {
343- ArgsChecker.checkLengthWithin(values, 1, 2);
344+ ArgsChecker.checkLengthWithin(values, 1, 2, "DOLLAR");
345 var v = TypeConverter.firstValueAsNumber(values[0]);
346 var places = values.length === 2 ? TypeConverter.firstValueAsNumber(values[1]) : 2;
347 var sign = (v > 0) ? 1 : -1;
348@@ -161,7 +161,7 @@ var DOLLAR = function (...values) : number {
349 * @constructor
350 */
351 var DOLLARDE = function (...values) : number {
352- ArgsChecker.checkLength(values, 2);
353+ ArgsChecker.checkLength(values, 2, "DOLLARDE");
354 var dollar = TypeConverter.firstValueAsNumber(values[0]);
355 var fraction = Math.floor(TypeConverter.firstValueAsNumber(values[1]));
356 if (fraction === 0) {
357@@ -186,7 +186,7 @@ var DOLLARDE = function (...values) : number {
358 * @constructor
359 */
360 var DOLLARFR = function (...values) : number {
361- ArgsChecker.checkLength(values, 2);
362+ ArgsChecker.checkLength(values, 2, "DOLLARFR");
363 var dollar = TypeConverter.firstValueAsNumber(values[0]);
364 var unit = Math.floor(TypeConverter.firstValueAsNumber(values[1]));
365 if (unit === 0) {
366@@ -206,7 +206,7 @@ var DOLLARFR = function (...values) : number {
367 * @constructor
368 */
369 var EFFECT = function (...values) : number {
370- ArgsChecker.checkLength(values, 2);
371+ ArgsChecker.checkLength(values, 2, "EFFECT");
372 var rate = TypeConverter.firstValueAsNumber(values[0]);
373 var periods = TypeConverter.firstValueAsNumber(values[1]);
374 if (rate <= 0) {
375@@ -266,7 +266,7 @@ function fv(rate, periods, payment, value, type) {
376 * @constructor
377 */
378 var CUMPRINC = function (...values) : number {
379- ArgsChecker.checkLength(values, 6);
380+ ArgsChecker.checkLength(values, 6, "CUMPRINC");
381 var rate = TypeConverter.firstValueAsNumber(values[0]);
382 var periods = TypeConverter.firstValueAsNumber(values[1]);
383 var value = TypeConverter.firstValueAsNumber(values[2]);
384@@ -318,7 +318,7 @@ var CUMPRINC = function (...values) : number {
385 * @constructor
386 */
387 var CUMIPMT = function (...values) : number {
388- ArgsChecker.checkLength(values, 6);
389+ ArgsChecker.checkLength(values, 6, "CUMIPMT");
390 var rate = TypeConverter.firstValueAsNumber(values[0]);
391 var periods = TypeConverter.firstValueAsNumber(values[1]);
392 var value = TypeConverter.firstValueAsNumber(values[2]);
393@@ -386,7 +386,7 @@ var CUMIPMT = function (...values) : number {
394 * TODO: second version that is closer to what MSExcel does and is named something like `ACCRINT.MS`.
395 */
396 var ACCRINT = function (...values) {
397- ArgsChecker.checkLengthWithin(values, 6, 7);
398+ ArgsChecker.checkLengthWithin(values, 6, 7, "ACCRINT");
399 var issue = TypeConverter.firstValueAsDateNumber(values[0]);
400 // "firstPayment" param is only here to check for errors for GS implementation.
401 // In MSE, there is a 7th (zero-indexed-6th) param that indicates the calculation-method to use, which indicates
402diff --git a/src/Formulas/Logical.ts b/src/Formulas/Logical.ts
403index 8381d5a..0c89672 100644
404--- a/src/Formulas/Logical.ts
405+++ b/src/Formulas/Logical.ts
406@@ -18,7 +18,7 @@ import {
407 * @constructor
408 */
409 var AND = function (...values) {
410- ArgsChecker.checkAtLeastLength(values, 1);
411+ ArgsChecker.checkAtLeastLength(values, 1, "AND");
412 var result = true;
413 for (var i = 0; i < values.length; i++) {
414 if (typeof values[i] === "string") {
415@@ -45,7 +45,7 @@ var AND = function (...values) {
416 * @constructor
417 */
418 var EXACT = function (...values) {
419- ArgsChecker.checkLength(values, 2);
420+ ArgsChecker.checkLength(values, 2, "EXACT");
421 var one = TypeConverter.firstValue(values[0]);
422 var two = TypeConverter.firstValue(values[1]);
423 return one.toString() === two.toString();
424@@ -55,6 +55,7 @@ var EXACT = function (...values) {
425 * Returns true.
426 * @returns {boolean} true boolean
427 * @constructor
428+ * TODO: Should throw NA error if param passed in.
429 */
430 var TRUE = function () : boolean {
431 return true;
432@@ -64,6 +65,7 @@ var TRUE = function () : boolean {
433 * Returns false.
434 * @returns {boolean} false boolean
435 * @constructor
436+ * TODO: Should throw NA error if param passed in.
437 */
438 var FALSE = function () : boolean {
439 return false;
440@@ -76,7 +78,7 @@ var FALSE = function () : boolean {
441 * @constructor
442 */
443 var NOT = function (...values) : boolean {
444- ArgsChecker.checkLength(values, 1);
445+ ArgsChecker.checkLength(values, 1, "NOT");
446 var X = values[0];
447 if (typeof(X) === "boolean") {
448 return !X;
449@@ -108,7 +110,7 @@ var NOT = function (...values) : boolean {
450 * @constructor
451 */
452 var OR = function (...values) {
453- ArgsChecker.checkAtLeastLength(values, 1);
454+ ArgsChecker.checkAtLeastLength(values, 1, "OR");
455 for (var i = 0; i < values.length; i++) {
456 if (values[i] instanceof Array) {
457 if (values[i].length === 0) {
458@@ -131,7 +133,7 @@ var OR = function (...values) {
459 * @constructor
460 */
461 var XOR = function (...values) {
462- ArgsChecker.checkAtLeastLength(values, 1);
463+ ArgsChecker.checkAtLeastLength(values, 1, "XOR");
464 var alreadyTruthy = false;
465 for (var i = 0; i < values.length; i++) {
466 if (values[i] instanceof Array) {
467diff --git a/src/Formulas/Math.ts b/src/Formulas/Math.ts
468index 7080ecb..91deaaf 100644
469--- a/src/Formulas/Math.ts
470+++ b/src/Formulas/Math.ts
471@@ -28,7 +28,7 @@ import {
472 * @constructor
473 */
474 var ABS = function (...values) {
475- ArgsChecker.checkLength(values, 1);
476+ ArgsChecker.checkLength(values, 1, "ABS");
477 var v = TypeConverter.valueToNumber(values[0]);
478 return Math.abs(v);
479 };
480@@ -40,7 +40,7 @@ var ABS = function (...values) {
481 * @constructor
482 */
483 var ACOS = function (value?) {
484- ArgsChecker.checkLength(arguments, 1);
485+ ArgsChecker.checkLength(arguments, 1, "ACOS");
486 value = TypeConverter.valueToNumber(value);
487 if (value === -1) {
488 return Math.PI;
489@@ -57,7 +57,7 @@ var ACOS = function (value?) {
490 * @constructor
491 */
492 var ACOSH = function (value?) {
493- ArgsChecker.checkLength(arguments, 1);
494+ ArgsChecker.checkLength(arguments, 1, "ACOSH");
495 value = TypeConverter.valueToNumber(value);
496 if (value < 1) {
497 throw new NumError("Function ACOSH parameter 1 value is " + value + ". It should be greater than or equal to 1.");
498@@ -72,7 +72,7 @@ var ACOSH = function (value?) {
499 * @constructor
500 */
501 var ACOTH = function (value?) {
502- ArgsChecker.checkLength(arguments, 1);
503+ ArgsChecker.checkLength(arguments, 1, "ACOTH");
504 value = TypeConverter.valueToNumber(value);
505 if (value <= 1 && value >= -1) {
506 throw new NumError("Function ACOTH parameter 1 value is " + value + ". Valid values cannot be between -1 and 1 inclusive.")
507@@ -87,7 +87,7 @@ var ACOTH = function (value?) {
508 * @constructor
509 */
510 var ASIN = function (value?) {
511- ArgsChecker.checkLength(arguments, 1);
512+ ArgsChecker.checkLength(arguments, 1, "ASIN");
513 value = TypeConverter.valueToNumber(value);
514 if (value === -1) {
515 return Math.PI;
516@@ -104,7 +104,7 @@ var ASIN = function (value?) {
517 * @constructor
518 */
519 var ASINH = function (value?) {
520- ArgsChecker.checkLength(arguments, 1);
521+ ArgsChecker.checkLength(arguments, 1, "ASINH");
522 value = TypeConverter.valueToNumber(value);
523 return Math.log(value + Math.sqrt(value * value + 1));
524 };
525@@ -117,7 +117,7 @@ var ASINH = function (value?) {
526 * @constructor
527 */
528 var ATAN = function (value?) {
529- ArgsChecker.checkLength(arguments, 1);
530+ ArgsChecker.checkLength(arguments, 1, "ATAN");
531 value = TypeConverter.valueToNumber(value);
532 if (value === -1) {
533 return Math.PI;
534@@ -136,7 +136,7 @@ var ATAN = function (value?) {
535 * @constructor
536 */
537 var ATAN2 = function (x, y) {
538- ArgsChecker.checkLength(arguments, 2);
539+ ArgsChecker.checkLength(arguments, 2, "ATAN2");
540 x = TypeConverter.valueToNumber(x);
541 y = TypeConverter.valueToNumber(y);
542 if (x === 0 && y === 0) {
543@@ -153,7 +153,7 @@ var ATAN2 = function (x, y) {
544 * @constructor
545 */
546 var ATANH = function (value?) : number {
547- ArgsChecker.checkLength(arguments, 1);
548+ ArgsChecker.checkLength(arguments, 1, "ATANH");
549 value = TypeConverter.valueToNumber(value);
550 if (value >= 1 || value <= -1) {
551 throw new NumError("Function ATANH parameter 1 value is " + value + ". Valid values are between -1 and 1 exclusive.");
552@@ -171,7 +171,7 @@ var ATANH = function (value?) : number {
553 * @constructor
554 */
555 var EVEN = function (...values) : number {
556- ArgsChecker.checkLength(values, 1);
557+ ArgsChecker.checkLength(values, 1, "EVEN");
558 if (values[0] instanceof Array) {
559 if (values[0].length === 0) {
560 throw new RefError("Reference does not exist.");
561@@ -190,7 +190,7 @@ var EVEN = function (...values) : number {
562 * @constructor
563 */
564 var MOD = function (...values) : number {
565- ArgsChecker.checkLength(values, 2);
566+ ArgsChecker.checkLength(values, 2, "MOD");
567 var oneN = TypeConverter.valueToNumber(values[0]);
568 var twoN = TypeConverter.valueToNumber(values[1]);
569 if (twoN === 0) {
570@@ -207,7 +207,7 @@ var MOD = function (...values) : number {
571 * @constructor
572 */
573 var ODD = function (...values) : number {
574- ArgsChecker.checkLength(values, 1);
575+ ArgsChecker.checkLength(values, 1, "ODD");
576 if (values[0] instanceof Array) {
577 if (values[0].length === 0) {
578 throw new RefError("Reference does not exist.");
579@@ -226,7 +226,7 @@ var ODD = function (...values) : number {
580 * @constructor
581 */
582 var POWER = function (...values) : number {
583- ArgsChecker.checkLength(values, 2);
584+ ArgsChecker.checkLength(values, 2, "POWER");
585 var n = TypeConverter.firstValueAsNumber(values[0]);
586 var p = TypeConverter.firstValueAsNumber(values[1]);
587 return Math.pow(n, p);
588@@ -239,7 +239,7 @@ var POWER = function (...values) : number {
589 * @constructor
590 */
591 var SUM = function (...values) : number {
592- ArgsChecker.checkAtLeastLength(values, 1);
593+ ArgsChecker.checkAtLeastLength(values, 1, "SUM");
594 var result = 0;
595 for (var i = 0; i < values.length; i++) {
596 if (values[i] instanceof Array) {
597@@ -261,7 +261,7 @@ var SUM = function (...values) : number {
598 * @constructor
599 */
600 var SQRT = function (...values) : number {
601- ArgsChecker.checkLength(values, 1);
602+ ArgsChecker.checkLength(values, 1, "SQRT");
603 var x = TypeConverter.firstValueAsNumber(values[0]);
604 if (x < 0) {
605 throw new ValueError("Function SQRT parameter 1 expects number values. But '" + values[0] + "' is a text and cannot be coerced to a number.");
606@@ -276,7 +276,7 @@ var SQRT = function (...values) : number {
607 * @constructor
608 */
609 var SQRTPI = function (...values) : number{
610- ArgsChecker.checkLength(values, 1);
611+ ArgsChecker.checkLength(values, 1, "SQRTPI");
612 var n = TypeConverter.firstValueAsNumber(values[0]);
613 if (n < 0) {
614 throw new NumError("Function SQRTPI parameter 1 value is " + n + ". It should be greater than or equal to 0.");
615@@ -291,7 +291,7 @@ var SQRTPI = function (...values) : number{
616 * @constructor
617 */
618 var COS = function (...values) : number {
619- ArgsChecker.checkLength(values, 1);
620+ ArgsChecker.checkLength(values, 1, "COS");
621 var r = TypeConverter.firstValueAsNumber(values[0]);
622 return Math.cos(r);
623 };
624@@ -303,7 +303,7 @@ var COS = function (...values) : number {
625 * @constructor
626 */
627 var COSH = function (...values) : number {
628- ArgsChecker.checkLength(values, 1);
629+ ArgsChecker.checkLength(values, 1, "COSH");
630 var r = TypeConverter.firstValueAsNumber(values[0]);
631 return Math["cosh"](r);
632 };
633@@ -315,7 +315,7 @@ var COSH = function (...values) : number {
634 * @constructor
635 */
636 var COT = function (...values) : number {
637- ArgsChecker.checkLength(values, 1);
638+ ArgsChecker.checkLength(values, 1, "COT");
639 var x = TypeConverter.firstValueAsNumber(values[0]);
640 if (x === 0) {
641 throw new DivZeroError("Evaluation of function COT caused a divide by zero error.");
642@@ -330,7 +330,7 @@ var COT = function (...values) : number {
643 * @constructor
644 */
645 var COTH = function (...values) : number {
646- ArgsChecker.checkLength(values, 1);
647+ ArgsChecker.checkLength(values, 1, "COTH");
648 var x = TypeConverter.firstValueAsNumber(values[0]);
649 if (x === 0) {
650 throw new DivZeroError("Evaluation of function COTH caused a divide by zero error.");
651@@ -345,7 +345,7 @@ var COTH = function (...values) : number {
652 * @constructor
653 */
654 var INT = function (...values) : number {
655- ArgsChecker.checkLength(values, 1);
656+ ArgsChecker.checkLength(values, 1, "INT");
657 var x = TypeConverter.firstValueAsNumber(values[0]);
658 return Math.floor(x);
659 };
660@@ -358,7 +358,7 @@ var INT = function (...values) : number {
661 * @constructor
662 */
663 var ISEVEN = function (...values) : boolean {
664- ArgsChecker.checkLength(values, 1);
665+ ArgsChecker.checkLength(values, 1, "ISEVEN");
666 if (values[0] === "") {
667 throw new ValueError("Function ISEVEN parameter 1 expects boolean values. But '" + values[0] + "' is a text and cannot be coerced to a boolean.");
668 }
669@@ -374,7 +374,7 @@ var ISEVEN = function (...values) : boolean {
670 * @constructor
671 */
672 var ISODD = function (...values) : boolean {
673- ArgsChecker.checkLength(values, 1);
674+ ArgsChecker.checkLength(values, 1, "ISODD");
675 if (values[0] === "") {
676 throw new ValueError("Function ISODD parameter 1 expects boolean values. But '" + values[0] + "' is a text and cannot be coerced to a boolean.");
677 }
678@@ -389,7 +389,7 @@ var ISODD = function (...values) : boolean {
679 * @constructor
680 */
681 var SIN = function (...values) {
682- ArgsChecker.checkLength(values, 1);
683+ ArgsChecker.checkLength(values, 1, "SIN");
684 var rad = TypeConverter.firstValueAsNumber(values[0]);
685 return rad === Math.PI ? 0 : Math.sin(rad);
686 };
687@@ -401,7 +401,7 @@ var SIN = function (...values) {
688 * @constructor
689 */
690 var SINH = function (...values) : number {
691- ArgsChecker.checkLength(values, 1);
692+ ArgsChecker.checkLength(values, 1, "SINH");
693 var rad = TypeConverter.firstValueAsNumber(values[0]);
694 return Math["sinh"](rad);
695 };
696@@ -412,6 +412,7 @@ var SINH = function (...values) : number {
697 * @constructor
698 */
699 var PI = function () {
700+ ArgsChecker.checkLength(arguments, 0, "SINH");
701 return Math.PI;
702 };
703
704@@ -422,7 +423,7 @@ var PI = function () {
705 * @constructor
706 */
707 var LOG10 = function (...values) : number {
708- ArgsChecker.checkLength(values, 1);
709+ ArgsChecker.checkLength(values, 1, "LOG10");
710 var n = TypeConverter.firstValueAsNumber(values[0]);
711 if (n < 1) {
712 throw new NumError("Function LOG10 parameter 1 value is " + n + ". It should be greater than 0.");
713@@ -440,7 +441,7 @@ var LOG10 = function (...values) : number {
714 * @constructor
715 */
716 var LOG = function (...values) : number {
717- ArgsChecker.checkAtLeastLength(values, 1);
718+ ArgsChecker.checkAtLeastLength(values, 1, "LOG");
719 var n = TypeConverter.firstValueAsNumber(values[0]);
720 var b = 10;
721 if (values.length > 1) {
722@@ -467,7 +468,7 @@ var LOG = function (...values) : number {
723 * @constructor
724 */
725 var LN = function (...values) : number {
726- ArgsChecker.checkLength(values, 1);
727+ ArgsChecker.checkLength(values, 1, "LN");
728 var n = TypeConverter.firstValueAsNumber(values[0]);
729 if (n < 1) {
730 throw new NumError("Function LN parameter 1 value is " + n + ". It should be greater than 0.");
731@@ -482,7 +483,7 @@ var LN = function (...values) : number {
732 * @constructor
733 */
734 var TAN = function (...values) : number {
735- ArgsChecker.checkLength(values, 1);
736+ ArgsChecker.checkLength(values, 1, "TAN");
737 var rad = TypeConverter.firstValueAsNumber(values[0]);
738 return rad === Math.PI ? 0 : Math.tan(rad);
739 };
740@@ -494,7 +495,7 @@ var TAN = function (...values) : number {
741 * @constructor
742 */
743 var TANH = function (...values) : number {
744- ArgsChecker.checkLength(values, 1);
745+ ArgsChecker.checkLength(values, 1, "TANH");
746 var rad = TypeConverter.firstValueAsNumber(values[0]);
747 return Math["tanh"](rad);
748 };
749@@ -507,7 +508,7 @@ var TANH = function (...values) : number {
750 * @constructor
751 */
752 var CEILING = function (...values) : number {
753- ArgsChecker.checkLengthWithin(values, 1, 2);
754+ ArgsChecker.checkLengthWithin(values, 1, 2, "CEILING");
755 var num = TypeConverter.firstValueAsNumber(values[0]);
756 if (values.length === 1) {
757 return Math.ceil(num);
758@@ -532,7 +533,7 @@ var CEILING = function (...values) : number {
759 * @constructor
760 */
761 var FLOOR = function (...values) : number {
762- ArgsChecker.checkLengthWithin(values, 1, 2);
763+ ArgsChecker.checkLengthWithin(values, 1, 2, "FLOOR");
764 var num = TypeConverter.firstValueAsNumber(values[0]);
765 if (values.length === 1) {
766 return Math.floor(num);
767@@ -558,7 +559,7 @@ var FLOOR = function (...values) : number {
768 * @constructor
769 */
770 var IF = function (...values) : any {
771- ArgsChecker.checkLength(values, 3);
772+ ArgsChecker.checkLength(values, 3, "IF");
773 if (values[0] instanceof Array) {
774 if (values[0].length === 0) {
775 throw new RefError("Reference does not exist.");
776@@ -582,7 +583,7 @@ var IF = function (...values) : any {
777 * @constructor
778 */
779 var COUNTIF = function (...values) {
780- ArgsChecker.checkLength(values, 2);
781+ ArgsChecker.checkLength(values, 2, "COUNTIF");
782 var range = values[0];
783 if (!(range instanceof Array)) {
784 range = [range];
785@@ -611,7 +612,7 @@ var COUNTIF = function (...values) {
786 * @constructor
787 */
788 var COUNTIFS = function (...values) {
789- ArgsChecker.checkAtLeastLength(values, 2);
790+ ArgsChecker.checkAtLeastLength(values, 2, "COUNTIFS");
791 var criteriaEvaluationFunctions = values.map(function (criteria, index) {
792 if (index % 2 === 1) {
793 return CriteriaFunctionFactory.createCriteriaFunction(criteria);
794@@ -661,7 +662,7 @@ var COUNTIFS = function (...values) {
795 * @constructor
796 */
797 var ROUND = function (...values) {
798- ArgsChecker.checkLengthWithin(values, 1, 2);
799+ ArgsChecker.checkLengthWithin(values, 1, 2, "ROUND");
800 var n = TypeConverter.firstValueAsNumber(values[0]);
801 if (values.length === 1) {
802 return Math.round(n);
803@@ -678,7 +679,7 @@ var ROUND = function (...values) {
804 * @constructor
805 */
806 var ROUNDDOWN = function (...values) {
807- ArgsChecker.checkLengthWithin(values, 1, 2);
808+ ArgsChecker.checkLengthWithin(values, 1, 2, "ROUNDDOWN");
809 var n = TypeConverter.firstValueAsNumber(values[0]);
810 if (values.length === 1) {
811 return Math.floor(n);
812@@ -695,7 +696,7 @@ var ROUNDDOWN = function (...values) {
813 * @constructor
814 */
815 var ROUNDUP = function (...values) {
816- ArgsChecker.checkLengthWithin(values, 1, 2);
817+ ArgsChecker.checkLengthWithin(values, 1, 2, "ROUNDUP");
818 var n = TypeConverter.firstValueAsNumber(values[0]);
819 if (values.length === 1) {
820 return Math.ceil(n);
821@@ -716,7 +717,7 @@ var ROUNDUP = function (...values) {
822 * @constructor
823 */
824 var SUMIF = function (...values) {
825- ArgsChecker.checkLengthWithin(values, 2, 3);
826+ ArgsChecker.checkLengthWithin(values, 2, 3, "SUMIF");
827 var range = values[0];
828 var criteria = values[1];
829 var sumRange = null;
830@@ -752,7 +753,7 @@ var SUMIF = function (...values) {
831 * @constructor
832 */
833 var SUMSQ = function (...values) {
834- ArgsChecker.checkAtLeastLength(values, 1);
835+ ArgsChecker.checkAtLeastLength(values, 1, "SUMSQ");
836 var result = 0;
837 for (var i = 0; i < values.length; i++) {
838 if (values[i] instanceof Array) {
839@@ -781,7 +782,7 @@ var SUMSQ = function (...values) {
840 * @constructor
841 */
842 var TRUNC = function (...values) : number {
843- ArgsChecker.checkLengthWithin(values, 1, 2);
844+ ArgsChecker.checkLengthWithin(values, 1, 2, "TRUNC");
845 var n = TypeConverter.firstValueAsNumber(values[0]);
846 var digits = 0;
847 if (values.length === 2) {
848@@ -799,7 +800,7 @@ var TRUNC = function (...values) : number {
849 * @constructor
850 */
851 var RADIANS = function (...values) {
852- ArgsChecker.checkLength(values, 1);
853+ ArgsChecker.checkLength(values, 1, "RADIANS");
854 var d = TypeConverter.firstValueAsNumber(values[0]);
855 return d * Math.PI / 180;
856 };
857@@ -811,7 +812,7 @@ var RADIANS = function (...values) {
858 * @constructor
859 */
860 var DEGREES = function (...values) {
861- ArgsChecker.checkLength(values, 1);
862+ ArgsChecker.checkLength(values, 1, "DEGREES");
863 var r = TypeConverter.firstValueAsNumber(values[0]);
864 return r * 180 / Math.PI;
865 };
866@@ -824,7 +825,7 @@ var DEGREES = function (...values) {
867 * @constructor
868 */
869 var ERFC = function (...values) {
870- ArgsChecker.checkLength(values, 1);
871+ ArgsChecker.checkLength(values, 1, "ERFC");
872 var v = TypeConverter.firstValueAsNumber(values[0]);
873 return v === 0 ? 1 : 1 - erf(v);
874 };
875@@ -839,7 +840,7 @@ var ERFC = function (...values) {
876 * @constructor
877 */
878 var ERF = function (...values) : number {
879- ArgsChecker.checkLengthWithin(values, 1, 2);
880+ ArgsChecker.checkLengthWithin(values, 1, 2, "ERF");
881 var lower = TypeConverter.firstValueAsNumber(values[0]);
882 var upper = values.length === 2 ? TypeConverter.firstValueAsNumber(values[1]) : 0;
883 return values.length === 1 ? erf(lower) : erf(upper) - erf(lower);
884@@ -902,7 +903,7 @@ function erf(x) {
885 * @constructor
886 */
887 var SUMX2PY2 = function (...values) : number {
888- ArgsChecker.checkLength(values, 2);
889+ ArgsChecker.checkLength(values, 2, "SUMX2PY2");
890 var arrOne = Filter.flattenAndThrow(values[0]);
891 var arrTwo = Filter.flattenAndThrow(values[1]);
892 if (arrOne.length !== arrTwo.length) {
893@@ -928,7 +929,7 @@ var SUMX2PY2 = function (...values) : number {
894 * @constructor
895 */
896 var SUMX2MY2 = function (...values) : number {
897- ArgsChecker.checkLength(values, 2);
898+ ArgsChecker.checkLength(values, 2, "SUMX2MY2");
899 var arrOne = Filter.flattenAndThrow(values[0]);
900 var arrTwo = Filter.flattenAndThrow(values[1]);
901 if (arrOne.length !== arrTwo.length) {
902@@ -953,7 +954,7 @@ var SUMX2MY2 = function (...values) : number {
903 * @constructor
904 */
905 var COUNTUNIQUE = function (...values) : number {
906- ArgsChecker.checkAtLeastLength(values, 1);
907+ ArgsChecker.checkAtLeastLength(values, 1, "COUNTUNIQUE");
908
909 // Private function that will recursively generate an array of the unique primitives
910 var countUniquePrivate = function (values: Array<any>) : Object {
911@@ -988,7 +989,7 @@ var COUNTUNIQUE = function (...values) : number {
912 * @constructor
913 */
914 var SUMPRODUCT = function (...values) : number {
915- ArgsChecker.checkAtLeastLength(values, 1);
916+ ArgsChecker.checkAtLeastLength(values, 1, "SUMPRODUCT");
917 // Ensuring that all values are array values
918 for (var x = 0; x < values.length; x++) {
919 if (!Array.isArray(values[x])) {
920@@ -1027,6 +1028,8 @@ var SUMPRODUCT = function (...values) : number {
921 * @constructor
922 */
923 var COMBIN = function (...values) : number {
924+ ArgsChecker.checkLength(values, 2, "COMBIN");
925+
926 var MEMOIZED_FACT = [];
927 function fact(number) {
928 var n = Math.floor(number);
929@@ -1039,7 +1042,6 @@ var COMBIN = function (...values) : number {
930 return MEMOIZED_FACT[n];
931 }
932 }
933- ArgsChecker.checkLength(values, 2);
934 var n = TypeConverter.firstValueAsNumber(values[0]);
935 var c = TypeConverter.firstValueAsNumber(values[1]);
936 if (n < c) {
937diff --git a/src/Formulas/Statistical.ts b/src/Formulas/Statistical.ts
938index c9a3ce3..840d42b 100644
939--- a/src/Formulas/Statistical.ts
940+++ b/src/Formulas/Statistical.ts
941@@ -26,7 +26,7 @@ import {
942 * @constructor
943 */
944 var DEVSQ = function (...values) : number {
945- ArgsChecker.checkAtLeastLength(values, 1);
946+ ArgsChecker.checkAtLeastLength(values, 1, "DEVSQ");
947 var range = Filter.flattenAndThrow(values);
948 var result = 0;
949 var count = 0;
950@@ -49,7 +49,7 @@ var DEVSQ = function (...values) : number {
951 * @constructor
952 */
953 var MEDIAN = function (...values) : number {
954- ArgsChecker.checkAtLeastLength(values, 1);
955+ ArgsChecker.checkAtLeastLength(values, 1, "MEDIAN");
956 var sortedArray = [];
957 values.forEach(function (currentValue) {
958 if (currentValue instanceof Array) {
959@@ -94,7 +94,7 @@ var MEDIAN = function (...values) : number {
960 * @constructor
961 */
962 var AVERAGE = function (...values) : number {
963- ArgsChecker.checkAtLeastLength(values, 1);
964+ ArgsChecker.checkAtLeastLength(values, 1, "AVERAGE");
965 var result = 0;
966 var count = 0;
967 for (var i = 0; i < values.length; i++) {
968@@ -120,7 +120,7 @@ var AVERAGE = function (...values) : number {
969 * @constructor
970 */
971 var AVEDEV = function (...values) {
972- ArgsChecker.checkAtLeastLength(values, 1);
973+ ArgsChecker.checkAtLeastLength(values, 1, "AVEDEV");
974
975 // Sort to array-values, and non-array-values
976 var arrayValues = [];
977@@ -167,7 +167,7 @@ var AVEDEV = function (...values) {
978 * @constructor
979 */
980 var AVERAGEA = function (...values) {
981- ArgsChecker.checkAtLeastLength(values, 1);
982+ ArgsChecker.checkAtLeastLength(values, 1, "AVERAGEA");
983 var result = 0;
984 var count = 0;
985 for (var i = 0; i < values.length; i++) {
986@@ -272,7 +272,7 @@ var CORREL = function (...values) : number {
987 }
988 return sum(sq_dev) / (arr1Len - 1);
989 }
990- ArgsChecker.checkLength(values, 2);
991+ ArgsChecker.checkLength(values, 2, "CORREL");
992 if (!Array.isArray(values[0])) {
993 values[0] = [values[0]];
994 }
995@@ -301,6 +301,7 @@ var CORREL = function (...values) : number {
996 * @constructor
997 */
998 var PEARSON = function (...values) {
999+ ArgsChecker.checkLength(values, 2, "PEARSON");
1000 return CORREL.apply(this, values);
1001 };
1002
1003@@ -314,13 +315,13 @@ var PEARSON = function (...values) {
1004 * @constructor
1005 */
1006 var EXPONDIST = function (...values) : number {
1007+ ArgsChecker.checkLength(values, 3, "EXPONDIST");
1008 function cdf(x, rate) {
1009 return x < 0 ? 0 : 1 - Math.exp(-rate * x);
1010 }
1011 function pdf(x, rate) {
1012 return x < 0 ? 0 : rate * Math.exp(-rate * x);
1013 }
1014- ArgsChecker.checkLength(values, 3);
1015 var x = TypeConverter.firstValueAsNumber(values[0]);
1016 var lambda = TypeConverter.firstValueAsNumber(values[1]);
1017 var cumulative = TypeConverter.firstValueAsBoolean(values[2]);
1018@@ -341,6 +342,7 @@ var EXPONDIST = function (...values) : number {
1019 * TODO: This function should be stricter in its return type.
1020 */
1021 var FDIST$LEFTTAILED = function (...values) : number|undefined|boolean {
1022+ ArgsChecker.checkLength(values, 4, "FDIST$LEFTTAILED");
1023 /**
1024 * Returns the Log-Gamma function evaluated at x. See http://jstat.github.io/special-functions.html#gammaln for more
1025 * information.
1026@@ -513,7 +515,6 @@ var FDIST$LEFTTAILED = function (...values) : number|undefined|boolean {
1027 // make sure x + y doesn't exceed the upper limit of usable values
1028 return (x + y > 170) ? Math.exp(betaln(x, y)) : gammafn(x) * gammafn(y) / gammafn(x + y);
1029 }
1030- ArgsChecker.checkLength(values, 4);
1031 var x = TypeConverter.firstValueAsNumber(values[0]);
1032 if (x < 0) {
1033 throw new NumError("Function F.DIST parameter 1 value is " + x + ". It should be greater than or equal to 0.");
1034@@ -534,6 +535,7 @@ var FDIST$LEFTTAILED = function (...values) : number|undefined|boolean {
1035 * @constructor
1036 */
1037 var FINV = function (...values) : number {
1038+ ArgsChecker.checkLength(values, 3, "FINV");
1039 /**
1040 * Returns the continued fraction for the incomplete Beta function with parameters a and b modified by Lentz's method
1041 * evaluated at x. For more information see http://jstat.github.io/special-functions.html#betacf
1042@@ -684,7 +686,6 @@ var FINV = function (...values) : number {
1043 function inv(x, df1, df2) {
1044 return df2 / (df1 * (1 / ibetainv(x, df1 / 2, df2 / 2) - 1));
1045 }
1046- ArgsChecker.checkLength(values, 3);
1047 var probability = TypeConverter.firstValueAsNumber(values[0]);
1048 if (probability <= 0.0 || probability > 1.0) {
1049 throw new NumError("Function FINV parameter 1 value is " + probability
1050@@ -702,7 +703,7 @@ var FINV = function (...values) : number {
1051 * @constructor
1052 */
1053 var FISHER = function (...values) : number {
1054- ArgsChecker.checkLength(values, 1);
1055+ ArgsChecker.checkLength(values, 1, "FISHER");
1056 var x = TypeConverter.firstValueAsNumber(values[0]);
1057 if (x <= -1 || x >= 1) {
1058 throw new NumError("Function FISHER parameter 1 value is " + x + ". Valid values are between -1 and 1 exclusive.");
1059@@ -717,7 +718,7 @@ var FISHER = function (...values) : number {
1060 * @constructor
1061 */
1062 var FISHERINV = function (...values) : number {
1063- ArgsChecker.checkLength(values, 1);
1064+ ArgsChecker.checkLength(values, 1, "FISHERINV");
1065 var y = TypeConverter.firstValueAsNumber(values[0]);
1066 var e2y = Math.exp(2 * y);
1067 return (e2y - 1) / (e2y + 1);
1068@@ -730,7 +731,7 @@ var FISHERINV = function (...values) : number {
1069 * @constructor
1070 */
1071 var MAX = function (...values) {
1072- ArgsChecker.checkAtLeastLength(values, 1);
1073+ ArgsChecker.checkAtLeastLength(values, 1, "MAX");
1074 var maxSoFar = -Infinity;
1075 for (var i = 0; i < values.length; i++) {
1076 if (values[i] instanceof Array) {
1077@@ -755,6 +756,7 @@ var MAX = function (...values) {
1078 * @constructor
1079 */
1080 var MAXA = function (...values) : number {
1081+ ArgsChecker.checkAtLeastLength(values, 1, "MAXA");
1082 return MAX.apply(this, values);
1083 };
1084
1085@@ -766,7 +768,7 @@ var MAXA = function (...values) : number {
1086 * @constructor
1087 */
1088 var MIN = function (...values) {
1089- ArgsChecker.checkAtLeastLength(values, 1);
1090+ ArgsChecker.checkAtLeastLength(values, 1, "MIN");
1091 var minSoFar = Infinity;
1092 for (var i = 0; i < values.length; i++) {
1093 if (values[i] instanceof Array) {
1094@@ -792,6 +794,7 @@ var MIN = function (...values) {
1095 * @constructor
1096 */
1097 var MINA = function (...values) : number {
1098+ ArgsChecker.checkAtLeastLength(values, 1, "MINA");
1099 return MIN.apply(this, values);
1100 };
1101
1102@@ -807,7 +810,7 @@ var MINA = function (...values) : number {
1103 * TODO: This needs to also accept a third parameter "average_range"
1104 */
1105 var AVERAGEIF = function (...values) {
1106- ArgsChecker.checkLength(values, 2);
1107+ ArgsChecker.checkLength(values, 2, "AVERAGEIF");
1108 var range = Filter.flatten(values[0]);
1109 var criteriaEvaluation = CriteriaFunctionFactory.createCriteriaFunction(values[1]);
1110
1111@@ -834,7 +837,7 @@ var AVERAGEIF = function (...values) {
1112 * @constructor
1113 */
1114 var COUNT = function (...values) : number {
1115- ArgsChecker.checkAtLeastLength(values, 1);
1116+ ArgsChecker.checkAtLeastLength(values, 1, "COUNT");
1117 var count = 0;
1118 for (var i = 0; i < values.length; i++) {
1119 if (values[i] instanceof Array) {
1120@@ -855,7 +858,7 @@ var COUNT = function (...values) : number {
1121 * @constructor
1122 */
1123 var COUNTA = function (...values) : number {
1124- ArgsChecker.checkAtLeastLength(values, 1);
1125+ ArgsChecker.checkAtLeastLength(values, 1, "COUNTA");
1126 var count = 0;
1127 for (var i = 0; i < values.length; i++) {
1128 if (values[i] instanceof Array) {
1129diff --git a/src/Formulas/Text.ts b/src/Formulas/Text.ts
1130index ca8dffb..01f99f6 100644
1131--- a/src/Formulas/Text.ts
1132+++ b/src/Formulas/Text.ts
1133@@ -18,7 +18,7 @@ import {
1134 * @constructor
1135 */
1136 var ARABIC = function (text?) {
1137- ArgsChecker.checkLength(arguments, 1);
1138+ ArgsChecker.checkLength(arguments, 1, "ARABIC");
1139 if (typeof text !== "string") {
1140 throw new ValueError('Invalid roman numeral in ARABIC evaluation.');
1141 }
1142@@ -48,7 +48,7 @@ var ARABIC = function (text?) {
1143 * @constructor
1144 */
1145 var CHAR = function (...values) : string {
1146- ArgsChecker.checkLength(values, 1);
1147+ ArgsChecker.checkLength(values, 1, "CHAR");
1148 var n = TypeConverter.firstValueAsNumber(values[0]);
1149 if (n < 1 || n > 1114112) { //limit
1150 throw new NumError("Function CHAR parameter 1 value " + n + " is out of range.");
1151@@ -63,7 +63,7 @@ var CHAR = function (...values) : string {
1152 * @constructor
1153 */
1154 var CODE = function (...values) : number {
1155- ArgsChecker.checkLength(values, 1);
1156+ ArgsChecker.checkLength(values, 1, "CODE");
1157 var text = TypeConverter.firstValueAsString(values[0]);
1158 if (text === "") {
1159 throw new ValueError("Function CODE parameter 1 value should be non-empty.");
1160@@ -82,7 +82,7 @@ var CODE = function (...values) : number {
1161 * TODO: At some point this needs to return a more complex type than Array. Needs to return a type that has a dimension.
1162 */
1163 var SPLIT = function (...values) : Array<string> {
1164- ArgsChecker.checkLengthWithin(values, 2, 3);
1165+ ArgsChecker.checkLengthWithin(values, 2, 3, "SPLIT");
1166 var text = TypeConverter.firstValueAsString(values[0]);
1167 var delimiter = TypeConverter.firstValueAsString(values[1]);
1168 var splitByEach = false;
1169@@ -114,7 +114,7 @@ var SPLIT = function (...values) : Array<string> {
1170 * @constructor
1171 */
1172 var CONCATENATE = function (...values) : string {
1173- ArgsChecker.checkAtLeastLength(values, 1);
1174+ ArgsChecker.checkAtLeastLength(values, 1, "CONCATENATE");
1175 var string = '';
1176 for (var i = 0; i < values.length; i++) {
1177 if (values[i] instanceof Array) {
1178@@ -139,7 +139,7 @@ var CONCATENATE = function (...values) : string {
1179 * TODO: Looking up units is not efficient at all. We should use an object instead of iterating through an array.
1180 */
1181 var CONVERT = function (...values) {
1182- ArgsChecker.checkLength(values, 3);
1183+ ArgsChecker.checkLength(values, 3, "CONVERT");
1184 var n = TypeConverter.firstValueAsNumber(values[0]);
1185 var fromUnit = TypeConverter.firstValueAsString(values[1]);
1186 var toUnit = TypeConverter.firstValueAsString(values[2]);
1187diff --git a/src/Utilities/ArgsChecker.ts b/src/Utilities/ArgsChecker.ts
1188index d8c6c0d..cc85633 100644
1189--- a/src/Utilities/ArgsChecker.ts
1190+++ b/src/Utilities/ArgsChecker.ts
1191@@ -10,10 +10,13 @@ class ArgsChecker {
1192 * Checks to see if the arguments are of the correct length.
1193 * @param args to check length of
1194 * @param length expected length
1195+ * @param caller name of the function calling this function, for use in error message formatting
1196 */
1197- static checkLength(args: Array<any> | IArguments, length: number) {
1198+ static checkLength(args: Array<any> | IArguments, length: number, caller?: string) {
1199 if (args.length !== length) {
1200- throw new NAError("Wrong number of arguments to ___. Expected 1 arguments, but got " + args.length + " arguments.");
1201+ var functionName = caller !== undefined ? " to " + caller : "";
1202+ throw new NAError("Wrong number of arguments" + functionName + ". Expected " + length
1203+ + " arguments, but got " + args.length + " arguments.");
1204 }
1205 }
1206
1207@@ -21,10 +24,13 @@ class ArgsChecker {
1208 * Checks to see if the arguments are at least a certain length.
1209 * @param args to check length of
1210 * @param length expected length
1211+ * @param caller name of the function calling this function, for use in error message formatting
1212 */
1213- static checkAtLeastLength(args: any, length: number) {
1214+ static checkAtLeastLength(args: any, length: number, caller?: string) {
1215 if (args.length < length) {
1216- throw new NAError("Wrong number of arguments to ___. Expected " + length + " arguments, but got " + args.length + " arguments.");
1217+ var functionName = caller !== undefined ? " to " + caller : "";
1218+ throw new NAError("Wrong number of arguments" + functionName + ". Expected " + length
1219+ + " arguments, but got " + args.length + " arguments.");
1220 }
1221 }
1222
1223@@ -33,10 +39,13 @@ class ArgsChecker {
1224 * @param args to check length of
1225 * @param low least number of arguments
1226 * @param high max number of arguments
1227+ * @param caller name of the function calling this function, for use in error message formatting
1228 */
1229- static checkLengthWithin(args: any, low: number, high: number) {
1230+ static checkLengthWithin(args: any, low: number, high: number, caller?: string) {
1231 if (args.length > high || args.length < low) {
1232- throw new NAError("Wrong number of arguments to ___. Expected 1 arguments, but got " + args.length + " arguments.");
1233+ var functionName = caller !== undefined ? " to " + caller : "";
1234+ throw new NAError("Wrong number of arguments" + functionName + ". Expected between" + low
1235+ + "and " + high + " arguments, but got " + args.length + " arguments.");
1236 }
1237 }
1238 }
1239diff --git a/tests/Utilities/ArgsCheckerTest.ts b/tests/Utilities/ArgsCheckerTest.ts
1240index 9c66105..8a1be62 100644
1241--- a/tests/Utilities/ArgsCheckerTest.ts
1242+++ b/tests/Utilities/ArgsCheckerTest.ts
1243@@ -9,13 +9,31 @@ import {
1244 import {NA_ERROR} from "../../src/Errors";
1245
1246
1247+function catchAndAssertErrorFormatting(toExecute : Function, errorString: string, nameToMatch: string) {
1248+ var toThrow = null;
1249+ try {
1250+ toExecute();
1251+ toThrow = true;
1252+ } catch (actualError) {
1253+ if (actualError.name !== errorString || actualError.message.indexOf(nameToMatch) === -1) {
1254+ console.log("expected:", errorString, " actual:", actualError.name, actualError.message);
1255+ console.trace();
1256+ }
1257+ }
1258+ if (toThrow) {
1259+ console.log("expected error: " + errorString, "and function name in error: ", nameToMatch);
1260+ console.trace();
1261+ }
1262+}
1263+
1264+const FORMULA_NAME = "FROMTEST";
1265 test("ArgsChecker.checkLength", function () {
1266 assertEquals(ArgsChecker.checkLength(["A", "B"], 2), undefined);
1267 assertEquals(ArgsChecker.checkLength(["A"], 1), undefined);
1268 assertEquals(ArgsChecker.checkLength([], 0), undefined);
1269- catchAndAssertEquals(function () {
1270- ArgsChecker.checkLength(["A", "B"], 100);
1271- }, NA_ERROR);
1272+ catchAndAssertErrorFormatting(function () {
1273+ ArgsChecker.checkLength(["A", "B"], 100, FORMULA_NAME);
1274+ }, NA_ERROR, FORMULA_NAME);
1275 });
1276
1277
1278@@ -25,9 +43,9 @@ test("ArgsChecker.checkAtLeastLength", function () {
1279 assertEquals(ArgsChecker.checkAtLeastLength(["A"], 1), undefined);
1280 assertEquals(ArgsChecker.checkAtLeastLength(["A"], 0), undefined);
1281 assertEquals(ArgsChecker.checkAtLeastLength([], 0), undefined);
1282- catchAndAssertEquals(function () {
1283- ArgsChecker.checkAtLeastLength(["A", "B"], 3);
1284- }, NA_ERROR);
1285+ catchAndAssertErrorFormatting(function () {
1286+ ArgsChecker.checkAtLeastLength(["A", "B"], 3, FORMULA_NAME);
1287+ }, NA_ERROR, FORMULA_NAME);
1288 });
1289
1290
1291@@ -36,9 +54,13 @@ test("ArgsChecker.checkLengthWithin", function () {
1292 assertEquals(ArgsChecker.checkLengthWithin(["A", "B"], 1, 4), undefined);
1293 assertEquals(ArgsChecker.checkLengthWithin(["A", "B", "C", "D"], 1, 4), undefined);
1294 assertEquals(ArgsChecker.checkLengthWithin(["A", "B", "C", "D"], 1, 6), undefined);
1295- catchAndAssertEquals(function () {
1296- ArgsChecker.checkLengthWithin(["A", "B"], 3, 10);
1297- ArgsChecker.checkLengthWithin(["A", "B"], 5, 10);
1298- ArgsChecker.checkLengthWithin(["A", "B", "C", "D"], 5, 6);
1299- }, NA_ERROR);
1300+ catchAndAssertErrorFormatting(function () {
1301+ ArgsChecker.checkLengthWithin(["A", "B"], 3, 10, FORMULA_NAME);
1302+ }, NA_ERROR, FORMULA_NAME);
1303+ catchAndAssertErrorFormatting(function () {
1304+ ArgsChecker.checkLengthWithin(["A", "B"], 5, 10, FORMULA_NAME);
1305+ }, NA_ERROR, FORMULA_NAME);
1306+ catchAndAssertErrorFormatting(function () {
1307+ ArgsChecker.checkLengthWithin(["A", "B", "C", "D"], 5, 6, FORMULA_NAME);
1308+ }, NA_ERROR, FORMULA_NAME);
1309 });