commit
message
Refactoring functions into category files, creating Financial.ts
author
Ben Vogt <[email protected]>
date
2017-02-20 22:09:23
stats
3 file(s) changed,
222 insertions(+),
234 deletions(-)
files
src/RawFormulas/Financial.ts
src/RawFormulas/Math.ts
src/RawFormulas/RawFormulas.ts
1diff --git a/src/RawFormulas/Financial.ts b/src/RawFormulas/Financial.ts
2new file mode 100644
3index 0000000..9726438
4--- /dev/null
5+++ b/src/RawFormulas/Financial.ts
6@@ -0,0 +1,83 @@
7+import {
8+ ArgsChecker,
9+ TypeCaster
10+} from "./Utils";
11+import {
12+ CellError
13+} from "../Errors"
14+import * as ERRORS from "../Errors"
15+
16+/**
17+ * Formats a number into the locale-specific currency format. WARNING: Currently the equivalent of TRUNC, since this
18+ * returns numbers
19+ * @param values[0] number - The value to be formatted.
20+ * @param values[1] places - [ OPTIONAL - 2 by default ] - The number of decimal places to display.
21+ * @returns {number} dollars
22+ * @constructor
23+ * TODO: In GS and Excel, Dollar values are primitive types at a certain level, meaning you can do =DOLLAR(10) + 10
24+ * TODO(cont.) and the result will be 20. Right now, JS allows you to inherit from primitives so you can use operators
25+ * TODO(cont.) on them (eg: new Number(10) + 10 == 20) but TS does not. So for now, Dollar values will be represented
26+ * TODO(cont.) with the primitive number type. At some point TS might allow me to suppress the warnings with
27+ * TODO(cont.) https://github.com/Microsoft/TypeScript/issues/9448 or
28+ * TODO(cont.) https://github.com/Microsoft/TypeScript/issues/11051
29+ *
30+ * TODO: Also, this does not do local-specific, as is.
31+ */
32+var DOLLAR = function (...values) : number {
33+ ArgsChecker.checkLengthWithin(values, 1, 2);
34+ var v = TypeCaster.firstValueAsNumber(values[0]);
35+ var places = values.length === 2 ? TypeCaster.firstValueAsNumber(values[1]) : 2;
36+ var sign = (v > 0) ? 1 : -1;
37+ return sign * (Math.floor(Math.abs(v) * Math.pow(10, places))) / Math.pow(10, places);
38+};
39+
40+
41+/**
42+ * Converts a price quotation given as a decimal fraction into a decimal value.
43+ * @param values[0] fractional_price - The price quotation given using fractional decimal conventions.
44+ * @param values[1] unit - The units of the fraction, e.g. 8 for 1/8ths or 32 for 1/32nds.
45+ * @returns {number} decimal value.
46+ * @constructor
47+ */
48+var DOLLARDE = function (...values) : number {
49+ ArgsChecker.checkLength(values, 2);
50+ var dollar = TypeCaster.firstValueAsNumber(values[0]);
51+ var fraction = Math.floor(TypeCaster.firstValueAsNumber(values[1]));
52+ if (fraction === 0) {
53+ throw new CellError(ERRORS.DIV_ZERO_ERROR, "Function DOLLARDE parameter 2 cannot be zero.");
54+ }
55+ var result = parseInt(dollar.toString(), 10);
56+ result += (dollar % 1) * Math.pow(10, Math.ceil(Math.log(fraction) / Math.LN10)) / fraction;
57+ var power = Math.pow(10, Math.ceil(Math.log(fraction) / Math.LN2) + 1);
58+ if (power === 0) {
59+ throw new CellError(ERRORS.DIV_ZERO_ERROR, "Evaluation of function DOLLARDE caused a divide by zero error.");
60+ }
61+ result = Math.round(result * power) / power;
62+ return result;
63+};
64+
65+
66+/**
67+ * Converts a price quotation given as a decimal value into a decimal fraction.
68+ * @param values[0] decimal_price - The price quotation given as a decimal value.
69+ * @param values[1] unit - The units of the desired fraction, e.g. 8 for 1/8ths or 32 for 1/32nds
70+ * @returns {number} price quotation as decimal fraction.
71+ * @constructor
72+ */
73+var DOLLARFR = function (...values) : number {
74+ ArgsChecker.checkLength(values, 2);
75+ var dollar = TypeCaster.firstValueAsNumber(values[0]);
76+ var unit = Math.floor(TypeCaster.firstValueAsNumber(values[1]));
77+ if (unit === 0) {
78+ throw new CellError(ERRORS.DIV_ZERO_ERROR, "Function DOLLARFR parameter 2 cannot be zero.");
79+ }
80+ var result = parseInt(dollar.toString(), 10);
81+ result += (dollar % 1) * Math.pow(10, -Math.ceil(Math.log(unit) / Math.LN10)) * unit;
82+ return result;
83+};
84+
85+export {
86+ DOLLAR,
87+ DOLLARDE,
88+ DOLLARFR
89+}
90\ No newline at end of file
91diff --git a/src/RawFormulas/Math.ts b/src/RawFormulas/Math.ts
92index 466d7ba..a4c735c 100644
93--- a/src/RawFormulas/Math.ts
94+++ b/src/RawFormulas/Math.ts
95@@ -1843,6 +1843,128 @@ var EXPONDIST = function (...values) : number {
96 };
97
98
99+/**
100+ * Returns the number of ways to choose some number of objects from a pool of a given size of objects.
101+ * @param values[0] n - The size of the pool of objects to choose from.
102+ * @param values[1] k - The number of objects to choose.
103+ * @returns {number} number of ways
104+ * @constructor
105+ */
106+var COMBIN = function (...values) : number {
107+ var MEMOIZED_FACT = [];
108+ function fact(number) {
109+ var n = Math.floor(number);
110+ if (n === 0 || n === 1) {
111+ return 1;
112+ } else if (MEMOIZED_FACT[n] > 0) {
113+ return MEMOIZED_FACT[n];
114+ } else {
115+ MEMOIZED_FACT[n] = fact(n - 1) * n;
116+ return MEMOIZED_FACT[n];
117+ }
118+ }
119+ ArgsChecker.checkLength(values, 2);
120+ var n = TypeCaster.firstValueAsNumber(values[0]);
121+ var c = TypeCaster.firstValueAsNumber(values[1]);
122+ if (n < c) {
123+ throw new CellError(ERRORS.NUM_ERROR, "Function COMBIN parameter 2 value is "
124+ + c + ". It should be less than or equal to value of Function COMBIN parameter 1 with " + n + ".");
125+ }
126+ n = Math.floor(n);
127+ c = Math.floor(c);
128+ var div = fact(c) * fact(n - c);
129+ if (div === 0) {
130+ throw new CellError(ERRORS.DIV_ZERO_ERROR, "Evaluation of function COMBIN caused a divide by zero error.");
131+ }
132+ return fact(n) / div;
133+};
134+
135+
136+/**
137+ * Calculates r, the Pearson product-moment correlation coefficient of a dataset. Any text encountered in the arguments
138+ * will be ignored. CORREL is synonymous with PEARSON.
139+ * @param values[0] data_y - The range representing the array or matrix of dependent data.
140+ * @param values[1] data_x - The range representing the array or matrix of independent data.
141+ * @returns {number} the Pearson product-moment correlation coefficient.
142+ * @constructor
143+ */
144+var CORREL = function (...values) : number {
145+ function stdev(arr, flag) {
146+ return Math.sqrt(variance(arr, flag));
147+ }
148+ function variance(arr, flag) {
149+ if ((arr.length - (flag ? 1 : 0)) === 0) {
150+ throw new CellError(ERRORS.DIV_ZERO_ERROR, "Evaluation of function CORREL caused a divide by zero error.");
151+ }
152+ return sumsqerr(arr) / (arr.length - (flag ? 1 : 0));
153+ }
154+ function sum(arr) {
155+ var sum = 0;
156+ var i = arr.length;
157+ while (--i >= 0) {
158+ sum += arr[i];
159+ }
160+ return sum;
161+ }
162+ function mean(arr) {
163+ return sum(arr) / arr.length;
164+ }
165+ function sumsqerr(arr) {
166+ var m = mean(arr);
167+ var sum = 0;
168+ var i = arr.length;
169+ var tmp;
170+ while (--i >= 0) {
171+ tmp = arr[i] - m;
172+ sum += tmp * tmp;
173+ }
174+ return sum;
175+ }
176+ function covariance(arr1, arr2) {
177+ var u = mean(arr1);
178+ var v = mean(arr2);
179+ var arr1Len = arr1.length;
180+ var sq_dev = new Array(arr1Len);
181+ for (var i = 0; i < arr1Len; i++) {
182+ sq_dev[i] = (arr1[i] - u) * (arr2[i] - v);
183+ }
184+ if ((arr1Len - 1) === 0) {
185+ throw new CellError(ERRORS.DIV_ZERO_ERROR, "Evaluation of function CORREL caused a divide by zero error.");
186+ }
187+ return sum(sq_dev) / (arr1Len - 1);
188+ }
189+ ArgsChecker.checkLength(values, 2);
190+ if (!Array.isArray(values[0])) {
191+ values[0] = [values[0]];
192+ }
193+ if (!Array.isArray(values[1])) {
194+ values[1] = [values[1]];
195+ }
196+ if (values[0].length !== values[1].length) {
197+ throw new CellError(ERRORS.NA_ERROR, "CORREL has mismatched argument count " + values[0] + " vs " + values[1] + ".");
198+ }
199+ var arr1 = Filter.filterOutNonNumberValues(Filter.flattenAndThrow(values[0]));
200+ var arr2 = Filter.filterOutNonNumberValues(Filter.flattenAndThrow(values[1]));
201+ var stdevArr1 = stdev(arr1, 1);
202+ var stdevArr2 = stdev(arr2, 1);
203+ if (stdevArr1 === 0 || stdevArr2 === 0) {
204+ throw new CellError(ERRORS.DIV_ZERO_ERROR, "Evaluation of function CORREL caused a divide by zero error.");
205+ }
206+ return covariance(arr1, arr2) / stdev(arr1, 1) / stdev(arr2, 1);
207+};
208+
209+/**
210+ * Calculates r, the Pearson product-moment correlation coefficient of a dataset. Any text encountered in the arguments
211+ * will be ignored. PEARSON is synonymous with CORREL.
212+ * @param values[0] data_y - The range representing the array or matrix of dependent data.
213+ * @param values[1] data_x - The range representing the array or matrix of independent data.
214+ * @returns {number} the Pearson product-moment correlation coefficient.
215+ * @constructor
216+ */
217+var PEARSON = function (...values) {
218+ return CORREL.apply(this, values);
219+};
220+
221
222 export {
223 ABS,
224@@ -1916,5 +2038,8 @@ export {
225 CEILING,
226 TRUNC,
227 RADIANS,
228- DEGREES
229+ DEGREES,
230+ PEARSON,
231+ CORREL,
232+ COMBIN
233 }
234\ No newline at end of file
235diff --git a/src/RawFormulas/RawFormulas.ts b/src/RawFormulas/RawFormulas.ts
236index cbbc5c4..763a5c3 100644
237--- a/src/RawFormulas/RawFormulas.ts
238+++ b/src/RawFormulas/RawFormulas.ts
239@@ -73,7 +73,10 @@ import {
240 CEILING,
241 TRUNC,
242 RADIANS,
243- DEGREES
244+ DEGREES,
245+ PEARSON,
246+ CORREL,
247+ COMBIN
248 } from "./Math";
249 import {
250 AND,
251@@ -96,6 +99,11 @@ import {
252 DEC2HEX,
253 DEC2OCT
254 } from "./Misc";
255+import {
256+ DOLLAR,
257+ DOLLARDE,
258+ DOLLARFR
259+} from "./Financial";
260 import {
261 CriteriaFunctionFactory,
262 ArgsChecker,
263@@ -103,7 +111,9 @@ import {
264 TypeCaster,
265 Serializer
266 } from "./Utils";
267-import {CellError} from "../Errors"
268+import {
269+ CellError
270+} from "../Errors"
271 import * as ERRORS from "../Errors"
272
273 var ACCRINT = Formula["ACCRINT"];
274@@ -124,206 +134,14 @@ var EOMONTH = function (start_date, months) {
275 var edate = moment(start_date).add(months, 'months');
276 return new Date(edate.year(), edate.month(), edate.daysInMonth());
277 };
278-var __COMPLEX = {
279- "F.DIST": FDIST$LEFTTAILED
280-};
281 var YEARFRAC = Formula["YEARFRAC"];
282
283
284-/**
285- * Formats a number into the locale-specific currency format. WARNING: Currently the equivalent of TRUNC, since this
286- * returns numbers
287- * @param values[0] number - The value to be formatted.
288- * @param values[1] places - [ OPTIONAL - 2 by default ] - The number of decimal places to display.
289- * @returns {number} dollars
290- * @constructor
291- * TODO: In GS and Excel, Dollar values are primitive types at a certain level, meaning you can do =DOLLAR(10) + 10
292- * TODO(cont.) and the result will be 20. Right now, JS allows you to inherit from primitives so you can use operators
293- * TODO(cont.) on them (eg: new Number(10) + 10 == 20) but TS does not. So for now, Dollar values will be represented
294- * TODO(cont.) with the primitive number type. At some point TS might allow me to suppress the warnings with
295- * TODO(cont.) https://github.com/Microsoft/TypeScript/issues/9448 or
296- * TODO(cont.) https://github.com/Microsoft/TypeScript/issues/11051
297- *
298- * TODO: Also, this does not do local-specific, as is.
299- */
300-var DOLLAR = function (...values) : number {
301- ArgsChecker.checkLengthWithin(values, 1, 2);
302- var v = TypeCaster.firstValueAsNumber(values[0]);
303- var places = values.length === 2 ? TypeCaster.firstValueAsNumber(values[1]) : 2;
304- var sign = (v > 0) ? 1 : -1;
305- return sign * (Math.floor(Math.abs(v) * Math.pow(10, places))) / Math.pow(10, places);
306-};
307-
308-
309-/**
310- * Converts a price quotation given as a decimal fraction into a decimal value.
311- * @param values[0] fractional_price - The price quotation given using fractional decimal conventions.
312- * @param values[1] unit - The units of the fraction, e.g. 8 for 1/8ths or 32 for 1/32nds.
313- * @returns {number} decimal value.
314- * @constructor
315- */
316-var DOLLARDE = function (...values) : number {
317- ArgsChecker.checkLength(values, 2);
318- var dollar = TypeCaster.firstValueAsNumber(values[0]);
319- var fraction = Math.floor(TypeCaster.firstValueAsNumber(values[1]));
320- if (fraction === 0) {
321- throw new CellError(ERRORS.DIV_ZERO_ERROR, "Function DOLLARDE parameter 2 cannot be zero.");
322- }
323- var result = parseInt(dollar.toString(), 10);
324- result += (dollar % 1) * Math.pow(10, Math.ceil(Math.log(fraction) / Math.LN10)) / fraction;
325- var power = Math.pow(10, Math.ceil(Math.log(fraction) / Math.LN2) + 1);
326- if (power === 0) {
327- throw new CellError(ERRORS.DIV_ZERO_ERROR, "Evaluation of function DOLLARDE caused a divide by zero error.");
328- }
329- result = Math.round(result * power) / power;
330- return result;
331-};
332-
333-
334-/**
335- * Converts a price quotation given as a decimal value into a decimal fraction.
336- * @param values[0] decimal_price - The price quotation given as a decimal value.
337- * @param values[1] unit - The units of the desired fraction, e.g. 8 for 1/8ths or 32 for 1/32nds
338- * @returns {number} price quotation as decimal fraction.
339- * @constructor
340- */
341-var DOLLARFR = function (...values) : number {
342- ArgsChecker.checkLength(values, 2);
343- var dollar = TypeCaster.firstValueAsNumber(values[0]);
344- var unit = Math.floor(TypeCaster.firstValueAsNumber(values[1]));
345- if (unit === 0) {
346- throw new CellError(ERRORS.DIV_ZERO_ERROR, "Function DOLLARFR parameter 2 cannot be zero.");
347- }
348- var result = parseInt(dollar.toString(), 10);
349- result += (dollar % 1) * Math.pow(10, -Math.ceil(Math.log(unit) / Math.LN10)) * unit;
350- return result;
351-};
352-
353-
354-
355-/**
356- * Returns the number of ways to choose some number of objects from a pool of a given size of objects.
357- * @param values[0] n - The size of the pool of objects to choose from.
358- * @param values[1] k - The number of objects to choose.
359- * @returns {number} number of ways
360- * @constructor
361- */
362-var COMBIN = function (...values) : number {
363- var MEMOIZED_FACT = [];
364- function fact(number) {
365- var n = Math.floor(number);
366- if (n === 0 || n === 1) {
367- return 1;
368- } else if (MEMOIZED_FACT[n] > 0) {
369- return MEMOIZED_FACT[n];
370- } else {
371- MEMOIZED_FACT[n] = fact(n - 1) * n;
372- return MEMOIZED_FACT[n];
373- }
374- }
375- ArgsChecker.checkLength(values, 2);
376- var n = TypeCaster.firstValueAsNumber(values[0]);
377- var c = TypeCaster.firstValueAsNumber(values[1]);
378- if (n < c) {
379- throw new CellError(ERRORS.NUM_ERROR, "Function COMBIN parameter 2 value is "
380- + c + ". It should be less than or equal to value of Function COMBIN parameter 1 with " + n + ".");
381- }
382- n = Math.floor(n);
383- c = Math.floor(c);
384- var div = fact(c) * fact(n - c);
385- if (div === 0) {
386- throw new CellError(ERRORS.DIV_ZERO_ERROR, "Evaluation of function COMBIN caused a divide by zero error.");
387- }
388- return fact(n) / div;
389-};
390-
391-
392-/**
393- * Calculates r, the Pearson product-moment correlation coefficient of a dataset. Any text encountered in the arguments
394- * will be ignored. CORREL is synonymous with PEARSON.
395- * @param values[0] data_y - The range representing the array or matrix of dependent data.
396- * @param values[1] data_x - The range representing the array or matrix of independent data.
397- * @returns {number} the Pearson product-moment correlation coefficient.
398- * @constructor
399- */
400-var CORREL = function (...values) : number {
401- function stdev(arr, flag) {
402- return Math.sqrt(variance(arr, flag));
403- }
404- function variance(arr, flag) {
405- if ((arr.length - (flag ? 1 : 0)) === 0) {
406- throw new CellError(ERRORS.DIV_ZERO_ERROR, "Evaluation of function CORREL caused a divide by zero error.");
407- }
408- return sumsqerr(arr) / (arr.length - (flag ? 1 : 0));
409- }
410- function sum(arr) {
411- var sum = 0;
412- var i = arr.length;
413- while (--i >= 0) {
414- sum += arr[i];
415- }
416- return sum;
417- }
418- function mean(arr) {
419- return sum(arr) / arr.length;
420- }
421- function sumsqerr(arr) {
422- var m = mean(arr);
423- var sum = 0;
424- var i = arr.length;
425- var tmp;
426- while (--i >= 0) {
427- tmp = arr[i] - m;
428- sum += tmp * tmp;
429- }
430- return sum;
431- }
432- function covariance(arr1, arr2) {
433- var u = mean(arr1);
434- var v = mean(arr2);
435- var arr1Len = arr1.length;
436- var sq_dev = new Array(arr1Len);
437- for (var i = 0; i < arr1Len; i++) {
438- sq_dev[i] = (arr1[i] - u) * (arr2[i] - v);
439- }
440- if ((arr1Len - 1) === 0) {
441- throw new CellError(ERRORS.DIV_ZERO_ERROR, "Evaluation of function CORREL caused a divide by zero error.");
442- }
443- return sum(sq_dev) / (arr1Len - 1);
444- }
445- ArgsChecker.checkLength(values, 2);
446- if (!Array.isArray(values[0])) {
447- values[0] = [values[0]];
448- }
449- if (!Array.isArray(values[1])) {
450- values[1] = [values[1]];
451- }
452- if (values[0].length !== values[1].length) {
453- throw new CellError(ERRORS.NA_ERROR, "CORREL has mismatched argument count " + values[0] + " vs " + values[1] + ".");
454- }
455- var arr1 = Filter.filterOutNonNumberValues(Filter.flattenAndThrow(values[0]));
456- var arr2 = Filter.filterOutNonNumberValues(Filter.flattenAndThrow(values[1]));
457- var stdevArr1 = stdev(arr1, 1);
458- var stdevArr2 = stdev(arr2, 1);
459- if (stdevArr1 === 0 || stdevArr2 === 0) {
460- throw new CellError(ERRORS.DIV_ZERO_ERROR, "Evaluation of function CORREL caused a divide by zero error.");
461- }
462- return covariance(arr1, arr2) / stdev(arr1, 1) / stdev(arr2, 1);
463-};
464-
465-/**
466- * Calculates r, the Pearson product-moment correlation coefficient of a dataset. Any text encountered in the arguments
467- * will be ignored. PEARSON is synonymous with CORREL.
468- * @param values[0] data_y - The range representing the array or matrix of dependent data.
469- * @param values[1] data_x - The range representing the array or matrix of independent data.
470- * @returns {number} the Pearson product-moment correlation coefficient.
471- * @constructor
472- */
473-var PEARSON = function (...values) {
474- return CORREL.apply(this, values);
475+// Using alias to bind dot-notation function names.
476+var __COMPLEX = {
477+ "F.DIST": FDIST$LEFTTAILED
478 };
479
480-
481 export {
482 __COMPLEX,
483