spreadsheet
typeScript/javascript spreadsheet parser, with formulas.
git clone https://git.vogt.world/spreadsheet.git
Log | Files | README.md
← Commit log
commit
message
[PERCENTRANK.EXC] formula added and tested
author
Ben Vogt <[email protected]>
date
2017-07-03 16:00:38
stats
8 file(s) changed, 140 insertions(+), 9 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 ad58531..52495ae 100644
  3--- a/DOCS.md
  4+++ b/DOCS.md
  5@@ -1725,7 +1725,18 @@
  6   Returns the percentage rank (percentile) of the given value in a sample. Functions the same as PERCENTRANK.INC. 
  7 @param data - The array or range of data in the sample. 
  8 @param x - The value. 
  9-@param significance - [OPTIONAL] - The number of significant digits to use in the calculation. 
 10+@param significance - [OPTIONAL] - The number of significant digits to use in the calculation. Defaults to 3. 
 11+@returns {number} 
 12+@constructor
 13+```
 14+
 15+### EXC 
 16+
 17+```
 18+  Returns the percentage rank (percentile) from 0 to 1 exclusive for a value in a sample. 
 19+@param data - The array or range of data in the sample. 
 20+@param x - The value 
 21+@param significance - [OPTIONAL] - The number of significant digits to use in the calculation. Defaults to 3. 
 22 @returns {number} 
 23 @constructor
 24 ```
 25diff --git a/TODO.md b/TODO.md
 26index 88112eb..7ad7ef2 100644
 27--- a/TODO.md
 28+++ b/TODO.md
 29@@ -73,7 +73,6 @@ For example 64 tbs to a qt.
 30 * NORMINV
 31 * NORMSDIST
 32 * NORMSINV
 33-* PERCENTRANK.EXC
 34 * PERMUT
 35 * PROB
 36 * RANK
 37diff --git a/dist/Formulas/AllFormulas.js b/dist/Formulas/AllFormulas.js
 38index adde802..65d4a45 100644
 39--- a/dist/Formulas/AllFormulas.js
 40+++ b/dist/Formulas/AllFormulas.js
 41@@ -157,6 +157,7 @@ exports.INTERCEPT = Statistical_1.INTERCEPT;
 42 exports.FORECAST = Statistical_1.FORECAST;
 43 exports.POISSON = Statistical_1.POISSON;
 44 exports.PERCENTRANK = Statistical_1.PERCENTRANK;
 45+exports.PERCENTRANK$EXC = Statistical_1.PERCENTRANK$EXC;
 46 var Text_1 = require("./Text");
 47 exports.ARABIC = Text_1.ARABIC;
 48 exports.CHAR = Text_1.CHAR;
 49@@ -198,6 +199,7 @@ var __COMPLEX = {
 50     "NETWORKDAYS.INTL": Date_1.NETWORKDAYS$INTL,
 51     "WORKDAY.INTL": Date_1.WORKDAY$INTL,
 52     "POISSON.DIST": Statistical_1.POISSON,
 53-    "PERCENTRANK.INC": Statistical_1.PERCENTRANK
 54+    "PERCENTRANK.INC": Statistical_1.PERCENTRANK,
 55+    "PERCENTRANK.EXC": Statistical_1.PERCENTRANK$EXC
 56 };
 57 exports.__COMPLEX = __COMPLEX;
 58diff --git a/dist/Formulas/Statistical.js b/dist/Formulas/Statistical.js
 59index 5e24370..afd6bd5 100644
 60--- a/dist/Formulas/Statistical.js
 61+++ b/dist/Formulas/Statistical.js
 62@@ -974,7 +974,7 @@ exports.POISSON = POISSON;
 63  * Returns the percentage rank (percentile) of the given value in a sample. Functions the same as PERCENTRANK.INC.
 64  * @param data - The array or range of data in the sample.
 65  * @param x - The value.
 66- * @param significance - [OPTIONAL] - The number of significant digits to use in the calculation.
 67+ * @param significance - [OPTIONAL] - The number of significant digits to use in the calculation. Defaults to 3.
 68  * @returns {number}
 69  * @constructor
 70  */
 71@@ -1016,3 +1016,49 @@ var PERCENTRANK = function (data, x, significance) {
 72     return v;
 73 };
 74 exports.PERCENTRANK = PERCENTRANK;
 75+/**
 76+ * Returns the percentage rank (percentile) from 0 to 1 exclusive for a value in a sample.
 77+ * @param data - The array or range of data in the sample.
 78+ * @param x - The value
 79+ * @param significance - [OPTIONAL] - The number of significant digits to use in the calculation. Defaults to 3.
 80+ * @returns {number}
 81+ * @constructor
 82+ */
 83+var PERCENTRANK$EXC = function (data, x, significance) {
 84+    ArgsChecker_1.ArgsChecker.checkLengthWithin(arguments, 2, 3, "PERCENTRANK.EXC");
 85+    data = Filter_1.Filter.flattenAndThrow(data).map(TypeConverter_1.TypeConverter.valueToNumber).sort(function (a, b) {
 86+        return a - b;
 87+    });
 88+    x = TypeConverter_1.TypeConverter.firstValueAsNumber(x);
 89+    var uniques = Filter_1.Filter.unique(data);
 90+    var n = data.length;
 91+    var m = uniques.length;
 92+    if (x < uniques[0] || x > uniques[m - 1]) {
 93+        throw new Errors_1.NAError("PERCENTRANK.EXC does not have valid input data.");
 94+    }
 95+    if (m === 1 && uniques[0] === x) {
 96+        return 1;
 97+    }
 98+    significance = (typeof significance === 'undefined') ? 3 : TypeConverter_1.TypeConverter.firstValueAsNumber(significance);
 99+    var power = Math.pow(10, significance);
100+    var result = 0;
101+    var match = false;
102+    var i = 0;
103+    while (!match && i < m) {
104+        if (x === uniques[i]) {
105+            result = (data.indexOf(uniques[i]) + 1) / (n + 1);
106+            match = true;
107+        }
108+        else if (x >= uniques[i] && (x < uniques[i + 1] || i === m - 1)) {
109+            result = (data.indexOf(uniques[i]) + 1 + (x - uniques[i]) / (uniques[i + 1] - uniques[i])) / (n + 1);
110+            match = true;
111+        }
112+        i++;
113+    }
114+    var v = Math.floor(result * power) / power;
115+    if (isNaN(v)) {
116+        throw new Errors_1.NAError("PERCENTRANK.EXC does not have valid input data.");
117+    }
118+    return v;
119+};
120+exports.PERCENTRANK$EXC = PERCENTRANK$EXC;
121diff --git a/src/Formulas/AllFormulas.ts b/src/Formulas/AllFormulas.ts
122index 14416fa..64e38a9 100644
123--- a/src/Formulas/AllFormulas.ts
124+++ b/src/Formulas/AllFormulas.ts
125@@ -162,7 +162,8 @@ import {
126   INTERCEPT,
127   FORECAST,
128   POISSON,
129-  PERCENTRANK
130+  PERCENTRANK,
131+  PERCENTRANK$EXC
132 } from "./Statistical";
133 import {
134   ARABIC,
135@@ -208,7 +209,8 @@ var __COMPLEX = {
136   "NETWORKDAYS.INTL": NETWORKDAYS$INTL,
137   "WORKDAY.INTL": WORKDAY$INTL,
138   "POISSON.DIST": POISSON,
139-  "PERCENTRANK.INC": PERCENTRANK
140+  "PERCENTRANK.INC": PERCENTRANK,
141+  "PERCENTRANK.EXC": PERCENTRANK$EXC
142 };
143 
144 export {
145@@ -395,5 +397,6 @@ export {
146   ISURL,
147   LINEST,
148   POISSON,
149-  PERCENTRANK
150+  PERCENTRANK,
151+  PERCENTRANK$EXC
152 }
153\ No newline at end of file
154diff --git a/src/Formulas/Statistical.ts b/src/Formulas/Statistical.ts
155index b170058..5bc4d98 100644
156--- a/src/Formulas/Statistical.ts
157+++ b/src/Formulas/Statistical.ts
158@@ -966,7 +966,7 @@ var POISSON = function (x, meanValue, cumulative?) {
159  * Returns the percentage rank (percentile) of the given value in a sample. Functions the same as PERCENTRANK.INC.
160  * @param data - The array or range of data in the sample.
161  * @param x - The value.
162- * @param significance - [OPTIONAL] - The number of significant digits to use in the calculation.
163+ * @param significance - [OPTIONAL] - The number of significant digits to use in the calculation. Defaults to 3.
164  * @returns {number}
165  * @constructor
166  */
167@@ -1008,6 +1008,52 @@ var PERCENTRANK = function (data, x, significance?) {
168 };
169 
170 
171+/**
172+ * Returns the percentage rank (percentile) from 0 to 1 exclusive for a value in a sample.
173+ * @param data - The array or range of data in the sample.
174+ * @param x - The value
175+ * @param significance - [OPTIONAL] - The number of significant digits to use in the calculation. Defaults to 3.
176+ * @returns {number}
177+ * @constructor
178+ */
179+var PERCENTRANK$EXC = function (data, x, significance?) {
180+  ArgsChecker.checkLengthWithin(arguments, 2, 3, "PERCENTRANK.EXC");
181+  data = Filter.flattenAndThrow(data).map(TypeConverter.valueToNumber).sort(function (a, b) {
182+    return a - b;
183+  });
184+  x = TypeConverter.firstValueAsNumber(x);
185+  var uniques = Filter.unique(data);
186+  var n = data.length;
187+  var m = uniques.length;
188+  if (x < uniques[0] || x > uniques[m - 1]) {
189+    throw new NAError("PERCENTRANK.EXC does not have valid input data.");
190+  }
191+  if (m === 1 && uniques[0] === x) {
192+    return 1;
193+  }
194+  significance = (typeof significance === 'undefined') ? 3 : TypeConverter.firstValueAsNumber(significance);
195+  var power = Math.pow(10, significance);
196+  var result = 0;
197+  var match = false;
198+  var i = 0;
199+  while (!match && i < m) {
200+    if (x === uniques[i]) {
201+      result = (data.indexOf(uniques[i]) + 1) / (n + 1);
202+      match = true;
203+    } else if (x >= uniques[i] && (x < uniques[i + 1] || i === m - 1)) {
204+      result = (data.indexOf(uniques[i]) + 1 + (x - uniques[i]) / (uniques[i + 1] - uniques[i])) / (n + 1);
205+      match = true;
206+    }
207+    i++;
208+  }
209+  var v = Math.floor(result * power) / power;
210+  if (isNaN(v)) {
211+    throw new NAError("PERCENTRANK.EXC does not have valid input data.");
212+  }
213+  return v;
214+};
215+
216+
217 export {
218   AVERAGE,
219   AVERAGEA,
220@@ -1043,5 +1089,6 @@ export {
221   INTERCEPT,
222   FORECAST,
223   POISSON,
224-  PERCENTRANK
225+  PERCENTRANK,
226+  PERCENTRANK$EXC
227 }
228\ No newline at end of file
229diff --git a/tests/Formulas/StatisticalTest.ts b/tests/Formulas/StatisticalTest.ts
230index 84dae7f..539e959 100644
231--- a/tests/Formulas/StatisticalTest.ts
232+++ b/tests/Formulas/StatisticalTest.ts
233@@ -33,7 +33,8 @@ import {
234   INTERCEPT,
235   FORECAST,
236   POISSON,
237-  PERCENTRANK
238+  PERCENTRANK,
239+  PERCENTRANK$EXC
240 } from "../../src/Formulas/Statistical";
241 import * as ERRORS from "../../src/Errors";
242 import {
243@@ -732,4 +733,19 @@ test("PERCENTRANK", function() {
244   catchAndAssertEquals(function() {
245     PERCENTRANK([1, 5, 3, 7, 3, 2, 6, 8, 4, 9, 0, 3, 1], -1);
246   }, ERRORS.NA_ERROR);
247+});
248+
249+
250+test("PERCENTRANK$EXC", function() {
251+  assertEquals(PERCENTRANK$EXC([1, 5, 3, 7, 3, 2, 6, 8, 4, 9, 0, 3, 1], 4), 0.571);
252+  assertEquals(PERCENTRANK$EXC([1, 5, 3, 7, 3, 2, 6, 8, 4, 9, 0, 3, 1], 5), 0.642);
253+  assertEquals(PERCENTRANK$EXC([1, 5, 3, 7, 3, 2, 6, 8, 4, 9, 0, 3, 1], 7), 0.785);
254+  assertEquals(PERCENTRANK$EXC([1], 1), 1);
255+  assertEquals(PERCENTRANK$EXC([22], 22), 1);
256+  catchAndAssertEquals(function() {
257+    PERCENTRANK$EXC([1, 5, 3, 7, 3, 2, 6, 8, 4, 9, 0, 3, 1], 10);
258+  }, ERRORS.NA_ERROR);
259+  catchAndAssertEquals(function() {
260+    PERCENTRANK$EXC([1, 5, 3, 7, 3, 2, 6, 8, 4, 9, 0, 3, 1], -1);
261+  }, ERRORS.NA_ERROR);
262 });
263\ No newline at end of file
264diff --git a/tests/SheetFormulaTest.ts b/tests/SheetFormulaTest.ts
265index 8a8a1ed..8b17052 100644
266--- a/tests/SheetFormulaTest.ts
267+++ b/tests/SheetFormulaTest.ts
268@@ -777,6 +777,10 @@ test("Sheet PERCENTRANK, PERCENTRANK.INC", function(){
269   assertFormulaEquals('=PERCENTRANK.INC([1], 1)', 1);
270 });
271 
272+test("Sheet PERCENTRANK.EXC", function(){
273+  assertFormulaEquals('=PERCENTRANK.EXC([1], 1)', 1);
274+});
275+
276 test("Sheet *", function(){
277   assertFormulaEquals('= 10 * 10', 100);
278   assertFormulaEquals('= 10 * 0', 0);