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);