commit
message
[MathHelpers] for heavy math functions used in Statistical
author
Ben Vogt <[email protected]>
date
2017-05-19 00:30:35
stats
4 file(s) changed,
377 insertions(+),
474 deletions(-)
files
README.md
src/Formulas/Math.ts
src/Formulas/Statistical.ts
src/Utilities/MathHelpers.ts
1diff --git a/README.md b/README.md
2index d64ec50..f8f1080 100644
3--- a/README.md
4+++ b/README.md
5@@ -35,12 +35,5 @@ Contingent upon cells having formats or types for primitives.
6 ### Scrape jsdocs for functions, put in simple index.html, doc.md files to serve up simple documentation
7
8
9-### Pull static functions outside of formulas, declare once.
10-
11-
12 ### CONVERT could offer more accurate conversions for units in the same system
13 For example 64 tbs to a qt.
14-
15-
16-### Sheet.ts and parser.js should be able to concatenate criteria and values
17-E.g. `=COUNTIFS(A7:A24, ">6", B7:B24, "<"&DATE(1969,7,20))`
18\ No newline at end of file
19diff --git a/src/Formulas/Math.ts b/src/Formulas/Math.ts
20index 3528743..190f868 100644
21--- a/src/Formulas/Math.ts
22+++ b/src/Formulas/Math.ts
23@@ -920,6 +920,26 @@ var SUMX2MY2 = function (arrayX, arrayY) : number {
24 };
25
26
27+// Private function that will recursively generate an array of the unique primitives
28+var _countUnique = function (values: Array<any>) : Object {
29+ var uniques = {};
30+ for (var i = 0; i < values.length; i++) {
31+ if (Array.isArray(values[i])) {
32+ // For some reasons an empty range is converted to a range with a single empty string in it.
33+ if (values[i].length === 0) {
34+ values[i] = [""];
35+ }
36+ var uniquesOfArray = _countUnique(values[i]);
37+ for (var key in uniquesOfArray) {
38+ uniques[key] = true;
39+ }
40+ } else {
41+ uniques[Serializer.serialize(values[i])] = true;
42+ }
43+ }
44+ return uniques;
45+};
46+
47 /**
48 * Counts the number of unique values in a list of specified values and ranges.
49 * @param values The values or ranges to consider for uniqueness. Supports an arbitrary number of arguments for this
50@@ -930,27 +950,7 @@ var SUMX2MY2 = function (arrayX, arrayY) : number {
51 var COUNTUNIQUE = function (...values) : number {
52 ArgsChecker.checkAtLeastLength(values, 1, "COUNTUNIQUE");
53
54- // Private function that will recursively generate an array of the unique primitives
55- var countUniquePrivate = function (values: Array<any>) : Object {
56- var uniques = {};
57- for (var i = 0; i < values.length; i++) {
58- if (Array.isArray(values[i])) {
59- // For some reasons an empty range is converted to a range with a single empty string in it.
60- if (values[i].length === 0) {
61- values[i] = [""];
62- }
63- var uniquesOfArray = countUniquePrivate(values[i]);
64- for (var key in uniquesOfArray) {
65- uniques[key] = true;
66- }
67- } else {
68- uniques[Serializer.serialize(values[i])] = true;
69- }
70- }
71- return uniques;
72- };
73-
74- var uniques = countUniquePrivate(values);
75+ var uniques = _countUnique(values);
76 return Object.keys(uniques).length;
77 };
78
79@@ -1069,11 +1069,11 @@ export {
80 ROUND,
81 ROUNDDOWN,
82 ROUNDUP,
83- SUMPRODUCT, // Array?
84+ SUMPRODUCT,
85 SUMIF,
86 SUMSQ,
87- SUMX2MY2, // Array?
88- SUMX2PY2, // Array?
89+ SUMX2MY2,
90+ SUMX2PY2,
91 FLOOR,
92 IF,
93 COUNTIF,
94diff --git a/src/Formulas/Statistical.ts b/src/Formulas/Statistical.ts
95index 7e0a894..a46657f 100644
96--- a/src/Formulas/Statistical.ts
97+++ b/src/Formulas/Statistical.ts
98@@ -17,6 +17,13 @@ import {
99 SUM,
100 ABS
101 } from "./Math";
102+import {
103+ cdf,
104+ covariance,
105+ inv,
106+ pdf,
107+ stdev,
108+} from "../Utilities/MathHelpers";
109
110
111 /**
112@@ -189,6 +196,7 @@ var AVERAGEA = function (...values) {
113 return result / count;
114 };
115
116+
117 /**
118 * Calculates r, the Pearson product-moment correlation coefficient of a dataset. Any text encountered in the arguments
119 * will be ignored. CORREL is synonymous with PEARSON.
120@@ -198,80 +206,6 @@ var AVERAGEA = function (...values) {
121 * @constructor
122 */
123 var CORREL = function (dataY, dataX) : number {
124- /**
125- * Return the standard deviation of a vector. By defaut, the population standard deviation is returned. Passing true
126- * for the flag parameter returns the sample standard deviation. See http://jstat.github.io/vector.html#stdev for
127- * more information.
128- */
129- function stdev(arr, flag) {
130- return Math.sqrt(variance(arr, flag));
131- }
132-
133- /**
134- * Return the variance of a vector. By default, the population variance is calculated. Passing true as the flag
135- * indicates computes the sample variance instead. See http://jstat.github.io/vector.html#variance for more
136- * information.
137- */
138- function variance(arr, flag) {
139- if ((arr.length - (flag ? 1 : 0)) === 0) {
140- throw new DivZeroError("Evaluation of function CORREL caused a divide by zero error.");
141- }
142- return sumsqerr(arr) / (arr.length - (flag ? 1 : 0));
143- }
144-
145- /**
146- * Return the sum of a vector. See http://jstat.github.io/vector.html#sum for more information.
147- */
148- function sum(arr) {
149- var sum = 0;
150- var i = arr.length;
151- while (--i >= 0) {
152- sum += arr[i];
153- }
154- return sum;
155- }
156- /**
157- * Return the mean of a vector. See http://jstat.github.io/vector.html#mean for more information.
158- */
159- function mean(arr) {
160- if (arr.length === 0) {
161- throw new DivZeroError("Evaluation of function CORREL caused a divide by zero error.");
162- }
163- return sum(arr) / arr.length;
164- }
165-
166- /**
167- * Return the sum of squared errors of prediction of a vector. See http://jstat.github.io/vector.html#sumsqerr for
168- * more information.
169- */
170- function sumsqerr(arr) {
171- var m = mean(arr);
172- var sum = 0;
173- var i = arr.length;
174- var tmp;
175- while (--i >= 0) {
176- tmp = arr[i] - m;
177- sum += tmp * tmp;
178- }
179- return sum;
180- }
181-
182- /**
183- * Return the covariance of two vectors. See http://jstat.github.io/vector.html#covariance for more information.
184- */
185- function covariance(arr1, arr2) {
186- var u = mean(arr1);
187- var v = mean(arr2);
188- var arr1Len = arr1.length;
189- var sq_dev = new Array(arr1Len);
190- for (var i = 0; i < arr1Len; i++) {
191- sq_dev[i] = (arr1[i] - u) * (arr2[i] - v);
192- }
193- if ((arr1Len - 1) === 0) {
194- throw new DivZeroError("Evaluation of function CORREL caused a divide by zero error.");
195- }
196- return sum(sq_dev) / (arr1Len - 1);
197- }
198 ArgsChecker.checkLength(arguments, 2, "CORREL");
199 if (!Array.isArray(dataY)) {
200 dataY = [dataY];
201@@ -328,6 +262,8 @@ var EXPONDIST = function (x, lambda, cumulative) : number {
202 return (cumulative) ? cdf(x, lambda) : pdf(x, lambda);
203 };
204
205+
206+
207 /**
208 * Calculates the left-tailed F probability distribution (degree of diversity) for two data sets with given input x.
209 * Alternately called Fisher-Snedecor distribution or Snecdor's F distribution.
210@@ -343,178 +279,7 @@ var EXPONDIST = function (x, lambda, cumulative) : number {
211 */
212 var FDIST$LEFTTAILED = function (x, degreesFreedom1, degreesFreedom2, cumulative) : number|undefined|boolean {
213 ArgsChecker.checkLength(arguments, 4, "FDIST$LEFTTAILED");
214- /**
215- * Returns the Log-Gamma function evaluated at x. See http://jstat.github.io/special-functions.html#gammaln for more
216- * information.
217- */
218- function gammaln(x) {
219- var j = 0;
220- var cof = [
221- 76.18009172947146, -86.50532032941677, 24.01409824083091,
222- -1.231739572450155, 0.1208650973866179e-2, -0.5395239384953e-5
223- ];
224- var ser = 1.000000000190015;
225- var xx, y, tmp;
226- tmp = (y = xx = x) + 5.5;
227- tmp -= (xx + 0.5) * Math.log(tmp);
228- for (; j < 6; j++)
229- ser += cof[j] / ++y;
230- return Math.log(2.5066282746310005 * ser / xx) - tmp;
231- }
232-
233- /**
234- * Returns the Gamma function evaluated at x. This is sometimes called the 'complete' gamma function. See
235- * http://jstat.github.io/special-functions.html#gammafn for more information.
236- */
237- function gammafn(x) {
238- var p = [-1.716185138865495, 24.76565080557592, -379.80425647094563,
239- 629.3311553128184, 866.9662027904133, -31451.272968848367,
240- -36144.413418691176, 66456.14382024054
241- ];
242- var q = [-30.8402300119739, 315.35062697960416, -1015.1563674902192,
243- -3107.771671572311, 22538.118420980151, 4755.8462775278811,
244- -134659.9598649693, -115132.2596755535];
245- var fact;
246- var n = 0;
247- var xden = 0;
248- var xnum = 0;
249- var y = x;
250- var i, z, yi, res;
251- if (y <= 0) {
252- res = y % 1 + 3.6e-16;
253- if (res) {
254- fact = (!(y & 1) ? 1 : -1) * Math.PI / Math.sin(Math.PI * res);
255- y = 1 - y;
256- } else {
257- return Infinity;
258- }
259- }
260- yi = y;
261- if (y < 1) {
262- z = y++;
263- } else {
264- z = (y -= n = (y | 0) - 1) - 1;
265- }
266- for (i = 0; i < 8; ++i) {
267- xnum = (xnum + p[i]) * z;
268- xden = xden * z + q[i];
269- }
270- res = xnum / xden + 1;
271- if (yi < y) {
272- res /= yi;
273- } else if (yi > y) {
274- for (i = 0; i < n; ++i) {
275- res *= y;
276- y++;
277- }
278- }
279- if (fact) {
280- res = fact / res;
281- }
282- return res;
283- }
284-
285- /**
286- * Returns the continued fraction for the incomplete Beta function with parameters a and b modified by Lentz's method
287- * evaluated at x. For more information see http://jstat.github.io/special-functions.html#betacf.
288- */
289- function betacf(x, a, b) {
290- var fpmin = 1e-30;
291- var m = 1;
292- var qab = a + b;
293- var qap = a + 1;
294- var qam = a - 1;
295- var c = 1;
296- var d = 1 - qab * x / qap;
297- var m2, aa, del, h;
298-
299- // These q's will be used in factors that occur in the coefficients
300- if (Math.abs(d) < fpmin)
301- d = fpmin;
302- d = 1 / d;
303- h = d;
304-
305- for (; m <= 100; m++) {
306- m2 = 2 * m;
307- aa = m * (b - m) * x / ((qam + m2) * (a + m2));
308- // One step (the even one) of the recurrence
309- d = 1 + aa * d;
310- if (Math.abs(d) < fpmin)
311- d = fpmin;
312- c = 1 + aa / c;
313- if (Math.abs(c) < fpmin)
314- c = fpmin;
315- d = 1 / d;
316- h *= d * c;
317- aa = -(a + m) * (qab + m) * x / ((a + m2) * (qap + m2));
318- // Next step of the recurrence (the odd one)
319- d = 1 + aa * d;
320- if (Math.abs(d) < fpmin)
321- d = fpmin;
322- c = 1 + aa / c;
323- if (Math.abs(c) < fpmin)
324- c = fpmin;
325- d = 1 / d;
326- del = d * c;
327- h *= del;
328- if (Math.abs(del - 1.0) < 3e-7)
329- break;
330- }
331-
332- return h;
333- }
334
335- /**
336- * Returns the incomplete Beta function evaluated at (x,a,b). See http://jstat.github.io/special-functions.html#ibeta
337- * for more information.
338- */
339- function ibeta(x, a, b) {
340- // Factors in front of the continued fraction.
341- var bt = (x === 0 || x === 1) ? 0 :
342- Math.exp(gammaln(a + b) - gammaln(a) -
343- gammaln(b) + a * Math.log(x) + b *
344- Math.log(1 - x));
345- if (x < 0 || x > 1)
346- return false;
347- if (x < (a + 1) / (a + b + 2))
348- // Use continued fraction directly.
349- return bt * betacf(x, a, b) / a;
350- // else use continued fraction after making the symmetry transformation.
351- return 1 - bt * betacf(1 - x, b, a) / b;
352- }
353-
354- /**
355- * Returns the value of x in the cdf of the Gamma distribution with the parameters shape (k) and scale (theta). Notice
356- * that if using the alpha beta convention, scale = 1/beta. For more information see
357- * http://jstat.github.io/distributions.html#jStat.gamma.cdf
358- */
359- function cdf(x, df1, df2) {
360- return ibeta((df1 * x) / (df1 * x + df2), df1 / 2, df2 / 2);
361- }
362-
363- /**
364- * Returns the value of x in the pdf of the Gamma distribution with the parameters shape (k) and scale (theta). Notice
365- * that if using the alpha beta convention, scale = 1/beta. For more information see
366- * http://jstat.github.io/distributions.html#jStat.gamma.pdf
367- */
368- function pdf(x, df1, df2) {
369- if (x < 0) {
370- return undefined;
371- }
372- return Math.sqrt((Math.pow(df1 * x, df1) * Math.pow(df2, df2)) /
373- (Math.pow(df1 * x + df2, df1 + df2))) /
374- (x * betafn(df1/2, df2/2));
375- }
376- function betaln(x, y) {
377- return gammaln(x) + gammaln(y) - gammaln(x + y);
378- }
379- function betafn(x, y) {
380- // ensure arguments are positive
381- if (x <= 0 || y <= 0)
382- return undefined;
383- // make sure x + y doesn't exceed the upper limit of usable values
384- return (x + y > 170) ? Math.exp(betaln(x, y)) : gammafn(x) * gammafn(y) / gammafn(x + y);
385- }
386 x = TypeConverter.firstValueAsNumber(x);
387 if (x < 0) {
388 throw new NumError("Function F.DIST parameter 1 value is " + x + ". It should be greater than or equal to 0.");
389@@ -525,6 +290,7 @@ var FDIST$LEFTTAILED = function (x, degreesFreedom1, degreesFreedom2, cumulative
390 return (cum) ? cdf(x, d1, d2) : pdf(x, d1, d2);
391 };
392
393+
394 /**
395 * Returns the inverse of the (right-tailed) F probability distribution. If p = FDIST(x,...), then FINV(p,...) = x. The
396 * F distribution can be used in an F-test that compares the degree of variability in two data sets.
397@@ -536,156 +302,7 @@ var FDIST$LEFTTAILED = function (x, degreesFreedom1, degreesFreedom2, cumulative
398 */
399 var FINV = function (probability, degFreedom1, degFreedom2) : number {
400 ArgsChecker.checkLength(arguments, 3, "FINV");
401- /**
402- * Returns the continued fraction for the incomplete Beta function with parameters a and b modified by Lentz's method
403- * evaluated at x. For more information see http://jstat.github.io/special-functions.html#betacf
404- */
405- function betacf(x, a, b) {
406- var fpmin = 1e-30;
407- var m = 1;
408- var qab = a + b;
409- var qap = a + 1;
410- var qam = a - 1;
411- var c = 1;
412- var d = 1 - qab * x / qap;
413- var m2, aa, del, h;
414-
415- // These q's will be used in factors that occur in the coefficients
416- if (Math.abs(d) < fpmin)
417- d = fpmin;
418- d = 1 / d;
419- h = d;
420-
421- for (; m <= 100; m++) {
422- m2 = 2 * m;
423- aa = m * (b - m) * x / ((qam + m2) * (a + m2));
424- // One step (the even one) of the recurrence
425- d = 1 + aa * d;
426- if (Math.abs(d) < fpmin)
427- d = fpmin;
428- c = 1 + aa / c;
429- if (Math.abs(c) < fpmin)
430- c = fpmin;
431- d = 1 / d;
432- h *= d * c;
433- aa = -(a + m) * (qab + m) * x / ((a + m2) * (qap + m2));
434- // Next step of the recurrence (the odd one)
435- d = 1 + aa * d;
436- if (Math.abs(d) < fpmin)
437- d = fpmin;
438- c = 1 + aa / c;
439- if (Math.abs(c) < fpmin)
440- c = fpmin;
441- d = 1 / d;
442- del = d * c;
443- h *= del;
444- if (Math.abs(del - 1.0) < 3e-7)
445- break;
446- }
447-
448- return h;
449- }
450-
451- /**
452- * Returns the incomplete Beta function evaluated at (x,a,b). See http://jstat.github.io/special-functions.html#ibeta
453- * for more information.
454- */
455- function ibeta(x, a, b) : number {
456- // Factors in front of the continued fraction.
457- var bt = (x === 0 || x === 1) ? 0 :
458- Math.exp(gammaln(a + b) - gammaln(a) -
459- gammaln(b) + a * Math.log(x) + b *
460- Math.log(1 - x));
461- if (x < 0 || x > 1)
462- // WARNING: I changed this to 0, because TS complains about doing numerical operations on boolean values.
463- // Still safe in javascript, but not TS.
464- return 0;
465- if (x < (a + 1) / (a + b + 2))
466- // Use continued fraction directly.
467- return bt * betacf(x, a, b) / a;
468- // else use continued fraction after making the symmetry transformation.
469- return 1 - bt * betacf(1 - x, b, a) / b;
470- }
471-
472- /**
473- * Returns the Log-Gamma function evaluated at x. For more information see
474- * http://jstat.github.io/special-functions.html#gammaln
475- */
476- function gammaln(x) {
477- var j = 0;
478- var cof = [
479- 76.18009172947146, -86.50532032941677, 24.01409824083091,
480- -1.231739572450155, 0.1208650973866179e-2, -0.5395239384953e-5
481- ];
482- var ser = 1.000000000190015;
483- var xx, y, tmp;
484- tmp = (y = xx = x) + 5.5;
485- tmp -= (xx + 0.5) * Math.log(tmp);
486- for (; j < 6; j++)
487- ser += cof[j] / ++y;
488- return Math.log(2.5066282746310005 * ser / xx) - tmp;
489- }
490
491- /**
492- * Returns the inverse of the incomplete Beta function evaluated at (p,a,b). For more information see
493- * http://jstat.github.io/special-functions.html#ibetainv
494- */
495- function ibetainv(p, a, b) {
496- var EPS = 1e-8;
497- var a1 = a - 1;
498- var b1 = b - 1;
499- var j = 0;
500- var lna, lnb, pp, t, u, err, x, al, h, w, afac;
501- if (p <= 0)
502- return 0;
503- if (p >= 1)
504- return 1;
505- if (a >= 1 && b >= 1) {
506- pp = (p < 0.5) ? p : 1 - p;
507- t = Math.sqrt(-2 * Math.log(pp));
508- x = (2.30753 + t * 0.27061) / (1 + t* (0.99229 + t * 0.04481)) - t;
509- if (p < 0.5)
510- x = -x;
511- al = (x * x - 3) / 6;
512- h = 2 / (1 / (2 * a - 1) + 1 / (2 * b - 1));
513- w = (x * Math.sqrt(al + h) / h) - (1 / (2 * b - 1) - 1 / (2 * a - 1)) *
514- (al + 5 / 6 - 2 / (3 * h));
515- x = a / (a + b * Math.exp(2 * w));
516- } else {
517- lna = Math.log(a / (a + b));
518- lnb = Math.log(b / (a + b));
519- t = Math.exp(a * lna) / a;
520- u = Math.exp(b * lnb) / b;
521- w = t + u;
522- if (p < t / w)
523- x = Math.pow(a * w * p, 1 / a);
524- else
525- x = 1 - Math.pow(b * w * (1 - p), 1 / b);
526- }
527- afac = -gammaln(a) - gammaln(b) + gammaln(a + b);
528- for(; j < 10; j++) {
529- if (x === 0 || x === 1)
530- return x;
531- err = ibeta(x, a, b) - p;
532- t = Math.exp(a1 * Math.log(x) + b1 * Math.log(1 - x) + afac);
533- u = err / t;
534- x -= (t = u / (1 - 0.5 * Math.min(1, u * (a1 / x - b1 / (1 - x)))));
535- if (x <= 0)
536- x = 0.5 * (x + t);
537- if (x >= 1)
538- x = 0.5 * (x + t + 1);
539- if (Math.abs(t) < EPS * x && j > 0)
540- break;
541- }
542- return x;
543- }
544-
545- /**
546- * http://jstat.github.io/distributions.html
547- */
548- function inv(x, df1, df2) {
549- return df2 / (df1 * (1 / ibetainv(x, df1 / 2, df2 / 2) - 1));
550- }
551 probability = TypeConverter.firstValueAsNumber(probability);
552 if (probability <= 0.0 || probability > 1.0) {
553 throw new NumError("Function FINV parameter 1 value is " + probability
554diff --git a/src/Utilities/MathHelpers.ts b/src/Utilities/MathHelpers.ts
555new file mode 100644
556index 0000000..53c440a
557--- /dev/null
558+++ b/src/Utilities/MathHelpers.ts
559@@ -0,0 +1,336 @@
560+import {
561+ DivZeroError
562+} from "../Errors";
563+/**
564+ * Returns the continued fraction for the incomplete Beta function with parameters a and b modified by Lentz's method
565+ * evaluated at x. For more information see http://jstat.github.io/special-functions.html#betacf
566+ */
567+function betacf(x, a, b) {
568+ var fpmin = 1e-30;
569+ var m = 1;
570+ var qab = a + b;
571+ var qap = a + 1;
572+ var qam = a - 1;
573+ var c = 1;
574+ var d = 1 - qab * x / qap;
575+ var m2, aa, del, h;
576+
577+ // These q's will be used in factors that occur in the coefficients
578+ if (Math.abs(d) < fpmin)
579+ d = fpmin;
580+ d = 1 / d;
581+ h = d;
582+
583+ for (; m <= 100; m++) {
584+ m2 = 2 * m;
585+ aa = m * (b - m) * x / ((qam + m2) * (a + m2));
586+ // One step (the even one) of the recurrence
587+ d = 1 + aa * d;
588+ if (Math.abs(d) < fpmin)
589+ d = fpmin;
590+ c = 1 + aa / c;
591+ if (Math.abs(c) < fpmin)
592+ c = fpmin;
593+ d = 1 / d;
594+ h *= d * c;
595+ aa = -(a + m) * (qab + m) * x / ((a + m2) * (qap + m2));
596+ // Next step of the recurrence (the odd one)
597+ d = 1 + aa * d;
598+ if (Math.abs(d) < fpmin)
599+ d = fpmin;
600+ c = 1 + aa / c;
601+ if (Math.abs(c) < fpmin)
602+ c = fpmin;
603+ d = 1 / d;
604+ del = d * c;
605+ h *= del;
606+ if (Math.abs(del - 1.0) < 3e-7)
607+ break;
608+ }
609+
610+ return h;
611+}
612+
613+/**
614+ * Returns the incomplete Beta function evaluated at (x,a,b). See http://jstat.github.io/special-functions.html#ibeta
615+ * for more information.
616+ */
617+function ibeta(x, a, b) : number {
618+ // Factors in front of the continued fraction.
619+ var bt = (x === 0 || x === 1) ? 0 :
620+ Math.exp(gammaln(a + b) - gammaln(a) -
621+ gammaln(b) + a * Math.log(x) + b *
622+ Math.log(1 - x));
623+ if (x < 0 || x > 1)
624+ // WARNING: I changed this to 0, because TS complains about doing numerical operations on boolean values.
625+ // Still safe in javascript, but not TS.
626+ return 0;
627+ if (x < (a + 1) / (a + b + 2))
628+ // Use continued fraction directly.
629+ return bt * betacf(x, a, b) / a;
630+ // else use continued fraction after making the symmetry transformation.
631+ return 1 - bt * betacf(1 - x, b, a) / b;
632+}
633+
634+/**
635+ * Returns the inverse of the incomplete Beta function evaluated at (p,a,b). For more information see
636+ * http://jstat.github.io/special-functions.html#ibetainv
637+ */
638+function ibetainv(p, a, b) {
639+ var EPS = 1e-8;
640+ var a1 = a - 1;
641+ var b1 = b - 1;
642+ var j = 0;
643+ var lna, lnb, pp, t, u, err, x, al, h, w, afac;
644+ if (p <= 0)
645+ return 0;
646+ if (p >= 1)
647+ return 1;
648+ if (a >= 1 && b >= 1) {
649+ pp = (p < 0.5) ? p : 1 - p;
650+ t = Math.sqrt(-2 * Math.log(pp));
651+ x = (2.30753 + t * 0.27061) / (1 + t* (0.99229 + t * 0.04481)) - t;
652+ if (p < 0.5)
653+ x = -x;
654+ al = (x * x - 3) / 6;
655+ h = 2 / (1 / (2 * a - 1) + 1 / (2 * b - 1));
656+ w = (x * Math.sqrt(al + h) / h) - (1 / (2 * b - 1) - 1 / (2 * a - 1)) *
657+ (al + 5 / 6 - 2 / (3 * h));
658+ x = a / (a + b * Math.exp(2 * w));
659+ } else {
660+ lna = Math.log(a / (a + b));
661+ lnb = Math.log(b / (a + b));
662+ t = Math.exp(a * lna) / a;
663+ u = Math.exp(b * lnb) / b;
664+ w = t + u;
665+ if (p < t / w)
666+ x = Math.pow(a * w * p, 1 / a);
667+ else
668+ x = 1 - Math.pow(b * w * (1 - p), 1 / b);
669+ }
670+ afac = -gammaln(a) - gammaln(b) + gammaln(a + b);
671+ for(; j < 10; j++) {
672+ if (x === 0 || x === 1)
673+ return x;
674+ err = ibeta(x, a, b) - p;
675+ t = Math.exp(a1 * Math.log(x) + b1 * Math.log(1 - x) + afac);
676+ u = err / t;
677+ x -= (t = u / (1 - 0.5 * Math.min(1, u * (a1 / x - b1 / (1 - x)))));
678+ if (x <= 0)
679+ x = 0.5 * (x + t);
680+ if (x >= 1)
681+ x = 0.5 * (x + t + 1);
682+ if (Math.abs(t) < EPS * x && j > 0)
683+ break;
684+ }
685+ return x;
686+}
687+
688+/**
689+ * http://jstat.github.io/distributions.html
690+ */
691+function inv(x, df1, df2) {
692+ return df2 / (df1 * (1 / ibetainv(x, df1 / 2, df2 / 2) - 1));
693+}
694+
695+
696+/**
697+ * Return the standard deviation of a vector. By defaut, the population standard deviation is returned. Passing true
698+ * for the flag parameter returns the sample standard deviation. See http://jstat.github.io/vector.html#stdev for
699+ * more information.
700+ */
701+function stdev(arr, flag) {
702+ return Math.sqrt(variance(arr, flag));
703+}
704+
705+/**
706+ * Return the variance of a vector. By default, the population variance is calculated. Passing true as the flag
707+ * indicates computes the sample variance instead. See http://jstat.github.io/vector.html#variance for more
708+ * information.
709+ */
710+function variance(arr, flag) {
711+ if ((arr.length - (flag ? 1 : 0)) === 0) {
712+ throw new DivZeroError("Evaluation of function CORREL caused a divide by zero error.");
713+ }
714+ return sumsqerr(arr) / (arr.length - (flag ? 1 : 0));
715+}
716+
717+/**
718+ * Return the sum of a vector. See http://jstat.github.io/vector.html#sum for more information.
719+ */
720+function sum(arr) {
721+ var sum = 0;
722+ var i = arr.length;
723+ while (--i >= 0) {
724+ sum += arr[i];
725+ }
726+ return sum;
727+}
728+/**
729+ * Return the mean of a vector. See http://jstat.github.io/vector.html#mean for more information.
730+ */
731+function mean(arr) {
732+ if (arr.length === 0) {
733+ throw new DivZeroError("Evaluation of function CORREL caused a divide by zero error.");
734+ }
735+ return sum(arr) / arr.length;
736+}
737+
738+/**
739+ * Return the sum of squared errors of prediction of a vector. See http://jstat.github.io/vector.html#sumsqerr for
740+ * more information.
741+ */
742+function sumsqerr(arr) {
743+ var m = mean(arr);
744+ var sum = 0;
745+ var i = arr.length;
746+ var tmp;
747+ while (--i >= 0) {
748+ tmp = arr[i] - m;
749+ sum += tmp * tmp;
750+ }
751+ return sum;
752+}
753+
754+/**
755+ * Return the covariance of two vectors. See http://jstat.github.io/vector.html#covariance for more information.
756+ */
757+function covariance(arr1, arr2) {
758+ var u = mean(arr1);
759+ var v = mean(arr2);
760+ var arr1Len = arr1.length;
761+ var sq_dev = new Array(arr1Len);
762+ for (var i = 0; i < arr1Len; i++) {
763+ sq_dev[i] = (arr1[i] - u) * (arr2[i] - v);
764+ }
765+ if ((arr1Len - 1) === 0) {
766+ throw new DivZeroError("Evaluation of function CORREL caused a divide by zero error.");
767+ }
768+ return sum(sq_dev) / (arr1Len - 1);
769+}
770+
771+/**
772+ * Returns the Log-Gamma function evaluated at x. See http://jstat.github.io/special-functions.html#gammaln for more
773+ * information.
774+ */
775+function gammaln(x) {
776+ var j = 0;
777+ var cof = [
778+ 76.18009172947146, -86.50532032941677, 24.01409824083091,
779+ -1.231739572450155, 0.1208650973866179e-2, -0.5395239384953e-5
780+ ];
781+ var ser = 1.000000000190015;
782+ var xx, y, tmp;
783+ tmp = (y = xx = x) + 5.5;
784+ tmp -= (xx + 0.5) * Math.log(tmp);
785+ for (; j < 6; j++)
786+ ser += cof[j] / ++y;
787+ return Math.log(2.5066282746310005 * ser / xx) - tmp;
788+}
789+
790+/**
791+ * Returns the Gamma function evaluated at x. This is sometimes called the 'complete' gamma function. See
792+ * http://jstat.github.io/special-functions.html#gammafn for more information.
793+ */
794+function gammafn(x) {
795+ var p = [-1.716185138865495, 24.76565080557592, -379.80425647094563,
796+ 629.3311553128184, 866.9662027904133, -31451.272968848367,
797+ -36144.413418691176, 66456.14382024054
798+ ];
799+ var q = [-30.8402300119739, 315.35062697960416, -1015.1563674902192,
800+ -3107.771671572311, 22538.118420980151, 4755.8462775278811,
801+ -134659.9598649693, -115132.2596755535];
802+ var fact;
803+ var n = 0;
804+ var xden = 0;
805+ var xnum = 0;
806+ var y = x;
807+ var i, z, yi, res;
808+ if (y <= 0) {
809+ res = y % 1 + 3.6e-16;
810+ if (res) {
811+ fact = (!(y & 1) ? 1 : -1) * Math.PI / Math.sin(Math.PI * res);
812+ y = 1 - y;
813+ } else {
814+ return Infinity;
815+ }
816+ }
817+ yi = y;
818+ if (y < 1) {
819+ z = y++;
820+ } else {
821+ z = (y -= n = (y | 0) - 1) - 1;
822+ }
823+ for (i = 0; i < 8; ++i) {
824+ xnum = (xnum + p[i]) * z;
825+ xden = xden * z + q[i];
826+ }
827+ res = xnum / xden + 1;
828+ if (yi < y) {
829+ res /= yi;
830+ } else if (yi > y) {
831+ for (i = 0; i < n; ++i) {
832+ res *= y;
833+ y++;
834+ }
835+ }
836+ if (fact) {
837+ res = fact / res;
838+ }
839+ return res;
840+}
841+
842+
843+/**
844+ * Returns the value of x in the cdf of the Gamma distribution with the parameters shape (k) and scale (theta). Notice
845+ * that if using the alpha beta convention, scale = 1/beta. For more information see
846+ * http://jstat.github.io/distributions.html#jStat.gamma.cdf
847+ */
848+function cdf(x, df1, df2) {
849+ return ibeta((df1 * x) / (df1 * x + df2), df1 / 2, df2 / 2);
850+}
851+
852+/**
853+ * Returns the value of x in the pdf of the Gamma distribution with the parameters shape (k) and scale (theta). Notice
854+ * that if using the alpha beta convention, scale = 1/beta. For more information see
855+ * http://jstat.github.io/distributions.html#jStat.gamma.pdf
856+ */
857+function pdf(x, df1, df2) {
858+ if (x < 0) {
859+ return undefined;
860+ }
861+ return Math.sqrt((Math.pow(df1 * x, df1) * Math.pow(df2, df2)) /
862+ (Math.pow(df1 * x + df2, df1 + df2))) /
863+ (x * betafn(df1/2, df2/2));
864+}
865+
866+function betaln(x, y) {
867+ return gammaln(x) + gammaln(y) - gammaln(x + y);
868+}
869+
870+function betafn(x, y) {
871+ // ensure arguments are positive
872+ if (x <= 0 || y <= 0)
873+ return undefined;
874+ // make sure x + y doesn't exceed the upper limit of usable values
875+ return (x + y > 170) ? Math.exp(betaln(x, y)) : gammafn(x) * gammafn(y) / gammafn(x + y);
876+}
877+
878+export {
879+ betacf,
880+ betafn,
881+ betaln,
882+ cdf,
883+ covariance,
884+ gammafn,
885+ gammaln,
886+ ibeta,
887+ ibetainv,
888+ inv,
889+ mean,
890+ pdf,
891+ stdev,
892+ sum,
893+ sumsqerr,
894+ variance
895+}
896\ No newline at end of file