spreadsheet
typeScript/javascript spreadsheet parser, with formulas.
git clone https://git.vogt.world/spreadsheet.git
Log | Files | README.md
← Commit log
commit
message
[TDIST] formula added and tested
author
Ben Vogt <[email protected]>
date
2017-08-06 15:08:57
stats
8 file(s) changed, 221 insertions(+), 6 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
tests/SheetFormulaTest.ts
  1diff --git a/DOCS.md b/DOCS.md
  2index a17eef6..e7b77cf 100644
  3--- a/DOCS.md
  4+++ b/DOCS.md
  5@@ -2123,6 +2123,17 @@
  6 @returns {number} 
  7 @constructor
  8 ```
  9+
 10+### TDIST 
 11+
 12+```
 13+  Returns the t-distribution for the given number. 
 14+@param x - Value to use in calculation. 
 15+@param degreesOfFreedom - The number of degrees of freedom for the t-distribution. 
 16+@param tails - 1 returns the one-tailed test, 2 returns the two-tailed test. 
 17+@returns {number} 
 18+@constructor
 19+```
 20 ## Text
 21 
 22 
 23diff --git a/TODO.md b/TODO.md
 24index 16ccfc2..d205a46 100644
 25--- a/TODO.md
 26+++ b/TODO.md
 27@@ -66,7 +66,6 @@ Many of these formulas can be written by allowing the Sheet and Parser to return
 28 * LOGINV
 29 * T.INV
 30 * T.INV.2T
 31-* TDIST
 32 * TINV
 33 * TTEST
 34 * ZTEST
 35diff --git a/dist/Formulas/AllFormulas.js b/dist/Formulas/AllFormulas.js
 36index daf55a8..443a5b7 100644
 37--- a/dist/Formulas/AllFormulas.js
 38+++ b/dist/Formulas/AllFormulas.js
 39@@ -197,6 +197,7 @@ exports.RANK = Statistical_1.RANK;
 40 exports.RANK$AVG = Statistical_1.RANK$AVG;
 41 exports.RANK$EQ = Statistical_1.RANK$EQ;
 42 exports.LOGNORMDIST = Statistical_1.LOGNORMDIST;
 43+exports.TDIST = Statistical_1.TDIST;
 44 var Text_1 = require("./Text");
 45 exports.ARABIC = Text_1.ARABIC;
 46 exports.CHAR = Text_1.CHAR;
 47diff --git a/dist/Formulas/Statistical.js b/dist/Formulas/Statistical.js
 48index a14a3c4..b5d50de 100644
 49--- a/dist/Formulas/Statistical.js
 50+++ b/dist/Formulas/Statistical.js
 51@@ -1978,3 +1978,85 @@ var LOGNORMDIST = function (x, meanValue, standardDev) {
 52     return 0.5 + 0.5 * MathHelpers_1.erf(a);
 53 };
 54 exports.LOGNORMDIST = LOGNORMDIST;
 55+/**
 56+ * Returns the t-distribution for the given number.
 57+ * @param x - Value to use in calculation.
 58+ * @param degreesOfFreedom - The number of degrees of freedom for the t-distribution.
 59+ * @param tails - 1 returns the one-tailed test, 2 returns the two-tailed test.
 60+ * @returns {number}
 61+ * @constructor
 62+ */
 63+var TDIST = function (x, degreesOfFreedom, tails) {
 64+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 3, "TDIST");
 65+    x = TypeConverter_1.TypeConverter.firstValueAsNumber(x);
 66+    degreesOfFreedom = TypeConverter_1.TypeConverter.firstValueAsNumber(degreesOfFreedom);
 67+    tails = TypeConverter_1.TypeConverter.firstValueAsNumber(tails);
 68+    if (tails < 1 || tails > 2) {
 69+        throw new Errors_1.NumError("Function TDIST parameter 3 value is " + tails +
 70+            ", but valid values are between 1 and 2, inclusively.");
 71+    }
 72+    if (degreesOfFreedom < 1) {
 73+        throw new Errors_1.NumError("Function TDIST parameter 2 value is " + degreesOfFreedom +
 74+            ", but it should be greater than or equal to 1.");
 75+    }
 76+    if (x < 0) {
 77+        throw new Errors_1.NumError("Function TDIST parameter 1 value is " + x + ", but it should be greater than or equal to 0.");
 78+    }
 79+    function _betacf(x, a, b) {
 80+        var fpmin = 1e-30;
 81+        var m = 1;
 82+        var qab = a + b;
 83+        var qap = a + 1;
 84+        var qam = a - 1;
 85+        var c = 1;
 86+        var d = 1 - qab * x / qap;
 87+        var m2, aa, del, h;
 88+        if (Math.abs(d) < fpmin)
 89+            d = fpmin;
 90+        d = 1 / d;
 91+        h = d;
 92+        for (; m <= 100; m++) {
 93+            m2 = 2 * m;
 94+            aa = m * (b - m) * x / ((qam + m2) * (a + m2));
 95+            d = 1 + aa * d;
 96+            if (Math.abs(d) < fpmin)
 97+                d = fpmin;
 98+            c = 1 + aa / c;
 99+            if (Math.abs(c) < fpmin)
100+                c = fpmin;
101+            d = 1 / d;
102+            h *= d * c;
103+            aa = -(a + m) * (qab + m) * x / ((a + m2) * (qap + m2));
104+            d = 1 + aa * d;
105+            if (Math.abs(d) < fpmin)
106+                d = fpmin;
107+            c = 1 + aa / c;
108+            if (Math.abs(c) < fpmin)
109+                c = fpmin;
110+            d = 1 / d;
111+            del = d * c;
112+            h *= del;
113+            if (Math.abs(del - 1.0) < 3e-7)
114+                break;
115+        }
116+        return h;
117+    }
118+    function _ibeta(x, a, b) {
119+        var bt = (x === 0 || x === 1) ? 0 :
120+            Math.exp(MathHelpers_1.gammaln(a + b) - MathHelpers_1.gammaln(a) -
121+                MathHelpers_1.gammaln(b) + a * Math.log(x) + b *
122+                Math.log(1 - x));
123+        if (x < 0 || x > 1)
124+            return 0;
125+        if (x < (a + 1) / (a + b + 2))
126+            return bt * _betacf(x, a, b) / a;
127+        return 1 - bt * _betacf(1 - x, b, a) / b;
128+    }
129+    function _studenttCDF(x, dof) {
130+        var dof2 = dof / 2;
131+        return _ibeta((x + Math.sqrt(x * x + dof)) /
132+            (2 * Math.sqrt(x * x + dof)), dof2, dof2);
133+    }
134+    return tails * (1 - _studenttCDF(x, degreesOfFreedom));
135+};
136+exports.TDIST = TDIST;
137diff --git a/src/Formulas/AllFormulas.ts b/src/Formulas/AllFormulas.ts
138index 427e42e..4533e77 100644
139--- a/src/Formulas/AllFormulas.ts
140+++ b/src/Formulas/AllFormulas.ts
141@@ -202,7 +202,8 @@ import {
142   RANK,
143   RANK$AVG,
144   RANK$EQ,
145-  LOGNORMDIST
146+  LOGNORMDIST,
147+  TDIST
148 } from "./Statistical";
149 import {
150   ARABIC,
151@@ -481,5 +482,6 @@ export {
152   RANK,
153   RANK$AVG,
154   RANK$EQ,
155-  LOGNORMDIST
156+  LOGNORMDIST,
157+  TDIST
158 }
159\ No newline at end of file
160diff --git a/src/Formulas/Statistical.ts b/src/Formulas/Statistical.ts
161index 0c1a530..fb2054a 100644
162--- a/src/Formulas/Statistical.ts
163+++ b/src/Formulas/Statistical.ts
164@@ -1963,6 +1963,92 @@ var LOGNORMDIST = function (x, meanValue, standardDev) {
165 };
166 
167 
168+/**
169+ * Returns the t-distribution for the given number.
170+ * @param x - Value to use in calculation.
171+ * @param degreesOfFreedom - The number of degrees of freedom for the t-distribution.
172+ * @param tails - 1 returns the one-tailed test, 2 returns the two-tailed test.
173+ * @returns {number}
174+ * @constructor
175+ */
176+var TDIST = function (x, degreesOfFreedom, tails) {
177+  ArgsChecker.checkLength(arguments, 3, "TDIST");
178+  x = TypeConverter.firstValueAsNumber(x);
179+  degreesOfFreedom = TypeConverter.firstValueAsNumber(degreesOfFreedom);
180+  tails = TypeConverter.firstValueAsNumber(tails);
181+  if (tails < 1 || tails > 2) {
182+    throw new NumError("Function TDIST parameter 3 value is " + tails +
183+        ", but valid values are between 1 and 2, inclusively.");
184+  }
185+  if (degreesOfFreedom < 1) {
186+    throw new NumError("Function TDIST parameter 2 value is " + degreesOfFreedom +
187+        ", but it should be greater than or equal to 1.");
188+  }
189+  if (x < 0) {
190+    throw new NumError("Function TDIST parameter 1 value is " + x + ", but it should be greater than or equal to 0.");
191+  }
192+  function _betacf(x, a, b) {
193+    var fpmin = 1e-30;
194+    var m = 1;
195+    var qab = a + b;
196+    var qap = a + 1;
197+    var qam = a - 1;
198+    var c = 1;
199+    var d = 1 - qab * x / qap;
200+    var m2, aa, del, h;
201+
202+    if (Math.abs(d) < fpmin)
203+      d = fpmin;
204+    d = 1 / d;
205+    h = d;
206+
207+    for (; m <= 100; m++) {
208+      m2 = 2 * m;
209+      aa = m * (b - m) * x / ((qam + m2) * (a + m2));
210+      d = 1 + aa * d;
211+      if (Math.abs(d) < fpmin)
212+        d = fpmin;
213+      c = 1 + aa / c;
214+      if (Math.abs(c) < fpmin)
215+        c = fpmin;
216+      d = 1 / d;
217+      h *= d * c;
218+      aa = -(a + m) * (qab + m) * x / ((a + m2) * (qap + m2));
219+      d = 1 + aa * d;
220+      if (Math.abs(d) < fpmin)
221+        d = fpmin;
222+      c = 1 + aa / c;
223+      if (Math.abs(c) < fpmin)
224+        c = fpmin;
225+      d = 1 / d;
226+      del = d * c;
227+      h *= del;
228+      if (Math.abs(del - 1.0) < 3e-7)
229+        break;
230+    }
231+
232+    return h;
233+  }
234+  function _ibeta(x, a, b) {
235+    var bt = (x === 0 || x === 1) ?  0 :
236+      Math.exp(gammaln(a + b) - gammaln(a) -
237+        gammaln(b) + a * Math.log(x) + b *
238+        Math.log(1 - x));
239+    if (x < 0 || x > 1)
240+      return 0;
241+    if (x < (a + 1) / (a + b + 2))
242+      return bt * _betacf(x, a, b) / a;
243+    return 1 - bt * _betacf(1 - x, b, a) / b;
244+  }
245+  function _studenttCDF(x, dof) {
246+    var dof2 = dof / 2;
247+    return _ibeta((x + Math.sqrt(x * x + dof)) /
248+      (2 * Math.sqrt(x * x + dof)), dof2, dof2);
249+  }
250+  return tails * (1 - _studenttCDF(x, degreesOfFreedom));
251+};
252+
253+
254 export {
255   AVERAGE,
256   AVERAGEA,
257@@ -2024,5 +2110,6 @@ export {
258   RANK,
259   RANK$AVG,
260   RANK$EQ,
261-  LOGNORMDIST
262+  LOGNORMDIST,
263+  TDIST
264 }
265\ No newline at end of file
266diff --git a/tests/Formulas/StatisticalTest.ts b/tests/Formulas/StatisticalTest.ts
267index 8bd796b..26b6b9b 100644
268--- a/tests/Formulas/StatisticalTest.ts
269+++ b/tests/Formulas/StatisticalTest.ts
270@@ -59,7 +59,8 @@ import {
271   RANK,
272   RANK$AVG,
273   RANK$EQ,
274-  LOGNORMDIST
275+  LOGNORMDIST,
276+  TDIST
277 } from "../../src/Formulas/Statistical";
278 import * as ERRORS from "../../src/Errors";
279 import {
280@@ -1211,4 +1212,31 @@ test("LOGNORMDIST", function() {
281   catchAndAssertEquals(function() {
282     LOGNORMDIST.apply(this, [4, 4, 4, 4]);
283   }, ERRORS.NA_ERROR);
284+});
285+
286+test("TDIST", function() {
287+  assertEquals(TDIST(0.55, 1, 2), 0.6798800684756632);
288+  assertEquals(TDIST(0.55, 1, 1), 0.3399400342378316);
289+  assertEquals(TDIST(0.55, 100, 1), 0.29177287888140824);
290+  catchAndAssertEquals(function() {
291+    TDIST(0.55, -1, 1);
292+  }, ERRORS.NUM_ERROR);
293+  catchAndAssertEquals(function() {
294+    TDIST(0.55, 1, 44);
295+  }, ERRORS.NUM_ERROR);
296+  catchAndAssertEquals(function() {
297+    TDIST(0.55, 1, 0);
298+  }, ERRORS.NUM_ERROR);
299+  catchAndAssertEquals(function() {
300+    TDIST(-1, 1, 1);
301+  }, ERRORS.NUM_ERROR);
302+  catchAndAssertEquals(function() {
303+    TDIST.apply(this, [4, 4, 4, 4]);
304+  }, ERRORS.NA_ERROR);
305+  catchAndAssertEquals(function() {
306+    TDIST.apply(this, [4, 4]);
307+  }, ERRORS.NA_ERROR);
308+  catchAndAssertEquals(function() {
309+    TDIST.apply(this, []);
310+  }, ERRORS.NA_ERROR);
311 });
312\ No newline at end of file
313diff --git a/tests/SheetFormulaTest.ts b/tests/SheetFormulaTest.ts
314index 7f626c0..f85b935 100644
315--- a/tests/SheetFormulaTest.ts
316+++ b/tests/SheetFormulaTest.ts
317@@ -946,6 +946,10 @@ test("Sheet LOGNORMDIST", function(){
318   assertFormulaEquals('=LOGNORMDIST(4, 4, 6)', 0.33155709720516946);
319 });
320 
321+test("Sheet LOGNORMDIST", function(){
322+  assertFormulaEquals('=TDIST(0.55, 1, 2)', 0.6798800684756632);
323+});
324+
325 test("Sheet *", function(){
326   assertFormulaEquals('= 10 * 10', 100);
327   assertFormulaEquals('= 10 * 0', 0);