commit
message
Added Formulas.COMBIN
author
Ben Vogt <[email protected]>
date
2017-02-20 18:02:49
stats
3 file(s) changed,
78 insertions(+),
2 deletions(-)
files
README.md
src/RawFormulas/RawFormulas.ts
tests/FormulasTest.ts
1diff --git a/README.md b/README.md
2index 1eace99..3b16fe2 100644
3--- a/README.md
4+++ b/README.md
5@@ -32,4 +32,16 @@ arbitrary javascript is executed in the client machine.
6 * ...etc.
7
8 ### Refactor the way we construct and throw errors
9-For example, the mis-matched argument length errors are all generated the same way.
10\ No newline at end of file
11+For example, the mis-matched argument length errors are all generated the same way.
12+
13+### Refactor the way tests are organized.
14+Group by error type and have some useful functions that will call with 0, N, N+1 args to test the args
15+checker. Also, test for *all possible* errors that could be thrown, and *all possible types* that could be passed in.
16+Another thing to think about would be throwing custom errors if an object is passed in.
17+
18+### DIV_ZERO Error
19+This error is thrown every time we're about to divide by zero in a formula. There are definitely a couple formulas that
20+don't check for this, and they should.
21+
22+### jStat functions should know their caller
23+Either through `arguments`, or directly passed in like `mean("FORMULA", [10, 20, 30])`
24diff --git a/src/RawFormulas/RawFormulas.ts b/src/RawFormulas/RawFormulas.ts
25index 82f2adf..dd375f1 100644
26--- a/src/RawFormulas/RawFormulas.ts
27+++ b/src/RawFormulas/RawFormulas.ts
28@@ -106,7 +106,6 @@ import {CellError, NUM_ERROR} from "../Errors"
29 import * as ERRORS from "../Errors"
30
31 var ACCRINT = Formula["ACCRINT"];
32-var COMBIN = Formula["COMBIN"];
33 var CONVERT = Formula["CONVERT"];
34 var CUMIPMT = Formula["CUMIPMT"];
35 var CUMPRINC = Formula["CUMPRINC"];
36@@ -133,6 +132,44 @@ var __COMPLEX = {
37 };
38 var YEARFRAC = Formula["YEARFRAC"];
39
40+
41+/**
42+ * Returns the number of ways to choose some number of objects from a pool of a given size of objects.
43+ * @param values[0] n - The size of the pool of objects to choose from.
44+ * @param values[1] k - The number of objects to choose.
45+ * @returns {number} number of ways
46+ * @constructor
47+ */
48+var COMBIN = function (...values) : number {
49+ var MEMOIZED_FACT = [];
50+ function fact(number) {
51+ var n = Math.floor(number);
52+ if (n === 0 || n === 1) {
53+ return 1;
54+ } else if (MEMOIZED_FACT[n] > 0) {
55+ return MEMOIZED_FACT[n];
56+ } else {
57+ MEMOIZED_FACT[n] = fact(n - 1) * n;
58+ return MEMOIZED_FACT[n];
59+ }
60+ }
61+ ArgsChecker.checkLength(values, 2);
62+ var n = TypeCaster.firstValueAsNumber(values[0]);
63+ var c = TypeCaster.firstValueAsNumber(values[1]);
64+ if (n < c) {
65+ throw new CellError(ERRORS.NUM_ERROR, "Function COMBIN parameter 2 value is "
66+ + c + ". It should be less than or equal to value of Function COMBIN parameter 1 with " + n + ".");
67+ }
68+ n = Math.floor(n);
69+ c = Math.floor(c);
70+ var div = fact(c) * fact(n - c);
71+ if (div === 0) {
72+ throw new CellError(ERRORS.DIV_ZERO_ERROR, "Evaluation of function COMBIN caused a divide by zero error.");
73+ }
74+ return fact(n) / div;
75+};
76+
77+
78 /**
79 * Calculates r, the Pearson product-moment correlation coefficient of a dataset. Any text encountered in the arguments
80 * will be ignored. CORREL is synonymous with PEARSON.
81diff --git a/tests/FormulasTest.ts b/tests/FormulasTest.ts
82index a9df7a4..a10646d 100644
83--- a/tests/FormulasTest.ts
84+++ b/tests/FormulasTest.ts
85@@ -419,7 +419,33 @@ assertEquals(CODE(['a']), 97);
86 assertEquals(CODE([['a'], 'p']), 97);
87
88
89+// Test COMBIN
90 assertEquals(COMBIN(4, 2), 6);
91+assertEquals(COMBIN(4.999, 2.888), 6);
92+assertEquals(COMBIN([4, "str"], [2]), 6);
93+assertEquals(COMBIN(0, 0), 1);
94+catchAndAssertEquals(function() {
95+ COMBIN(2, "str");
96+}, ERRORS.VALUE_ERROR);
97+catchAndAssertEquals(function() {
98+ COMBIN(2, []);
99+}, ERRORS.REF_ERROR);
100+catchAndAssertEquals(function() {
101+ COMBIN(2, 4);
102+}, ERRORS.NUM_ERROR);
103+catchAndAssertEquals(function() {
104+ COMBIN(0, 1);
105+}, ERRORS.NUM_ERROR);
106+catchAndAssertEquals(function() {
107+ COMBIN();
108+}, ERRORS.NA_ERROR);
109+catchAndAssertEquals(function() {
110+ COMBIN(4);
111+}, ERRORS.NA_ERROR);
112+catchAndAssertEquals(function() {
113+ COMBIN(4, 2, 66);
114+}, ERRORS.NA_ERROR);
115+
116
117
118 // Test CONCATENATE