commit
message
[NORMINV] formula added and tested
author
Ben Vogt <[email protected]>
date
2017-07-03 21:14:16
stats
8 file(s) changed,
201 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 52576c9..7c2e38e 100644
3--- a/DOCS.md
4+++ b/DOCS.md
5@@ -1770,6 +1770,17 @@
6 @returns {number}
7 @constructor
8 ```
9+
10+### NORMINV
11+
12+```
13+ Returns the inverse of the normal distribution for the given number in the distribution.
14+@param probability - Number in the distribution.
15+@param meanVal - The mean value in the normal distribution.
16+@param standDev - The standard deviation of the normal distribution.
17+@returns {number}
18+@constructor
19+```
20 ## Text
21
22
23diff --git a/TODO.md b/TODO.md
24index 8d17884..5db3218 100644
25--- a/TODO.md
26+++ b/TODO.md
27@@ -69,7 +69,6 @@ For example 64 tbs to a qt.
28 * LOGNORMDIST
29 * MODE
30 * NEGBINOMDIST
31-* NORMINV
32 * PERMUT
33 * PROB
34 * RANK
35diff --git a/dist/Formulas/AllFormulas.js b/dist/Formulas/AllFormulas.js
36index 9e2fec4..6db97e2 100644
37--- a/dist/Formulas/AllFormulas.js
38+++ b/dist/Formulas/AllFormulas.js
39@@ -161,6 +161,7 @@ exports.PERCENTRANK$EXC = Statistical_1.PERCENTRANK$EXC;
40 exports.NORMSINV = Statistical_1.NORMSINV;
41 exports.NORMSDIST = Statistical_1.NORMSDIST;
42 exports.NORMDIST = Statistical_1.NORMDIST;
43+exports.NORMINV = Statistical_1.NORMINV;
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 fdd2d0d..051fa33 100644
49--- a/dist/Formulas/Statistical.js
50+++ b/dist/Formulas/Statistical.js
51@@ -1141,3 +1141,79 @@ var NORMDIST = function (x, meanValue, standDev, cumulative) {
52 return (cumulative === 0) ? _pdf(x, meanValue, standDev) : _cdf(x, meanValue, standDev);
53 };
54 exports.NORMDIST = NORMDIST;
55+/**
56+ * Returns the inverse of the normal distribution for the given number in the distribution.
57+ * @param probability - Number in the distribution.
58+ * @param meanVal - The mean value in the normal distribution.
59+ * @param standDev - The standard deviation of the normal distribution.
60+ * @returns {number}
61+ * @constructor
62+ */
63+var NORMINV = function (probability, meanVal, standDev) {
64+ ArgsChecker_1.ArgsChecker.checkLength(arguments, 3, "NORMINV");
65+ function erf(x) {
66+ var cof = [-1.3026537197817094, 6.4196979235649026e-1, 1.9476473204185836e-2,
67+ -9.561514786808631e-3, -9.46595344482036e-4, 3.66839497852761e-4,
68+ 4.2523324806907e-5, -2.0278578112534e-5, -1.624290004647e-6,
69+ 1.303655835580e-6, 1.5626441722e-8, -8.5238095915e-8,
70+ 6.529054439e-9, 5.059343495e-9, -9.91364156e-10,
71+ -2.27365122e-10, 9.6467911e-11, 2.394038e-12,
72+ -6.886027e-12, 8.94487e-13, 3.13092e-13,
73+ -1.12708e-13, 3.81e-16, 7.106e-15,
74+ -1.523e-15, -9.4e-17, 1.21e-16,
75+ -2.8e-17];
76+ var j = cof.length - 1;
77+ var isneg = false;
78+ var d = 0;
79+ var dd = 0;
80+ var t, ty, tmp, res;
81+ if (x < 0) {
82+ x = -x;
83+ isneg = true;
84+ }
85+ t = 2 / (2 + x);
86+ ty = 4 * t - 2;
87+ for (; j > 0; j--) {
88+ tmp = d;
89+ d = ty * d - dd + cof[j];
90+ dd = tmp;
91+ }
92+ res = t * Math.exp(-x * x + 0.5 * (cof[0] + ty * d) - dd);
93+ return isneg ? res - 1 : 1 - res;
94+ }
95+ function erfc(x) {
96+ return 1 - erf(x);
97+ }
98+ function erfcinv(p) {
99+ var j = 0;
100+ var x, err, t, pp;
101+ if (p >= 2)
102+ return -100;
103+ if (p <= 0)
104+ return 100;
105+ pp = (p < 1) ? p : 2 - p;
106+ t = Math.sqrt(-2 * Math.log(pp / 2));
107+ x = -0.70711 * ((2.30753 + t * 0.27061) /
108+ (1 + t * (0.99229 + t * 0.04481)) - t);
109+ for (; j < 2; j++) {
110+ err = erfc(x) - pp;
111+ x += err / (1.12837916709551257 * Math.exp(-x * x) - x * err);
112+ }
113+ return (p < 1) ? x : -x;
114+ }
115+ function inv(p, meanVal, std) {
116+ return -1.41421356237309505 * std * erfcinv(2 * p) + meanVal;
117+ }
118+ probability = TypeConverter_1.TypeConverter.firstValueAsNumber(probability);
119+ meanVal = TypeConverter_1.TypeConverter.firstValueAsNumber(meanVal);
120+ standDev = TypeConverter_1.TypeConverter.firstValueAsNumber(standDev);
121+ if (probability <= 0 || probability >= 1) {
122+ throw new Errors_1.NumError("Function NORMINV parameter 1 value is " + probability +
123+ ". Valid values are between 0 and 1 exclusive.");
124+ }
125+ if (standDev <= 0) {
126+ throw new Errors_1.NumError("Function NORMINV parameter 3 value is " + standDev + ". It should be greater than 0.");
127+ }
128+ return inv(probability, meanVal, standDev);
129+};
130+exports.NORMINV = NORMINV;
131diff --git a/src/Formulas/AllFormulas.ts b/src/Formulas/AllFormulas.ts
132index 867af80..cf885e3 100644
133--- a/src/Formulas/AllFormulas.ts
134+++ b/src/Formulas/AllFormulas.ts
135@@ -166,7 +166,8 @@ import {
136 PERCENTRANK$EXC,
137 NORMSINV,
138 NORMSDIST,
139- NORMDIST
140+ NORMDIST,
141+ NORMINV
142 } from "./Statistical";
143 import {
144 ARABIC,
145@@ -404,5 +405,6 @@ export {
146 PERCENTRANK$EXC,
147 NORMSINV,
148 NORMSDIST,
149- NORMDIST
150+ NORMDIST,
151+ NORMINV
152 }
153\ No newline at end of file
154diff --git a/src/Formulas/Statistical.ts b/src/Formulas/Statistical.ts
155index f03e836..5a11ab1 100644
156--- a/src/Formulas/Statistical.ts
157+++ b/src/Formulas/Statistical.ts
158@@ -1138,6 +1138,86 @@ var NORMDIST = function (x, meanValue, standDev, cumulative) {
159 return (cumulative === 0) ? _pdf(x, meanValue, standDev) : _cdf(x, meanValue, standDev);
160 };
161
162+/**
163+ * Returns the inverse of the normal distribution for the given number in the distribution.
164+ * @param probability - Number in the distribution.
165+ * @param meanVal - The mean value in the normal distribution.
166+ * @param standDev - The standard deviation of the normal distribution.
167+ * @returns {number}
168+ * @constructor
169+ */
170+var NORMINV = function (probability, meanVal, standDev) {
171+ ArgsChecker.checkLength(arguments, 3, "NORMINV");
172+ function erf(x) {
173+ var cof = [-1.3026537197817094, 6.4196979235649026e-1, 1.9476473204185836e-2,
174+ -9.561514786808631e-3, -9.46595344482036e-4, 3.66839497852761e-4,
175+ 4.2523324806907e-5, -2.0278578112534e-5, -1.624290004647e-6,
176+ 1.303655835580e-6, 1.5626441722e-8, -8.5238095915e-8,
177+ 6.529054439e-9, 5.059343495e-9, -9.91364156e-10,
178+ -2.27365122e-10, 9.6467911e-11, 2.394038e-12,
179+ -6.886027e-12, 8.94487e-13, 3.13092e-13,
180+ -1.12708e-13, 3.81e-16, 7.106e-15,
181+ -1.523e-15, -9.4e-17, 1.21e-16,
182+ -2.8e-17];
183+ var j = cof.length - 1;
184+ var isneg = false;
185+ var d = 0;
186+ var dd = 0;
187+ var t, ty, tmp, res;
188+
189+ if (x < 0) {
190+ x = -x;
191+ isneg = true;
192+ }
193+
194+ t = 2 / (2 + x);
195+ ty = 4 * t - 2;
196+
197+ for(; j > 0; j--) {
198+ tmp = d;
199+ d = ty * d - dd + cof[j];
200+ dd = tmp;
201+ }
202+
203+ res = t * Math.exp(-x * x + 0.5 * (cof[0] + ty * d) - dd);
204+ return isneg ? res - 1 : 1 - res;
205+ }
206+ function erfc(x) {
207+ return 1 - erf(x);
208+ }
209+ function erfcinv(p) {
210+ var j = 0;
211+ var x, err, t, pp;
212+ if (p >= 2)
213+ return -100;
214+ if (p <= 0)
215+ return 100;
216+ pp = (p < 1) ? p : 2 - p;
217+ t = Math.sqrt(-2 * Math.log(pp / 2));
218+ x = -0.70711 * ((2.30753 + t * 0.27061) /
219+ (1 + t * (0.99229 + t * 0.04481)) - t);
220+ for (; j < 2; j++) {
221+ err = erfc(x) - pp;
222+ x += err / (1.12837916709551257 * Math.exp(-x * x) - x * err);
223+ }
224+ return (p < 1) ? x : -x;
225+ }
226+ function inv(p, meanVal ,std) {
227+ return -1.41421356237309505 * std * erfcinv(2 * p) + meanVal;
228+ }
229+ probability = TypeConverter.firstValueAsNumber(probability);
230+ meanVal = TypeConverter.firstValueAsNumber(meanVal);
231+ standDev = TypeConverter.firstValueAsNumber(standDev);
232+ if (probability <= 0 || probability >= 1) {
233+ throw new NumError("Function NORMINV parameter 1 value is " + probability +
234+ ". Valid values are between 0 and 1 exclusive.");
235+ }
236+ if (standDev <= 0) {
237+ throw new NumError("Function NORMINV parameter 3 value is " + standDev + ". It should be greater than 0.");
238+ }
239+ return inv(probability, meanVal, standDev);
240+};
241+
242
243 export {
244 AVERAGE,
245@@ -1178,5 +1258,6 @@ export {
246 PERCENTRANK$EXC,
247 NORMSINV,
248 NORMSDIST,
249- NORMDIST
250+ NORMDIST,
251+ NORMINV
252 }
253\ No newline at end of file
254diff --git a/tests/Formulas/StatisticalTest.ts b/tests/Formulas/StatisticalTest.ts
255index b6b462b..032366a 100644
256--- a/tests/Formulas/StatisticalTest.ts
257+++ b/tests/Formulas/StatisticalTest.ts
258@@ -37,7 +37,8 @@ import {
259 PERCENTRANK$EXC,
260 NORMSINV,
261 NORMSDIST,
262- NORMDIST
263+ NORMDIST,
264+ NORMINV
265 } from "../../src/Formulas/Statistical";
266 import * as ERRORS from "../../src/Errors";
267 import {
268@@ -800,4 +801,23 @@ test("NORMDIST", function() {
269 catchAndAssertEquals(function() {
270 NORMDIST.apply(this, [1, 0, 6, true, 5]);
271 }, ERRORS.NA_ERROR);
272+});
273+
274+
275+test("NORMINV", function() {
276+ assertEquals(NORMINV(0.8, 0, 6), 5.049727401437487);
277+ assertEquals(NORMINV(0.2, 0, 6), -5.049727401437487);
278+ assertEquals(NORMINV(0.4, 1, 6), -0.5200826188147996);
279+ catchAndAssertEquals(function() {
280+ NORMINV(-0.5, 0.44, 1);
281+ }, ERRORS.NUM_ERROR);
282+ catchAndAssertEquals(function() {
283+ NORMINV(0.5, 0.44, 0);
284+ }, ERRORS.NUM_ERROR);
285+ catchAndAssertEquals(function() {
286+ NORMINV.apply(this, [0.2, 0.8]);
287+ }, ERRORS.NA_ERROR);
288+ catchAndAssertEquals(function() {
289+ NORMINV.apply(this, [0.2, 0.8, 6, 1]);
290+ }, ERRORS.NA_ERROR);
291 });
292\ No newline at end of file
293diff --git a/tests/SheetFormulaTest.ts b/tests/SheetFormulaTest.ts
294index c52ad7d..02c5dc2 100644
295--- a/tests/SheetFormulaTest.ts
296+++ b/tests/SheetFormulaTest.ts
297@@ -789,6 +789,10 @@ test("Sheet NORMSINV", function(){
298 assertFormulaEquals('=NORMDIST(1, 0, 6, true)', 0.5661838326109037);
299 });
300
301+test("Sheet NORMINV", function(){
302+ assertFormulaEquals('=NORMINV(0.8, 0, 6)', 5.049727401437487);
303+});
304+
305 test("Sheet *", function(){
306 assertFormulaEquals('= 10 * 10', 100);
307 assertFormulaEquals('= 10 * 0', 0);