spreadsheet
typeScript/javascript spreadsheet parser, with formulas.
git clone https://git.vogt.world/spreadsheet.git
Log | Files | README.md
← Commit log
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);