spreadsheet
typeScript/javascript spreadsheet parser, with formulas.
git clone https://git.vogt.world/spreadsheet.git
Log | Files | README.md
← Commit log
commit
message
[BINOMDIST] formula added and tested
author
Ben Vogt <[email protected]>
date
2017-07-08 14:13:27
stats
7 file(s) changed, 173 insertions(+), 8 deletions(-)
files
DOCS.md
TODO.md
dist/Formulas/AllFormulas.js
dist/Formulas/Statistical.js
src/Formulas/AllFormulas.ts
src/Formulas/Statistical.ts
tests/Formulas/StatisticalTest.ts
  1diff --git a/DOCS.md b/DOCS.md
  2index f27f203..88a439e 100644
  3--- a/DOCS.md
  4+++ b/DOCS.md
  5@@ -1848,6 +1848,18 @@
  6 @returns {number} 
  7 @constructor
  8 ```
  9+
 10+### BINOMDIST 
 11+
 12+```
 13+  Returns the individual term binomial distribution probability. 
 14+@param successes - The number of successes in a set of trials. 
 15+@param trials - The number of independent trials. 
 16+@param probability - The probability of success on each trial. 
 17+@param cumulative - 0 calculates the probability of a single event, 1 calculates the cumulative probability. 
 18+@returns {number} 
 19+@constructor
 20+```
 21 ## Text
 22 
 23 
 24diff --git a/TODO.md b/TODO.md
 25index 1b60759..91e8cfb 100644
 26--- a/TODO.md
 27+++ b/TODO.md
 28@@ -54,7 +54,6 @@ For example 64 tbs to a qt.
 29 * TO_DOLLARS - Contingent upon cells having display formats derived from type-hierarchy
 30 * TO_PERCENT - Contingent upon cells having display formats derived from type-hierarchy
 31 * TO_TEXT - Contingent upon cells having display formats derived from type-hierarchy
 32-* BINOMDIST
 33 * COVAR
 34 * CRITBINOM
 35 * F.DIST.RT
 36diff --git a/dist/Formulas/AllFormulas.js b/dist/Formulas/AllFormulas.js
 37index 379513a..6a837e8 100644
 38--- a/dist/Formulas/AllFormulas.js
 39+++ b/dist/Formulas/AllFormulas.js
 40@@ -169,6 +169,7 @@ exports.NEGBINOMDIST = Statistical_1.NEGBINOMDIST;
 41 exports.GEOMEAN = Statistical_1.GEOMEAN;
 42 exports.HARMEAN = Statistical_1.HARMEAN;
 43 exports.CONFIDENCE = Statistical_1.CONFIDENCE;
 44+exports.BINOMDIST = Statistical_1.BINOMDIST;
 45 var Text_1 = require("./Text");
 46 exports.ARABIC = Text_1.ARABIC;
 47 exports.CHAR = Text_1.CHAR;
 48diff --git a/dist/Formulas/Statistical.js b/dist/Formulas/Statistical.js
 49index b1a0f8e..137bd06 100644
 50--- a/dist/Formulas/Statistical.js
 51+++ b/dist/Formulas/Statistical.js
 52@@ -1342,10 +1342,10 @@ exports.HARMEAN = HARMEAN;
 53  * @constructor
 54  */
 55 var CONFIDENCE = function (alpha, standDev, size) {
 56+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 3, "CONFIDENCE");
 57     alpha = TypeConverter_1.TypeConverter.firstValueAsNumber(alpha);
 58     standDev = TypeConverter_1.TypeConverter.firstValueAsNumber(standDev);
 59     size = TypeConverter_1.TypeConverter.firstValueAsNumber(size);
 60-    ArgsChecker_1.ArgsChecker.checkLength(arguments, 3, "CONFIDENCE");
 61     if (alpha <= 0 || alpha >= 1) {
 62         throw new Errors_1.NumError("Function CONFIDENCE parameter 1 value is " + alpha
 63             + ". Valid values are between 0 and 1 exclusively.");
 64@@ -1415,3 +1415,65 @@ var CONFIDENCE = function (alpha, standDev, size) {
 65     return _normalci(1, alpha, standDev, size)[1] - 1;
 66 };
 67 exports.CONFIDENCE = CONFIDENCE;
 68+/**
 69+ * Returns the individual term binomial distribution probability.
 70+ * @param successes - The number of successes in a set of trials.
 71+ * @param trials - The number of independent trials.
 72+ * @param probability - The probability of success on each trial.
 73+ * @param cumulative - 0 calculates the probability of a single event, 1 calculates the cumulative probability.
 74+ * @returns {number}
 75+ * @constructor
 76+ */
 77+var BINOMDIST = function (successes, trials, probability, cumulative) {
 78+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 4, "BINOMDIST");
 79+    successes = TypeConverter_1.TypeConverter.firstValueAsNumber(successes);
 80+    trials = TypeConverter_1.TypeConverter.firstValueAsNumber(trials);
 81+    probability = TypeConverter_1.TypeConverter.firstValueAsNumber(probability);
 82+    cumulative = TypeConverter_1.TypeConverter.firstValueAsNumber(cumulative);
 83+    function _binomialCDF(x, n, p) {
 84+        var binomarr = [], k = 0;
 85+        if (x < 0) {
 86+            return 0;
 87+        }
 88+        if (x < n) {
 89+            for (; k <= x; k++) {
 90+                binomarr[k] = _binomialPDF(k, n, p);
 91+            }
 92+            return MathHelpers_1.sum(binomarr);
 93+        }
 94+        return 1;
 95+    }
 96+    function _combination(n, m) {
 97+        // make sure n or m don't exceed the upper limit of usable values
 98+        return (n > 170 || m > 170)
 99+            ? Math.exp(_combinationln(n, m))
100+            : (_factorial(n) / _factorial(m)) / _factorial(n - m);
101+    }
102+    function _factorial(n) {
103+        return n < 0 ? NaN : MathHelpers_1.gammafn(n + 1);
104+    }
105+    function _factorialln(n) {
106+        return n < 0 ? NaN : MathHelpers_1.gammaln(n + 1);
107+    }
108+    function _combinationln(n, m) {
109+        return _factorialln(n) - _factorialln(m) - _factorialln(n - m);
110+    }
111+    function _binomialPDF(k, n, p) {
112+        return (p === 0 || p === 1) ?
113+            ((n * p) === k ? 1 : 0) :
114+            _combination(n, k) * Math.pow(p, k) * Math.pow(1 - p, n - k);
115+    }
116+    if (trials < 0) {
117+        throw new Errors_1.NumError("Function BINOMDIST parameter 2 value is " + trials + ", but should be greater than 0.");
118+    }
119+    if (trials < successes) {
120+        throw new Errors_1.NumError("Function BINOMDIST parameter 1 value is " + trials
121+            + ". It should be less than or equal to value of Function BINOMDIST parameter 2 with " + successes + ".");
122+    }
123+    if (probability > 1 || probability < 0) {
124+        throw new Errors_1.NumError("Function BINOMDIST parameter 3 value is " + probability
125+            + ", but should be between 0 and 1 inclusive.");
126+    }
127+    return (cumulative) ? _binomialCDF(successes, trials, probability) : _binomialPDF(successes, trials, probability);
128+};
129+exports.BINOMDIST = BINOMDIST;
130diff --git a/src/Formulas/AllFormulas.ts b/src/Formulas/AllFormulas.ts
131index 13960c6..c30dc27 100644
132--- a/src/Formulas/AllFormulas.ts
133+++ b/src/Formulas/AllFormulas.ts
134@@ -174,7 +174,8 @@ import {
135   NEGBINOMDIST,
136   GEOMEAN,
137   HARMEAN,
138-  CONFIDENCE
139+  CONFIDENCE,
140+  BINOMDIST
141 } from "./Statistical";
142 import {
143   ARABIC,
144@@ -420,5 +421,6 @@ export {
145   CONFIDENCE,
146   N,
147   UNARY_PERCENT,
148-  MULTINOMIAL
149+  MULTINOMIAL,
150+  BINOMDIST
151 }
152\ No newline at end of file
153diff --git a/src/Formulas/Statistical.ts b/src/Formulas/Statistical.ts
154index c4adb45..24d1d79 100644
155--- a/src/Formulas/Statistical.ts
156+++ b/src/Formulas/Statistical.ts
157@@ -28,7 +28,8 @@ import {
158   mean,
159   gammafn,
160   sum,
161-  erf
162+  erf,
163+  gammaln
164 } from "../Utilities/MathHelpers";
165 
166 
167@@ -1339,10 +1340,10 @@ var HARMEAN = function (...values) {
168  * @constructor
169  */
170 var CONFIDENCE = function (alpha, standDev, size) {
171+  ArgsChecker.checkLength(arguments, 3, "CONFIDENCE");
172   alpha = TypeConverter.firstValueAsNumber(alpha);
173   standDev = TypeConverter.firstValueAsNumber(standDev);
174   size = TypeConverter.firstValueAsNumber(size);
175-  ArgsChecker.checkLength(arguments, 3, "CONFIDENCE");
176   if (alpha <= 0 || alpha >= 1) {
177     throw new NumError("Function CONFIDENCE parameter 1 value is " + alpha
178         + ". Valid values are between 0 and 1 exclusively.");
179@@ -1408,6 +1409,70 @@ var CONFIDENCE = function (alpha, standDev, size) {
180 };
181 
182 
183+/**
184+ * Returns the individual term binomial distribution probability.
185+ * @param successes - The number of successes in a set of trials.
186+ * @param trials - The number of independent trials.
187+ * @param probability - The probability of success on each trial.
188+ * @param cumulative - 0 calculates the probability of a single event, 1 calculates the cumulative probability.
189+ * @returns {number}
190+ * @constructor
191+ */
192+var BINOMDIST = function (successes, trials, probability, cumulative) {
193+  ArgsChecker.checkLength(arguments, 4, "BINOMDIST");
194+  successes = TypeConverter.firstValueAsNumber(successes);
195+  trials = TypeConverter.firstValueAsNumber(trials);
196+  probability = TypeConverter.firstValueAsNumber(probability);
197+  cumulative = TypeConverter.firstValueAsNumber(cumulative);
198+  function _binomialCDF(x, n, p) {
199+    var binomarr = [],
200+      k = 0;
201+    if (x < 0) {
202+      return 0;
203+    }
204+    if (x < n) {
205+      for (; k <= x; k++) {
206+        binomarr[ k ] = _binomialPDF(k, n, p);
207+      }
208+      return sum(binomarr);
209+    }
210+    return 1;
211+  }
212+  function _combination(n, m) {
213+    // make sure n or m don't exceed the upper limit of usable values
214+    return (n > 170 || m > 170)
215+      ? Math.exp(_combinationln(n, m))
216+      : (_factorial(n) / _factorial(m)) / _factorial(n - m);
217+  }
218+  function _factorial(n) {
219+    return n < 0 ? NaN : gammafn(n + 1);
220+  }
221+  function _factorialln(n) {
222+    return n < 0 ? NaN : gammaln(n + 1);
223+  }
224+  function _combinationln(n, m) {
225+    return _factorialln(n) - _factorialln(m) - _factorialln(n - m);
226+  }
227+  function _binomialPDF(k, n, p) {
228+    return (p === 0 || p === 1) ?
229+      ((n * p) === k ? 1 : 0) :
230+    _combination(n, k) * Math.pow(p, k) * Math.pow(1 - p, n - k);
231+  }
232+  if (trials < 0) {
233+    throw new NumError("Function BINOMDIST parameter 2 value is " + trials + ", but should be greater than 0.");
234+  }
235+  if (trials < successes) {
236+    throw new NumError("Function BINOMDIST parameter 1 value is " + trials
237+        + ". It should be less than or equal to value of Function BINOMDIST parameter 2 with " + successes + ".");
238+  }
239+  if (probability > 1 || probability < 0) {
240+    throw new NumError("Function BINOMDIST parameter 3 value is " + probability
241+        + ", but should be between 0 and 1 inclusive.");
242+  }
243+  return (cumulative) ? _binomialCDF(successes, trials, probability) : _binomialPDF(successes, trials, probability);
244+};
245+
246+
247 export {
248   AVERAGE,
249   AVERAGEA,
250@@ -1452,5 +1517,6 @@ export {
251   NEGBINOMDIST,
252   GEOMEAN,
253   HARMEAN,
254-  CONFIDENCE
255+  CONFIDENCE,
256+  BINOMDIST
257 }
258\ No newline at end of file
259diff --git a/tests/Formulas/StatisticalTest.ts b/tests/Formulas/StatisticalTest.ts
260index 4dcf84a..b1ae495 100644
261--- a/tests/Formulas/StatisticalTest.ts
262+++ b/tests/Formulas/StatisticalTest.ts
263@@ -42,7 +42,8 @@ import {
264   NEGBINOMDIST,
265   GEOMEAN,
266   HARMEAN,
267-  CONFIDENCE
268+  CONFIDENCE,
269+  BINOMDIST
270 } from "../../src/Formulas/Statistical";
271 import * as ERRORS from "../../src/Errors";
272 import {
273@@ -893,4 +894,25 @@ test("CONFIDENCE", function() {
274   catchAndAssertEquals(function() {
275     CONFIDENCE.apply(this, [0.8, 101.1, 24281, 22]);
276   }, ERRORS.NA_ERROR);
277+});
278+
279+test("BINOMDIST", function() {
280+  assertEquals(BINOMDIST(20, 22, 0.04, true), 0.9999999999999998);
281+  assertEquals(BINOMDIST(14, 22, 0.4, true), 0.9929516025629364);
282+  assertEquals(BINOMDIST(14, 22, 0.4, false), 0.014417421604478797);
283+  catchAndAssertEquals(function() {
284+    BINOMDIST(21, 20, 0.4, false);
285+  }, ERRORS.NUM_ERROR);
286+  catchAndAssertEquals(function() {
287+    BINOMDIST(20, 20, -1, false);
288+  }, ERRORS.NUM_ERROR);
289+  catchAndAssertEquals(function() {
290+    BINOMDIST(20, 0, -1, false);
291+  }, ERRORS.NUM_ERROR);
292+  catchAndAssertEquals(function() {
293+    BINOMDIST.apply(this, [20, 20, 1]);
294+  }, ERRORS.NA_ERROR);
295+  catchAndAssertEquals(function() {
296+    BINOMDIST.apply(this, [20, 20, 1, true, 10]);
297+  }, ERRORS.NA_ERROR);
298 });
299\ No newline at end of file