[se] Added fix for HYPGEOM_DIST function (#1729)

[se] Added fix for HYPGEOM_DIST function

Co-authored-by: Dmitriy Orlov <dmitriy.orlov@onlyoffice.com>
Co-committed-by: Dmitriy Orlov <dmitriy.orlov@onlyoffice.com>
This commit is contained in:
Dmitriy Orlov
2025-12-01 11:20:21 +00:00
committed by Igor Zotov
parent 64c8a6d180
commit 79ddd0784a
2 changed files with 139 additions and 134 deletions

View File

@ -85,6 +85,38 @@ function (window, undefined) {
cT_DIST_2T, cT_DIST_RT, cT_INV, cT_INV_2T, cTINV, cTREND, cTRIMMEAN, cTTEST, cT_TEST, cVAR, cVARA, cVARP,
cVAR_P, cVAR_S, cVARPA, cWEIBULL, cWEIBULL_DIST, cZTEST, cZ_TEST);
const MAX_SIGNED_INTEGER = 2147483647; // 32 bit
function hypgeomDistExcel(k, n, M, N, cumulative) {
function logC(a, b) {
if (b < 0 || b > a) return -Infinity;
return getLogGamma(a + 1) - getLogGamma(b + 1) - getLogGamma(a - b + 1);
}
function pmf(x) {
return Math.exp(logC(M, x) + logC(N - M, n - x) - logC(N, n));
}
const xmin = Math.max(0, n - (N - M));
const xmax = Math.min(n, M);
// if (cumulative === "FALSE") return pmf(k);
if (!cumulative) {
if (k < xmin || k > xmax) return 0;
return pmf(k);
}
// CDF
if (k < xmin) return 0;
if (k >= xmax) return 1;
let sum = 0;
for (let x = xmin; x <= k; x++) {
sum += pmf(x);
}
return sum;
}
function integralPhi(x) { // Using gauss(x)+0.5 has severe cancellation errors for x<-4
return 0.5 * AscCommonExcel.rtl_math_erfc(-x * 0.7071067811865475); // * 1/sqrt(2)
}
@ -7281,29 +7313,29 @@ function (window, undefined) {
cHYPGEOMDIST.prototype.argumentsMax = 4;
cHYPGEOMDIST.prototype.argumentsType = [argType.number, argType.number, argType.number, argType.number];
cHYPGEOMDIST.prototype.Calculate = function (arg) {
var arg0 = arg[0], arg1 = arg[1], arg2 = arg[2], arg3 = arg[3];
let arg0 = arg[0], arg1 = arg[1], arg2 = arg[2], arg3 = arg[3];
if (arg0 instanceof cArea || arg0 instanceof cArea3D) {
if (arg0.type === cElementType.cellsRange || arg0.type === cElementType.cellsRange3D) {
arg0 = arg0.cross(arguments[1]);
} else if (arg0 instanceof cArray) {
} else if (arg0.type === cElementType.array) {
arg0 = arg0.getElement(0);
}
if (arg1 instanceof cArea || arg1 instanceof cArea3D) {
if (arg1.type === cElementType.cellsRange || arg1.type === cElementType.cellsRange3D) {
arg1 = arg1.cross(arguments[1]);
} else if (arg1 instanceof cArray) {
} else if (arg1.type === cElementType.array) {
arg1 = arg1.getElement(0);
}
if (arg2 instanceof cArea || arg2 instanceof cArea3D) {
if (arg2.type === cElementType.cellsRange || arg2.type === cElementType.cellsRange3D) {
arg2 = arg2.cross(arguments[1]);
} else if (arg2 instanceof cArray) {
} else if (arg2.type === cElementType.array) {
arg2 = arg2.getElement(0);
}
if (arg3 instanceof cArea || arg3 instanceof cArea3D) {
if (arg3.type === cElementType.cellsRange || arg3.type === cElementType.cellsRange3D) {
arg3 = arg3.cross(arguments[1]);
} else if (arg3 instanceof cArray) {
} else if (arg3.type === cElementType.array) {
arg3 = arg3.getElement(0);
}
@ -7312,30 +7344,36 @@ function (window, undefined) {
arg2 = arg2.tocNumber();
arg3 = arg3.tocNumber();
if (arg0 instanceof cError) {
if (arg0.type === cElementType.error) {
return arg0;
}
if (arg1 instanceof cError) {
if (arg1.type === cElementType.error) {
return arg1;
}
if (arg2 instanceof cError) {
if (arg2.type === cElementType.error) {
return arg2;
}
if (arg3 instanceof cError) {
if (arg3.type === cElementType.error) {
return arg3;
}
if (arg0.getValue() < 0 || arg0.getValue() > Math.min(arg1.getValue(), arg2.getValue()) ||
arg0.getValue() < Math.max(0, arg1.getValue() - arg3.getValue() + arg2.getValue()) ||
arg1.getValue() <= 0 || arg1.getValue() > arg3.getValue() || arg2.getValue() <= 0 ||
arg2.getValue() > arg3.getValue() || arg3.getValue() <= 0) {
arg0 = Math.floor(arg0);
arg1 = Math.floor(arg1);
arg2 = Math.floor(arg2);
arg3 = Math.floor(arg3);
if (arg0 < 0 || arg1 < 0 || arg2 < 0 || arg3 < 0 || arg1 > arg3 || arg2 > arg3 ) {
return new cError(cErrorType.not_numeric);
}
return new cNumber(Math.binomCoeff(arg2.getValue(), arg0.getValue()) *
Math.binomCoeff(arg3.getValue() - arg2.getValue(), arg1.getValue() - arg0.getValue()) /
Math.binomCoeff(arg3.getValue(), arg1.getValue()));
if (arg0 > MAX_SIGNED_INTEGER || arg1 > MAX_SIGNED_INTEGER || arg2 > MAX_SIGNED_INTEGER || arg3 > MAX_SIGNED_INTEGER) {
return new cError(cErrorType.not_numeric);
}
let res = hypgeomDistExcel(arg0, arg1, arg2, arg3, /*bCumulative*/ false);
return isNaN(res) ? new cError(cErrorType.not_numeric) : new cNumber(res);
};
@ -7355,54 +7393,47 @@ function (window, undefined) {
cHYPGEOM_DIST.prototype.isXLFN = true;
cHYPGEOM_DIST.prototype.argumentsType = [argType.number, argType.number, argType.number, argType.number, argType.logical];
cHYPGEOM_DIST.prototype.Calculate = function (arg) {
var oArguments = this._prepareArguments(arg, arguments[1], true);
var argClone = oArguments.args;
let oArguments = this._prepareArguments(arg, arguments[1], true);
let argClone = oArguments.args;
argClone[0] = argClone[0].tocNumber();
argClone[1] = argClone[1].tocNumber();
argClone[2] = argClone[2].tocNumber();
argClone[3] = argClone[3].tocNumber();
argClone[4] = argClone[4].tocNumber();
argClone[4] = argClone[4].tocBool();
var argError;
let argError;
if (argError = this._checkErrorArg(argClone)) {
return argError;
}
function hypgeomdist(argArray) {
var arg0 = Math.floor(argArray[0]);
var arg1 = Math.floor(argArray[1]);
var arg2 = Math.floor(argArray[2]);
var arg3 = Math.floor(argArray[3]);
var bCumulative = argArray[4];
if (argClone[4].type !== cElementType.bool) {
return new cError(cErrorType.wrong_value_type);
}
argClone[4] = argClone[4].value;
if (arg0 < 0 || arg0 > Math.min(arg1, arg2) || arg0 < Math.max(0, arg1 - arg3 + arg2) || arg1 <= 0 ||
arg1 > arg3 || arg2 <= 0 || arg2 > arg3 || arg3 <= 0) {
function hypgeomdist(argArray) {
let arg0 = Math.floor(argArray[0]),
arg1 = Math.floor(argArray[1]),
arg2 = Math.floor(argArray[2]),
arg3 = Math.floor(argArray[3]),
bCumulative = argArray[4];
if (arg0 < 0 || arg1 < 0 || arg2 < 0 || arg3 < 0 || arg1 > arg3 || arg2 > arg3 ) {
return new cError(cErrorType.not_numeric);
}
var res;
if (bCumulative) {
var fVal = 0.0;
if (arg0 > MAX_SIGNED_INTEGER || arg1 > MAX_SIGNED_INTEGER || arg2 > MAX_SIGNED_INTEGER || arg3 > MAX_SIGNED_INTEGER) {
return new cError(cErrorType.not_numeric);
}
//TODO значения неверные для этой ветки! пересчитать
for (var i = 0; i <= arg0; i++) {
var temp = Math.binomCoeff(arg2, i) * Math.binomCoeff(arg3 - arg2, arg1 - i) /
Math.binomCoeff(arg3, arg1);
if (!isNaN(temp)) {
fVal += temp;
}
}
res = fVal;
} else {
res = Math.binomCoeff(arg2, arg0) * Math.binomCoeff(arg3 - arg2, arg1 - arg0) /
Math.binomCoeff(arg3, arg1);
}
let res = hypgeomDistExcel(arg0, arg1, arg2, arg3, bCumulative);
return isNaN(res) ? new cError(cErrorType.not_numeric) : new cNumber(res);
}
return this._findArrayInNumberArguments(oArguments, hypgeomdist);
};

View File

@ -20406,11 +20406,7 @@ $(function () {
oParser = new parserFormula("HYPGEOMDIST(1,4,8,20)", "A1", ws);
assert.ok(oParser.parse());
assert.strictEqual(oParser.calculate().getValue(), hypgeomdist(1, 4, 8, 20));
oParser = new parserFormula("HYPGEOMDIST(1,4,8,20)", "A1", ws);
assert.ok(oParser.parse());
assert.strictEqual(oParser.calculate().getValue(), hypgeomdist(1, 4, 8, 20));
assert.strictEqual(oParser.calculate().getValue(), 0.3632610939112495);
oParser = new parserFormula("HYPGEOMDIST(-1,4,8,20)", "A1", ws);
assert.ok(oParser.parse());
@ -20418,7 +20414,7 @@ $(function () {
oParser = new parserFormula("HYPGEOMDIST(5,4,8,20)", "A1", ws);
assert.ok(oParser.parse());
assert.strictEqual(oParser.calculate().getValue(), "#NUM!");
assert.strictEqual(oParser.calculate().getValue(), 0);
ws.getRange2("A1:C214").cleanAll();
// Data for reference link. Use A100-A111
@ -20461,19 +20457,19 @@ $(function () {
// Case #1: Number(4). All arguments are integers. 4 of 4 arguments used.
oParser = new parserFormula('HYPGEOMDIST(2,10,5,20)', 'A2', ws);
assert.ok(oParser.parse(), 'Test: HYPGEOMDIST(2,10,5,20) is parsed.');
assert.strictEqual(oParser.calculate().getValue(), 0.34829721362229105, 'Test: Positive case: Number(4). All arguments are integers. 4 of 4 arguments used.');
assert.strictEqual(oParser.calculate().getValue(), 0.3482972136222904, 'Test: Positive case: Number(4). All arguments are integers. 4 of 4 arguments used.');
// Case #2: Number(4). All arguments are integers, different valid values. 4 of 4 arguments used.
oParser = new parserFormula('HYPGEOMDIST(1,5,3,15)', 'A2', ws);
assert.ok(oParser.parse(), 'Test: HYPGEOMDIST(1,5,3,15) is parsed.');
assert.strictEqual(oParser.calculate().getValue(), 0.4945054945054945, 'Test: Positive case: Number(4). All arguments are integers, different valid values. 4 of 4 arguments used.');
assert.strictEqual(oParser.calculate().getValue(), 0.4945054945054937, 'Test: Positive case: Number(4). All arguments are integers, different valid values. 4 of 4 arguments used.');
// Case #3: String(4). All arguments as strings convertible to valid numbers. 4 of 4 arguments used.
oParser = new parserFormula('HYPGEOMDIST("2","10","5","20")', 'A2', ws);
assert.ok(oParser.parse(), 'Test: HYPGEOMDIST("2","10","5","20") is parsed.');
assert.strictEqual(oParser.calculate().getValue(), 0.34829721362229105, 'Test: Positive case: String(4). All arguments as strings convertible to valid numbers. 4 of 4 arguments used.');
assert.strictEqual(oParser.calculate().getValue(), 0.3482972136222904, 'Test: Positive case: String(4). All arguments as strings convertible to valid numbers. 4 of 4 arguments used.');
// Case #4: Formula(4). All arguments filled with formulas resolving to valid values. 4 of 4 arguments used.
oParser = new parserFormula('HYPGEOMDIST(ABS(-2),SUM(5,5),MIN(10,5),MAX(10,20))', 'A2', ws);
assert.ok(oParser.parse(), 'Test: HYPGEOMDIST(ABS(-2),SUM(5,5),MIN(10,5),MAX(10,20)) is parsed.');
assert.strictEqual(oParser.calculate().getValue(), 0.34829721362229105, 'Test: Positive case: Formula(4). All arguments filled with formulas resolving to valid values. 4 of 4 arguments used.');
assert.strictEqual(oParser.calculate().getValue(), 0.3482972136222904, 'Test: Positive case: Formula(4). All arguments filled with formulas resolving to valid values. 4 of 4 arguments used.');
// Case #5: Reference link(4). All arguments as cell references to valid values. 4 of 4 arguments used.
oParser = new parserFormula('HYPGEOMDIST(A100,A101,A102,A103)', 'A2', ws);
assert.ok(oParser.parse(), 'Test: HYPGEOMDIST(A100,A101,A102,A103) is parsed.');
@ -20485,7 +20481,7 @@ $(function () {
// Case #7: Array(4). All arguments as single-element arrays. 4 of 4 arguments used.
oParser = new parserFormula('HYPGEOMDIST({2},{10},{5},{20})', 'A2', ws);
assert.ok(oParser.parse(), 'Test: HYPGEOMDIST({2},{10},{5},{20}) is parsed.');
assert.strictEqual(oParser.calculate().getValue(), 0.34829721362229105, 'Test: Positive case: Array(4). All arguments as single-element arrays. 4 of 4 arguments used.');
assert.strictEqual(oParser.calculate().getValue(), 0.3482972136222904, 'Test: Positive case: Array(4). All arguments as single-element arrays. 4 of 4 arguments used.');
// Case #8: Name(4). All arguments as named ranges with valid values. 4 of 4 arguments used.
oParser = new parserFormula('HYPGEOMDIST(TestName,TestName1,TestName2,TestName2)', 'A2', ws);
assert.ok(oParser.parse(), 'Test: HYPGEOMDIST(TestName,TestName1,TestName2,TestName2) is parsed.');
@ -20509,35 +20505,35 @@ $(function () {
// Case #13: Formula,Number(3). sample_s filled with IF formula. 4 of 4 arguments used.
oParser = new parserFormula('HYPGEOMDIST(IF(TRUE,2,1),10,5,20)', 'A2', ws);
assert.ok(oParser.parse(), 'Test: HYPGEOMDIST(IF(TRUE,2,1),10,5,20) is parsed.');
assert.strictEqual(oParser.calculate().getValue(), 0.34829721362229105, 'Test: Positive case: Formula,Number(3). sample_s filled with IF formula. 4 of 4 arguments used.');
assert.strictEqual(oParser.calculate().getValue(), 0.3482972136222904, 'Test: Positive case: Formula,Number(3). sample_s filled with IF formula. 4 of 4 arguments used.');
// Case #14: Date(4). Date arguments truncated to integers. 4 of 4 arguments used.
oParser = new parserFormula('HYPGEOMDIST(DATE(2025,1,1),DATE(2025,2,1),DATE(2025,3,1),DATE(2025,4,1))', 'A2', ws);
assert.ok(oParser.parse(), 'Test: HYPGEOMDIST(DATE(2025,1,1),DATE(2025,2,1),DATE(2025,3,1),DATE(2025,4,1)) is parsed.');
//? assert.strictEqual(oParser.calculate().getValue(), 0.960771353, 'Test: Positive case: Date(4). Date arguments truncated to integers. 4 of 4 arguments used.');
assert.strictEqual(oParser.calculate().getValue(), 0.9607713533224601, 'Test: Positive case: Date(4). Date arguments truncated to integers. 4 of 4 arguments used.');
// Case #15: Time(4). Time arguments adjusted to valid integers. 4 of 4 arguments used.
oParser = new parserFormula('HYPGEOMDIST(TIME(1,0,0)+2,TIME(2,0,0)+10,TIME(3,0,0)+5,TIME(4,0,0)+20)', 'A2', ws);
assert.ok(oParser.parse(), 'Test: HYPGEOMDIST(TIME(1,0,0)+2,TIME(2,0,0)+10,TIME(3,0,0)+5,TIME(4,0,0)+20) is parsed.');
assert.strictEqual(oParser.calculate().getValue(), 0.34829721362229105, 'Test: Positive case: Time(4). Time arguments adjusted to valid integers. 4 of 4 arguments used.');
assert.strictEqual(oParser.calculate().getValue(), 0.3482972136222904, 'Test: Positive case: Time(4). Time arguments adjusted to valid integers. 4 of 4 arguments used.');
// Case #16: Formula,Number(3). HYPGEOMDIST inside SUM formula. 4 of 4 arguments used.
oParser = new parserFormula('SUM(HYPGEOMDIST(2,10,5,20),0.1)', 'A2', ws);
assert.ok(oParser.parse(), 'Test: SUM(HYPGEOMDIST(2,10,5,20),0.1) is parsed.');
//? assert.strictEqual(oParser.calculate().getValue(), '#NUM!', 'Test: Positive case: Formula,Number(3). HYPGEOMDIST inside SUM formula. 4 of 4 arguments used.');
assert.strictEqual(oParser.calculate().getValue(), 0.44829721362229036, 'Test: Positive case: Formula,Number(3). HYPGEOMDIST inside SUM formula. 4 of 4 arguments used.');
// Case #17: String(3),Number. Numeric strings converted to numbers. 4 of 4 arguments used.
oParser = new parserFormula('HYPGEOMDIST("2","10","5",20)', 'A2', ws);
assert.ok(oParser.parse(), 'Test: HYPGEOMDIST("2","10","5",20) is parsed.');
assert.strictEqual(oParser.calculate().getValue(), 0.34829721362229105, 'Test: Positive case: String(3),Number. Numeric strings converted to numbers. 4 of 4 arguments used.');
assert.strictEqual(oParser.calculate().getValue(), 0.3482972136222904, 'Test: Positive case: String(3),Number. Numeric strings converted to numbers. 4 of 4 arguments used.');
// Case #18: Array(4). Multi-element arrays with valid values. 4 of 4 arguments used.
oParser = new parserFormula('HYPGEOMDIST({2,3},{10,15},{5,7},{20,25})', 'A2', ws);
assert.ok(oParser.parse(), 'Test: HYPGEOMDIST({2,3},{10,15},{5,7},{20,25}) is parsed.');
assert.strictEqual(oParser.calculate().getValue(), 0.34829721362229105, 'Test: Positive case: Array(4). Multi-element arrays with valid values. 4 of 4 arguments used.');
assert.strictEqual(oParser.calculate().getValue(), 0.3482972136222904, 'Test: Positive case: Array(4). Multi-element arrays with valid values. 4 of 4 arguments used.');
// Case #19: Number(4). All arguments as floats, truncated to integers. 4 of 4 arguments used.
oParser = new parserFormula('HYPGEOMDIST(2.7,10.8,5.6,20.4)', 'A2', ws);
assert.ok(oParser.parse(), 'Test: HYPGEOMDIST(2.7,10.8,5.6,20.4) is parsed.');
//? assert.strictEqual(oParser.calculate().getValue(), 0.34829721362229105, 'Test: Positive case: Number(4). All arguments as floats, truncated to integers. 4 of 4 arguments used.');
assert.strictEqual(oParser.calculate().getValue(), 0.3482972136222904, 'Test: Positive case: Number(4). All arguments as floats, truncated to integers. 4 of 4 arguments used.');
// Case #20: Number(4). Minimum valid integers for all arguments. 4 of 4 arguments used.
oParser = new parserFormula('HYPGEOMDIST(0,1,0,1)', 'A2', ws);
assert.ok(oParser.parse(), 'Test: HYPGEOMDIST(0,1,0,1) is parsed.');
//? assert.strictEqual(oParser.calculate().getValue(), 1, 'Test: Positive case: Number(4). Minimum valid integers for all arguments. 4 of 4 arguments used.');
assert.strictEqual(oParser.calculate().getValue(), 1, 'Test: Positive case: Number(4). Minimum valid integers for all arguments. 4 of 4 arguments used.');
// Negative cases:
// Case #1: Number(4). sample_s < 0 returns #NUM!. 4 of 4 arguments used.
@ -20559,11 +20555,11 @@ $(function () {
// Case #5: Number(4). sample_s > number_sample returns #NUM!. 4 of 4 arguments used.
oParser = new parserFormula('HYPGEOMDIST(11,10,5,20)', 'A2', ws);
assert.ok(oParser.parse(), 'Test: HYPGEOMDIST(11,10,5,20) is parsed.');
//? assert.strictEqual(oParser.calculate().getValue(), 0, 'Test: Negative case: Number(4). sample_s > number_sample returns #NUM!. 4 of 4 arguments used.');
assert.strictEqual(oParser.calculate().getValue(), 0, 'Test: Negative case: Number(4). sample_s > number_sample returns #NUM!. 4 of 4 arguments used.');
// Case #6: Number(4). sample_s > population_s returns #NUM!. 4 of 4 arguments used.
oParser = new parserFormula('HYPGEOMDIST(6,10,5,20)', 'A2', ws);
assert.ok(oParser.parse(), 'Test: HYPGEOMDIST(6,10,5,20) is parsed.');
//? assert.strictEqual(oParser.calculate().getValue(), 0, 'Test: Negative case: Number(4). sample_s > population_s returns #NUM!. 4 of 4 arguments used.');
assert.strictEqual(oParser.calculate().getValue(), 0, 'Test: Negative case: Number(4). sample_s > population_s returns #NUM!. 4 of 4 arguments used.');
// Case #7: Number(4). number_sample > number_pop returns #NUM!. 4 of 4 arguments used.
oParser = new parserFormula('HYPGEOMDIST(6,10,5,4)', 'A2', ws);
assert.ok(oParser.parse(), 'Test: HYPGEOMDIST(6,10,5,4) is parsed.');
@ -20575,7 +20571,7 @@ $(function () {
// Case #9: Number(4). sample_s < (number_sample - number_pop + population_s) returns #NUM!. 4 of 4 arguments used.
oParser = new parserFormula('HYPGEOMDIST(8,10,2,20)', 'A2', ws);
assert.ok(oParser.parse(), 'Test: HYPGEOMDIST(8,10,2,20) is parsed.');
//? assert.strictEqual(oParser.calculate().getValue(), 0, 'Test: Negative case: Number(4). sample_s < (number_sample - number_pop + population_s) returns #NUM!. 4 of 4 arguments used.');
assert.strictEqual(oParser.calculate().getValue(), 0, 'Test: Negative case: Number(4). sample_s < (number_sample - number_pop + population_s) returns #NUM!. 4 of 4 arguments used.');
// Case #10: String(4). Non-numeric string returns #VALUE!. 4 of 4 arguments used.
oParser = new parserFormula('HYPGEOMDIST("abc","10","5","20")', 'A2', ws);
assert.ok(oParser.parse(), 'Test: HYPGEOMDIST("abc","10","5","20") is parsed.');
@ -20583,15 +20579,15 @@ $(function () {
// Case #11: Empty,Number(3). sample_s empty returns #VALUE!. 4 of 4 arguments used.
oParser = new parserFormula('HYPGEOMDIST(,10,5,20)', 'A2', ws);
assert.ok(oParser.parse(), 'Test: HYPGEOMDIST(,10,5,20) is parsed.');
assert.strictEqual(oParser.calculate().getValue(), 0.016253869969040248, 'Test: Negative case: Empty,Number(3). sample_s empty returns #VALUE!. 4 of 4 arguments used.');
assert.strictEqual(oParser.calculate().getValue(), 0.016253869969040196, 'Test: Negative case: Empty,Number(3). sample_s empty returns #VALUE!. 4 of 4 arguments used.');
// Case #12: Number,Empty,Number(2). number_sample empty returns #VALUE!. 4 of 4 arguments used.
oParser = new parserFormula('HYPGEOMDIST(2,,5,20)', 'A2', ws);
assert.ok(oParser.parse(), 'Test: HYPGEOMDIST(2,,5,20) is parsed.');
//? assert.strictEqual(oParser.calculate().getValue(), 0, 'Test: Negative case: Number,Empty,Number(2). number_sample empty returns #VALUE!. 4 of 4 arguments used.');
assert.strictEqual(oParser.calculate().getValue(), 0, 'Test: Negative case: Number,Empty,Number(2). number_sample empty returns #VALUE!. 4 of 4 arguments used.');
// Case #13: Number(2),Empty,Number. population_s empty returns #VALUE!. 4 of 4 arguments used.
oParser = new parserFormula('HYPGEOMDIST(2,10,,20)', 'A2', ws);
assert.ok(oParser.parse(), 'Test: HYPGEOMDIST(2,10,,20) is parsed.');
//? assert.strictEqual(oParser.calculate().getValue(), 0, 'Test: Negative case: Number(2),Empty,Number. population_s empty returns #VALUE!. 4 of 4 arguments used.');
assert.strictEqual(oParser.calculate().getValue(), 0, 'Test: Negative case: Number(2),Empty,Number. population_s empty returns #VALUE!. 4 of 4 arguments used.');
// Case #14: Number(3),Empty. number_pop empty returns #VALUE!. 4 of 4 arguments used.
oParser = new parserFormula('HYPGEOMDIST(2,10,5,)', 'A2', ws);
assert.ok(oParser.parse(), 'Test: HYPGEOMDIST(2,10,5,) is parsed.');
@ -20602,20 +20598,21 @@ $(function () {
assert.strictEqual(oParser.calculate().getValue(), '#N/A', 'Test: Negative case: Error,Number(3). sample_s as error propagates #N/A. 4 of 4 arguments used.');
// Case #16: Area,Number(3). sample_s as multi-cell range returns #NUM!. 4 of 4 arguments used.
oParser = new parserFormula('HYPGEOMDIST(A100:A101,10,5,20)', 'A2', ws);
oParser.setArrayFormulaRef(ws.getRange2("B1:C2").bbox);
assert.ok(oParser.parse(), 'Test: HYPGEOMDIST(A100:A101,10,5,20) is parsed.');
//? assert.strictEqual(oParser.calculate().getValue(), 0.01625387, 'Test: Negative case: Area,Number(3). sample_s as multi-cell range returns #NUM!. 4 of 4 arguments used.');
assert.strictEqual(oParser.calculate().getElementRowCol(0,0).getValue().toFixed(8) - 0, 0.01625387, 'Test: Negative case: Area,Number(3). sample_s as multi-cell range returns #NUM!. 4 of 4 arguments used.');
// Case #17: Array,Number(3). sample_s as multi-element array returns #NUM!. 4 of 4 arguments used.
oParser = new parserFormula('HYPGEOMDIST({2,3},10,5,20)', 'A2', ws);
assert.ok(oParser.parse(), 'Test: HYPGEOMDIST({2,3},10,5,20) is parsed.');
assert.strictEqual(oParser.calculate().getValue(), 0.34829721362229105, 'Test: Negative case: Array,Number(3). sample_s as multi-element array returns #NUM!. 4 of 4 arguments used.');
assert.strictEqual(oParser.calculate().getValue(), 0.3482972136222904, 'Test: Negative case: Array,Number(3). sample_s as multi-element array returns #NUM!. 4 of 4 arguments used.');
// Case #18: Name,Number(3). sample_s as named range with area returns #VALUE!. 4 of 4 arguments used.
oParser = new parserFormula('HYPGEOMDIST(TestNameArea2,10,5,20)', 'A2', ws);
assert.ok(oParser.parse(), 'Test: HYPGEOMDIST(TestNameArea2,10,5,20) is parsed.');
assert.strictEqual(oParser.calculate().getValue(), 0.8126934984520123, 'Test: Negative case: Name,Number(3). sample_s as named range with area returns #VALUE!. 4 of 4 arguments used.');
assert.strictEqual(oParser.calculate().getValue(), 0.016253869969040196, 'Test: Negative case: Name,Number(3). sample_s as named range with area returns #VALUE!. 4 of 4 arguments used.');
// Case #19: Name3D,Number(3). sample_s as 3D named range with area returns #VALUE!. 4 of 4 arguments used.
oParser = new parserFormula('HYPGEOMDIST(TestNameArea3D2,10,5,20)', 'A2', ws);
assert.ok(oParser.parse(), 'Test: HYPGEOMDIST(TestNameArea3D2,10,5,20) is parsed.');
assert.strictEqual(oParser.calculate().getValue(), 0.8126934984520123, 'Test: Negative case: Name3D,Number(3). sample_s as 3D named range with area returns #VALUE!. 4 of 4 arguments used.');
assert.strictEqual(oParser.calculate().getValue(), 0.016253869969040196, 'Test: Negative case: Name3D,Number(3). sample_s as 3D named range with area returns #VALUE!. 4 of 4 arguments used.');
// Case #20: Formula,Number(3). sample_s as formula resulting in #NUM! propagates error. 4 of 4 arguments used.
oParser = new parserFormula('HYPGEOMDIST(SQRT(-1),10,5,20)', 'A2', ws);
assert.ok(oParser.parse(), 'Test: HYPGEOMDIST(SQRT(-1),10,5,20) is parsed.');
@ -20625,7 +20622,7 @@ $(function () {
// Case #1: Number(4). Minimum valid values for sample_s, number_sample, population_s, number_pop. 4 of 4 arguments used.
oParser = new parserFormula('HYPGEOMDIST(0,1,0,1)', 'A2', ws);
assert.ok(oParser.parse(), 'Test: HYPGEOMDIST(0,1,0,1) is parsed.');
//? assert.strictEqual(oParser.calculate().getValue(), 1, 'Test: Bounded case: Number(4). Minimum valid values for sample_s, number_sample, population_s, number_pop. 4 of 4 arguments used.');
assert.strictEqual(oParser.calculate().getValue(), 1, 'Test: Bounded case: Number(4). Minimum valid values for sample_s, number_sample, population_s, number_pop. 4 of 4 arguments used.');
// Case #2: Number(4). Maximum valid Excel numbers (truncated to integers). 4 of 4 arguments used.
oParser = new parserFormula('HYPGEOMDIST(1E+307,1E+307,1E+307,1E+307)', 'A2', ws);
assert.ok(oParser.parse(), 'Test: HYPGEOMDIST(1E+307,1E+307,1E+307,1E+307) is parsed.');
@ -20633,20 +20630,7 @@ $(function () {
// Case #3: Number(4). Smallest positive number for sample_s (truncates to 0). 4 of 4 arguments used.
oParser = new parserFormula('HYPGEOMDIST(1E-307,2,1,3)', 'A2', ws);
assert.ok(oParser.parse(), 'Test: HYPGEOMDIST(1E-307,2,1,3) is parsed.');
assert.strictEqual(oParser.calculate().getValue(), 0.3333333333333333, 'Test: Bounded case: Number(4). Smallest positive number for sample_s (truncates to 0). 4 of 4 arguments used.');
// Need to fix: ms diff results, boundary cases problem
// Case #14: Date(4). Date arguments truncated to integers. 4 of 4 arguments used.
// Case #16: Formula,Number(3). HYPGEOMDIST inside SUM formula. 4 of 4 arguments used.
// Case #19: Number(4). All arguments as floats, truncated to integers. 4 of 4 arguments used.
// Case #20: Number(4). Minimum valid integers for all arguments. 4 of 4 arguments used
// Case #5: Number(4). sample_s > number_sample returns #NUM!. 4 of 4 arguments used.
// Case #6: Number(4). sample_s > population_s returns #NUM!. 4 of 4 arguments used.
// Case #9: Number(4). sample_s < (number_sample - number_pop + population_s) returns #NUM!. 4 of 4 arguments used.
// Case #12: Number,Empty,Number(2). number_sample empty returns #VALUE!. 4 of 4 arguments used.
// Case #13: Number(2),Empty,Number. population_s empty returns #VALUE!. 4 of 4 arguments used.
// Case #16: Area,Number(3). sample_s as multi-cell range returns #NUM!. 4 of 4 arguments used.
// Case #1: Number(4). Minimum valid values for sample_s, number_sample, population_s, number_pop. 4 of 4 arguments used.
assert.strictEqual(oParser.calculate().getValue().toFixed(2) - 0, 0.33, 'Test: Bounded case: Number(4). Smallest positive number for sample_s (truncates to 0). 4 of 4 arguments used.');
testArrayFormula2(assert, "HYPGEOMDIST", 4, 4);
@ -20672,7 +20656,7 @@ $(function () {
oParser = new parserFormula("HYPGEOM.DIST(1,2,3,4,5)", "A1", ws);
assert.ok(oParser.parse());
assert.strictEqual(oParser.calculate().getValue() - 0, 0.5);
assert.strictEqual(oParser.calculate().getValue().toFixed(2) - 0, 0.5);
ws.getRange2("A1:C214").cleanAll();
// Data for reference link. Use A100-A111
@ -20714,23 +20698,23 @@ $(function () {
// Case #1: Number(5). All arguments are integers, cumulative TRUE. 5 of 5 arguments used.
oParser = new parserFormula('HYPGEOM.DIST(2,10,5,20,TRUE)', 'A2', ws);
assert.ok(oParser.parse(), 'Test: HYPGEOM.DIST(2,10,5,20,TRUE) is parsed.');
assert.strictEqual(oParser.calculate().getValue(), 0.5, 'Test: Positive case: Number(5). All arguments are integers, cumulative TRUE. 5 of 5 arguments used.');
assert.strictEqual(oParser.calculate().getValue().toFixed(2) - 0, 0.5, 'Test: Positive case: Number(5). All arguments are integers, cumulative TRUE. 5 of 5 arguments used.');
// Case #2: Number(5). All arguments are integers, cumulative FALSE. 5 of 5 arguments used.
oParser = new parserFormula('HYPGEOM.DIST(2,10,5,20,FALSE)', 'A2', ws);
assert.ok(oParser.parse(), 'Test: HYPGEOM.DIST(2,10,5,20,FALSE) is parsed.');
assert.strictEqual(oParser.calculate().getValue(), 0.34829721362229105, 'Test: Positive case: Number(5). All arguments are integers, cumulative FALSE. 5 of 5 arguments used.');
assert.strictEqual(oParser.calculate().getValue(), 0.3482972136222904, 'Test: Positive case: Number(5). All arguments are integers, cumulative FALSE. 5 of 5 arguments used.');
// Case #3: Number(4),Boolean. Cumulative as numeric 1 (converts to TRUE). 5 of 5 arguments used.
oParser = new parserFormula('HYPGEOM.DIST(2,10,5,20,1)', 'A2', ws);
assert.ok(oParser.parse(), 'Test: HYPGEOM.DIST(2,10,5,20,1) is parsed.');
assert.strictEqual(oParser.calculate().getValue(), 0.5, 'Test: Positive case: Number(4),Boolean. Cumulative as numeric 1 (converts to TRUE). 5 of 5 arguments used.');
assert.strictEqual(oParser.calculate().getValue().toFixed(2) - 0, 0.5, 'Test: Positive case: Number(4),Boolean. Cumulative as numeric 1 (converts to TRUE). 5 of 5 arguments used.');
// Case #4: String(5). All arguments as strings convertible to valid numbers/boolean. 5 of 5 arguments used.
oParser = new parserFormula('HYPGEOM.DIST("2","10","5","20","TRUE")', 'A2', ws);
assert.ok(oParser.parse(), 'Test: HYPGEOM.DIST("2","10","5","20","TRUE") is parsed.');
//? assert.strictEqual(oParser.calculate().getValue(), 0.5, 'Test: Positive case: String(5). All arguments as strings convertible to valid numbers/boolean. 5 of 5 arguments used.');
assert.strictEqual(oParser.calculate().getValue().toFixed(2) - 0, 0.5, 'Test: Positive case: String(5). All arguments as strings convertible to valid numbers/boolean. 5 of 5 arguments used.');
// Case #5: Formula(5). All arguments filled with formulas resolving to valid values. 5 of 5 arguments used.
oParser = new parserFormula('HYPGEOM.DIST(ABS(-2),SUM(5,5),MIN(10,5),MAX(10,20),IF(TRUE,1,0))', 'A2', ws);
assert.ok(oParser.parse(), 'Test: HYPGEOM.DIST(ABS(-2),SUM(5,5),MIN(10,5),MAX(10,20),IF(TRUE,1,0)) is parsed.');
assert.strictEqual(oParser.calculate().getValue(), 0.5, 'Test: Positive case: Formula(5). All arguments filled with formulas resolving to valid values. 5 of 5 arguments used.');
assert.strictEqual(oParser.calculate().getValue().toFixed(2) - 0, 0.5, 'Test: Positive case: Formula(5). All arguments filled with formulas resolving to valid values. 5 of 5 arguments used.');
// Case #6: Reference link(5). All arguments as cell references to valid values. 5 of 5 arguments used.
oParser = new parserFormula('HYPGEOM.DIST(A100,A101,A102,A103,A104)', 'A2', ws);
assert.ok(oParser.parse(), 'Test: HYPGEOM.DIST(A100,A101,A102,A103,A104) is parsed.');
@ -20742,7 +20726,7 @@ $(function () {
// Case #8: Array(5). All arguments as single-element arrays. 5 of 5 arguments used.
oParser = new parserFormula('HYPGEOM.DIST({2},{10},{5},{20},{TRUE})', 'A2', ws);
assert.ok(oParser.parse(), 'Test: HYPGEOM.DIST({2},{10},{5},{20},{TRUE}) is parsed.');
assert.strictEqual(oParser.calculate().getValue(), 0.5, 'Test: Positive case: Array(5). All arguments as single-element arrays. 5 of 5 arguments used.');
assert.strictEqual(oParser.calculate().getValue().toFixed(2) - 0, 0.5, 'Test: Positive case: Array(5). All arguments as single-element arrays. 5 of 5 arguments used.');
// Case #9: Name(5). All arguments as named ranges with valid values. 5 of 5 arguments used.
oParser = new parserFormula('HYPGEOM.DIST(TestName,TestName1,TestName2,TestName,TestName)', 'A2', ws);
assert.ok(oParser.parse(), 'Test: HYPGEOM.DIST(TestName,TestName1,TestName2,TestName,TestName) is parsed.');
@ -20766,31 +20750,31 @@ $(function () {
// Case #14: Number(4),Formula. Cumulative filled with IF formula. 5 of 5 arguments used.
oParser = new parserFormula('HYPGEOM.DIST(2,10,5,20,IF(TRUE,TRUE,FALSE))', 'A2', ws);
assert.ok(oParser.parse(), 'Test: HYPGEOM.DIST(2,10,5,20,IF(TRUE,TRUE,FALSE)) is parsed.');
assert.strictEqual(oParser.calculate().getValue(), 0.5, 'Test: Positive case: Number(4),Formula. Cumulative filled with IF formula. 5 of 5 arguments used.');
assert.strictEqual(oParser.calculate().getValue().toFixed(2) - 0, 0.5, 'Test: Positive case: Number(4),Formula. Cumulative filled with IF formula. 5 of 5 arguments used.');
// Case #15: Date(4),Boolean. Date arguments truncated to integers. 5 of 5 arguments used.
oParser = new parserFormula('HYPGEOM.DIST(DATE(2025,1,1),DATE(2025,2,1),DATE(2025,3,1),DATE(2025,4,1),TRUE)', 'A2', ws);
assert.ok(oParser.parse(), 'Test: HYPGEOM.DIST(DATE(2025,1,1),DATE(2025,2,1),DATE(2025,3,1),DATE(2025,4,1),TRUE) is parsed.');
//? assert.strictEqual(oParser.calculate().getValue(), 0.960771353, 'Test: Positive case: Date(4),Boolean. Date arguments truncated to integers. 5 of 5 arguments used.');
assert.strictEqual(oParser.calculate().getValue().toFixed(9) - 0, 0.960771353, 'Test: Positive case: Date(4),Boolean. Date arguments truncated to integers. 5 of 5 arguments used.');
// Case #16: Time(4),Boolean. Time arguments adjusted to valid integers. 5 of 5 arguments used.
oParser = new parserFormula('HYPGEOM.DIST(TIME(1,0,0)+1,TIME(2,0,0)+10,TIME(3,0,0)+5,TIME(4,0,0)+20,TRUE)', 'A2', ws);
assert.ok(oParser.parse(), 'Test: HYPGEOM.DIST(TIME(1,0,0)+1,TIME(2,0,0)+10,TIME(3,0,0)+5,TIME(4,0,0)+20,TRUE) is parsed.');
assert.strictEqual(oParser.calculate().getValue(), 0.15170278637770898, 'Test: Positive case: Time(4),Boolean. Time arguments adjusted to valid integers. 5 of 5 arguments used.');
assert.strictEqual(oParser.calculate().getValue().toFixed(9) - 0, 0.151702786, 'Test: Positive case: Time(4),Boolean. Time arguments adjusted to valid integers. 5 of 5 arguments used.');
// Case #17: Formula,Number(4). HYPGEOM.DIST inside SUM formula. 5 of 5 arguments used.
oParser = new parserFormula('SUM(HYPGEOM.DIST(2,10,5,20,TRUE),0.1)', 'A2', ws);
assert.ok(oParser.parse(), 'Test: SUM(HYPGEOM.DIST(2,10,5,20,TRUE),0.1) is parsed.');
assert.strictEqual(oParser.calculate().getValue(), 0.6, 'Test: Positive case: Formula,Number(4). HYPGEOM.DIST inside SUM formula. 5 of 5 arguments used.');
assert.strictEqual(oParser.calculate().getValue().toFixed(2) - 0, 0.6, 'Test: Positive case: Formula,Number(4). HYPGEOM.DIST inside SUM formula. 5 of 5 arguments used.');
// Case #18: String(4),Number. Numeric strings converted to numbers, cumulative as 1. 5 of 5 arguments used.
oParser = new parserFormula('HYPGEOM.DIST("2","10","5","20",1)', 'A2', ws);
assert.ok(oParser.parse(), 'Test: HYPGEOM.DIST("2","10","5","20",1) is parsed.');
assert.strictEqual(oParser.calculate().getValue(), 0.5, 'Test: Positive case: String(4),Number. Numeric strings converted to numbers, cumulative as 1. 5 of 5 arguments used.');
assert.strictEqual(oParser.calculate().getValue().toFixed(2) - 0, 0.5, 'Test: Positive case: String(4),Number. Numeric strings converted to numbers, cumulative as 1. 5 of 5 arguments used.');
// Case #19: Array(5). Multi-element arrays with valid values. 5 of 5 arguments used.
oParser = new parserFormula('HYPGEOM.DIST({2,3},{10,15},{5,7},{20,25},{TRUE,FALSE})', 'A2', ws);
assert.ok(oParser.parse(), 'Test: HYPGEOM.DIST({2,3},{10,15},{5,7},{20,25},{TRUE,FALSE}) is parsed.');
assert.strictEqual(oParser.calculate().getValue(), 0.5, 'Test: Positive case: Array(5). Multi-element arrays with valid values. 5 of 5 arguments used.');
assert.strictEqual(oParser.calculate().getValue().toFixed(2) - 0, 0.5, 'Test: Positive case: Array(5). Multi-element arrays with valid values. 5 of 5 arguments used.');
// Case #20: Number(5). All arguments as floats, truncated to integers. 5 of 5 arguments used.
oParser = new parserFormula('HYPGEOM.DIST(2.7,10.8,5.6,20.4,0.9)', 'A2', ws);
assert.ok(oParser.parse(), 'Test: HYPGEOM.DIST(2.7,10.8,5.6,20.4,0.9) is parsed.');
assert.strictEqual(oParser.calculate().getValue(), 0.5, 'Test: Positive case: Number(5). All arguments as floats, truncated to integers. 5 of 5 arguments used.');
assert.strictEqual(oParser.calculate().getValue().toFixed(2) - 0, 0.5, 'Test: Positive case: Number(5). All arguments as floats, truncated to integers. 5 of 5 arguments used.');
// Negative cases:
// Case #1: Number(5). sample_s < 0 returns #NUM!. 5 of 5 arguments used.
@ -20812,11 +20796,11 @@ $(function () {
// Case #5: Number(5). sample_s > number_sample returns #NUM!. 5 of 5 arguments used.
oParser = new parserFormula('HYPGEOM.DIST(11,10,5,20,TRUE)', 'A2', ws);
assert.ok(oParser.parse(), 'Test: HYPGEOM.DIST(11,10,5,20,TRUE) is parsed.');
//? assert.strictEqual(oParser.calculate().getValue(), 1, 'Test: Negative case: Number(5). sample_s > number_sample returns #NUM!. 5 of 5 arguments used.');
assert.strictEqual(oParser.calculate().getValue(), 1, 'Test: Negative case: Number(5). sample_s > number_sample returns #NUM!. 5 of 5 arguments used.');
// Case #6: Number(5). sample_s > population_s returns #NUM!. 5 of 5 arguments used.
oParser = new parserFormula('HYPGEOM.DIST(6,10,5,20,TRUE)', 'A2', ws);
assert.ok(oParser.parse(), 'Test: HYPGEOM.DIST(6,10,5,20,TRUE) is parsed.');
//? assert.strictEqual(oParser.calculate().getValue(), 1, 'Test: Negative case: Number(5). sample_s > population_s returns #NUM!. 5 of 5 arguments used.');
assert.strictEqual(oParser.calculate().getValue(), 1, 'Test: Negative case: Number(5). sample_s > population_s returns #NUM!. 5 of 5 arguments used.');
// Case #7: Number(5). number_sample > number_pop returns #NUM!. 5 of 5 arguments used.
oParser = new parserFormula('HYPGEOM.DIST(6,10,5,4,TRUE)', 'A2', ws);
assert.ok(oParser.parse(), 'Test: HYPGEOM.DIST(6,10,5,4,TRUE) is parsed.');
@ -20828,23 +20812,23 @@ $(function () {
// Case #9: Number(5). sample_s < (number_sample - number_pop + population_s) returns #NUM!. 5 of 5 arguments used.
oParser = new parserFormula('HYPGEOM.DIST(8,10,2,20,TRUE)', 'A2', ws);
assert.ok(oParser.parse(), 'Test: HYPGEOM.DIST(8,10,2,20,TRUE) is parsed.');
//? assert.strictEqual(oParser.calculate().getValue(), 1, 'Test: Negative case: Number(5). sample_s < (number_sample - number_pop + population_s) returns #NUM!. 5 of 5 arguments used.');
assert.strictEqual(oParser.calculate().getValue(), 1, 'Test: Negative case: Number(5). sample_s < (number_sample - number_pop + population_s) returns #NUM!. 5 of 5 arguments used.');
// Case #10: String(5). Non-numeric string returns #VALUE!. 5 of 5 arguments used.
oParser = new parserFormula('HYPGEOM.DIST("abc","10","5","20","TRUE")', 'A2', ws);
assert.ok(oParser.parse(), 'Test: HYPGEOM.DIST("abc","10","5","20","TRUE") is parsed.');
assert.strictEqual(oParser.calculate().getValue(), '#VALUE!', 'Test: Negative case: String(5). Non-numeric string returns #VALUE!. 5 of 5 arguments used.');
// Case #11: Empty,Number(4). sample_s empty returns #VALUE!. 5 of 5 arguments used.
// Case #11: Empty,Number(4). sample_s empty returns number. 5 of 5 arguments used.
oParser = new parserFormula('HYPGEOM.DIST(,10,5,20,TRUE)', 'A2', ws);
assert.ok(oParser.parse(), 'Test: HYPGEOM.DIST(,10,5,20,TRUE) is parsed.');
assert.strictEqual(oParser.calculate().getValue(), 0.016253869969040248, 'Test: Negative case: Empty,Number(4). sample_s empty returns #VALUE!. 5 of 5 arguments used.');
assert.strictEqual(oParser.calculate().getValue().toFixed(9) - 0, 0.01625387, 'Test: Negative case: Empty,Number(4). sample_s empty returns number. 5 of 5 arguments used.');
// Case #12: Number,Empty,Number(3). number_sample empty returns #VALUE!. 5 of 5 arguments used.
oParser = new parserFormula('HYPGEOM.DIST(2,,5,20,TRUE)', 'A2', ws);
assert.ok(oParser.parse(), 'Test: HYPGEOM.DIST(2,,5,20,TRUE) is parsed.');
//? assert.strictEqual(oParser.calculate().getValue(), 1, 'Test: Negative case: Number,Empty,Number(3). number_sample empty returns #VALUE!. 5 of 5 arguments used.');
assert.strictEqual(oParser.calculate().getValue(), 1, 'Test: Negative case: Number,Empty,Number(3). number_sample empty returns #VALUE!. 5 of 5 arguments used.');
// Case #13: Number(2),Empty,Number(2). population_s empty returns #VALUE!. 5 of 5 arguments used.
oParser = new parserFormula('HYPGEOM.DIST(2,10,,20,TRUE)', 'A2', ws);
assert.ok(oParser.parse(), 'Test: HYPGEOM.DIST(2,10,,20,TRUE) is parsed.');
//? assert.strictEqual(oParser.calculate().getValue(), 1, 'Test: Negative case: Number(2),Empty,Number(2). population_s empty returns #VALUE!. 5 of 5 arguments used.');
assert.strictEqual(oParser.calculate().getValue(), 1, 'Test: Negative case: Number(2),Empty,Number(2). population_s empty returns #VALUE!. 5 of 5 arguments used.');
// Case #14: Number(3),Empty,Boolean. number_pop empty returns #VALUE!. 5 of 5 arguments used.
oParser = new parserFormula('HYPGEOM.DIST(2,10,5,,TRUE)', 'A2', ws);
assert.ok(oParser.parse(), 'Test: HYPGEOM.DIST(2,10,5,,TRUE) is parsed.');
@ -20859,46 +20843,36 @@ $(function () {
assert.strictEqual(oParser.calculate().getValue(), '#N/A', 'Test: Negative case: Error,Number(4). sample_s as error propagates #N/A. 5 of 5 arguments used.');
// Case #17: Area,Number(4). sample_s as multi-cell range returns #NUM!. 5 of 5 arguments used.
oParser = new parserFormula('HYPGEOM.DIST(A100:A101,10,5,20,TRUE)', 'A2', ws);
oParser.setArrayFormulaRef(ws.getRange2("B1:C2").bbox);
assert.ok(oParser.parse(), 'Test: HYPGEOM.DIST(A100:A101,10,5,20,TRUE) is parsed.');
//? assert.strictEqual(oParser.calculate().getValue(), 0.01625387, 'Test: Negative case: Area,Number(4). sample_s as multi-cell range returns #NUM!. 5 of 5 arguments used.');
assert.strictEqual(oParser.calculate().getElementRowCol(0,0).getValue(), 0.016253869969040196, 'Test: Negative case: Area,Number(4). sample_s as multi-cell range returns #NUM!. 5 of 5 arguments used.');
// Case #18: Array,Number(4). sample_s as multi-element array returns #NUM!. 5 of 5 arguments used.
oParser = new parserFormula('HYPGEOM.DIST({2,3},10,5,20,TRUE)', 'A2', ws);
assert.ok(oParser.parse(), 'Test: HYPGEOM.DIST({2,3},10,5,20,TRUE) is parsed.');
assert.strictEqual(oParser.calculate().getValue(), 0.5, 'Test: Negative case: Array,Number(4). sample_s as multi-element array returns #NUM!. 5 of 5 arguments used.');
assert.strictEqual(oParser.calculate().getValue().toFixed(2) - 0, 0.5, 'Test: Negative case: Array,Number(4). sample_s as multi-element array returns #NUM!. 5 of 5 arguments used.');
// Case #19: Name,Number(4). sample_s as named range with area returns #VALUE!. 5 of 5 arguments used.
oParser = new parserFormula('HYPGEOM.DIST(TestNameArea2,10,5,20,TRUE)', 'A2', ws);
assert.ok(oParser.parse(), 'Test: HYPGEOM.DIST(TestNameArea2,10,5,20,TRUE) is parsed.');
assert.strictEqual(oParser.calculate().getValue(), 0.016253869969040248, 'Test: Negative case: Name,Number(4). sample_s as named range with area returns #VALUE!. 5 of 5 arguments used.');
assert.strictEqual(oParser.calculate().getValue(), 0.016253869969040196, 'Test: Negative case: Name,Number(4). sample_s as named range with area returns #VALUE!. 5 of 5 arguments used.');
// Case #20: Name3D,Number(4). sample_s as 3D named range with area returns #VALUE!. 5 of 5 arguments used.
oParser = new parserFormula('HYPGEOM.DIST(TestNameArea3D2,10,5,20,TRUE)', 'A2', ws);
assert.ok(oParser.parse(), 'Test: HYPGEOM.DIST(TestNameArea3D2,10,5,20,TRUE) is parsed.');
assert.strictEqual(oParser.calculate().getValue(), 0.016253869969040248, 'Test: Negative case: Name3D,Number(4). sample_s as 3D named range with area returns #VALUE!. 5 of 5 arguments used.');
assert.strictEqual(oParser.calculate().getValue(), 0.016253869969040196, 'Test: Negative case: Name3D,Number(4). sample_s as 3D named range with area returns #VALUE!. 5 of 5 arguments used.');
// Bounded cases:
// Case #1: Number(5). Minimum valid values for sample_s, number_sample, population_s, number_pop. 5 of 5 arguments used.
oParser = new parserFormula('HYPGEOM.DIST(0,1,0,1,TRUE)', 'A2', ws);
assert.ok(oParser.parse(), 'Test: HYPGEOM.DIST(0,1,0,1,TRUE) is parsed.');
//? assert.strictEqual(oParser.calculate().getValue(), 1, 'Test: Bounded case: Number(5). Minimum valid values for sample_s, number_sample, population_s, number_pop. 5 of 5 arguments used.');
assert.strictEqual(oParser.calculate().getValue(), 1, 'Test: Bounded case: Number(5). Minimum valid values for sample_s, number_sample, population_s, number_pop. 5 of 5 arguments used.');
// Case #2: Number(5). Maximum valid Excel numbers (truncated to integers). 5 of 5 arguments used.
oParser = new parserFormula('HYPGEOM.DIST(1E+307,1E+307,1E+307,1E+307,TRUE)', 'A2', ws);
// assert.ok(oParser.parse(), 'Test: HYPGEOM.DIST(1E+307,1E+307,1E+307,1E+307,TRUE) is parsed.');
//?! assert.strictEqual(oParser.calculate().getValue(), '#NUM!', 'Test: Bounded case: Number(5). Maximum valid Excel numbers (truncated to integers). 5 of 5 arguments used.');
assert.ok(oParser.parse(), 'Test: HYPGEOM.DIST(1E+307,1E+307,1E+307,1E+307,TRUE) is parsed.');
assert.strictEqual(oParser.calculate().getValue(), '#NUM!', 'Test: Bounded case: Number(5). Maximum valid Excel numbers (truncated to integers). 5 of 5 arguments used.');
// Case #3: Number(5). Smallest positive number for sample_s (truncates to 0). 5 of 5 arguments used.
oParser = new parserFormula('HYPGEOM.DIST(1E-307,2,1,3,TRUE)', 'A2', ws);
assert.ok(oParser.parse(), 'Test: HYPGEOM.DIST(1E-307,2,1,3,TRUE) is parsed.');
assert.strictEqual(oParser.calculate().getValue(), 0.3333333333333333, 'Test: Bounded case: Number(5). Smallest positive number for sample_s (truncates to 0). 5 of 5 arguments used.');
assert.strictEqual(oParser.calculate().getValue(), 0.33333333333333337, 'Test: Bounded case: Number(5). Smallest positive number for sample_s (truncates to 0). 5 of 5 arguments used.');
// Need to fix:
// Case #4: String(5). All arguments as strings convertible to valid numbers/boolean. 5 of 5 arguments used.
// Case #15: Date(4),Boolean. Date arguments truncated to integers. 5 of 5 arguments used.
// Case #5: Number(5). sample_s > number_sample returns #NUM!. 5 of 5 arguments used.
// Case #6: Number(5). sample_s > population_s returns #NUM!. 5 of 5 arguments used.
// Case #9: Number(5). sample_s < (number_sample - number_pop + population_s) returns #NUM!. 5 of 5 arguments used.
// Case #12: Number,Empty,Number(3). number_sample empty returns #VALUE!. 5 of 5 arguments used.
// Case #13: Number(2),Empty,Number(2). population_s empty returns #VALUE!. 5 of 5 arguments used.
// Case #17: Area,Number(4). sample_s as multi-cell range returns #NUM!. 5 of 5 arguments used.
// Case #1: Number(5). Minimum valid values for sample_s, number_sample, population_s, number_pop. 5 of 5 arguments used.
// Case #2: Number(5). Maximum valid Excel numbers (truncated to integers). 5 of 5 arguments used. - critical
testArrayFormula2(assert, "HYPGEOM.DIST", 5, 5);
@ -34192,7 +34166,7 @@ $(function () {
assert.strictEqual(oParser.calculate().getValue(), '#DIV/0!', 'Test: Negative case: String. Empty string in array returns #VALUE!.');
// Case #17: Formula. Nested IF returning text causes #DIV/0!.
oParser = new parserFormula('SKEW.P(IF(FALSE,1,"text"),2,3)', 'A2', ws);
assert.ok(oParser.parse(), 'Test: SKEW.P(IF(FALSE,1,"text"),2,3) is parsed.');debugger
assert.ok(oParser.parse(), 'Test: SKEW.P(IF(FALSE,1,"text"),2,3) is parsed.');
assert.strictEqual(oParser.calculate().getValue(), '#DIV/0!', 'Test: Negative case: Formula. Nested IF returning text causes #DIV/0!.');
// Case #18: Reference link. Reference to error value returns #N/A.
oParser = new parserFormula('SKEW.P(A109)', 'A2', ws);