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