Skip to content

Commit

Permalink
[se] Fix bug 55084. Enhancement for POW function (#3664)
Browse files Browse the repository at this point in the history
* [se] Fix bug 55084. Enhancement for POW function
  • Loading branch information
DimitryOrlov authored Aug 28, 2023
1 parent c97d5bd commit 178b87f
Show file tree
Hide file tree
Showing 3 changed files with 197 additions and 41 deletions.
38 changes: 22 additions & 16 deletions cell/model/FormulaObjects/mathematicFunctions.js
Original file line number Diff line number Diff line change
Expand Up @@ -3306,42 +3306,49 @@
cPOWER.prototype.Calculate = function (arg) {

function powerHelper(a, b) {
if (a == 0 && b < 0) {
if (a === 0 && b < 0) {
return new cError(cErrorType.division_by_zero);
}
if (a == 0 && b == 0) {
return new cError(cErrorType.not_numeric);
}

return new cNumber(Math.pow(a, b));
if (a >= 0 || Math.round(b) === b) {
return new cNumber(Math.pow(a, b));
} else {
let r = -1 * Math.pow(-a, b);
if (Math.round(Math.pow(r, 1 / b)) === Math.round(a)) {
return new cNumber(r);
} else {
return new cError(cErrorType.not_numeric);
}
}
}

function f(a, b, r, c) {
if (a instanceof cNumber && b instanceof cNumber) {
if (cElementType.number === a.type && cElementType.number === b.type) {
this.array[r][c] = powerHelper(a.getValue(), b.getValue());
} else {
this.array[r][c] = new cError(cErrorType.wrong_value_type);
}
}

var arg0 = arg[0], arg1 = arg[1];
if (arg0 instanceof cArea || arg1 instanceof cArea3D) {
let arg0 = arg[0], arg1 = arg[1];
if (cElementType.cellsRange === arg0.type || cElementType.cellsRange3D === arg0.type) {
arg0 = arg0.cross(arguments[1]);
}
if (arg1 instanceof cArea || arg1 instanceof cArea3D) {
if (cElementType.cellsRange === arg1.type || cElementType.cellsRange3D === arg1.type) {
arg1 = arg1.cross(arguments[1]);
}

arg0 = arg0.tocNumber();
arg1 = arg1.tocNumber();

if (arg0 instanceof cError) {
if (cElementType.error === arg0.type) {
return arg0;
}
if (arg1 instanceof cError) {
if (cElementType.error === arg1.type) {
return arg1;
}

if (arg0 instanceof cArray && arg1 instanceof cArray) {
if (cElementType.array === arg0.type && cElementType.array === arg1.type) {
if (arg0.getCountElement() != arg1.getCountElement() || arg0.getRowCount() != arg1.getRowCount()) {
return new cError(cErrorType.not_available);
} else {
Expand All @@ -3350,24 +3357,23 @@
});
return arg0;
}
} else if (arg0 instanceof cArray) {
} else if (cElementType.array === arg0.type) {
arg0.foreach(function (elem, r, c) {
f.call(this, elem, arg1, r, c)
});
return arg0;
} else if (arg1 instanceof cArray) {
} else if (cElementType.array === arg1.type) {
arg1.foreach(function (elem, r, c) {
f.call(this, arg0, elem, r, c);
});
return arg1;
}

if (!(arg0 instanceof cNumber) || ( arg1 && !(arg0 instanceof cNumber) )) {
if (!(cElementType.number === arg0.type) || (arg1 && !(cElementType.number === arg0.type))) {
return new cError(cErrorType.wrong_value_type);
}

return powerHelper(arg0.getValue(), arg1.getValue());

};

/**
Expand Down
30 changes: 5 additions & 25 deletions cell/model/FormulaObjects/parserFormula.js
Original file line number Diff line number Diff line change
Expand Up @@ -3981,33 +3981,13 @@ parserHelp.setDigitSeparator(AscCommon.g_oDefaultCultureInfo.NumberDecimalSepara
cPowOperator.prototype.priority = 40;
cPowOperator.prototype.argumentsCurrent = 2;
cPowOperator.prototype.Calculate = function (arg) {
var arg0 = arg[0], arg1 = arg[1];
if (arg0 instanceof cArea) {
arg0 = arg0.cross(arguments[1]);
} else if (arg0 instanceof cArea3D) {
arg0 = arg0.cross(arguments[1], arguments[3]);
}
arg0 = arg0.tocNumber();
if (arg1 instanceof cArea) {
arg1 = arg1.cross(arguments[1]);
} else if (arg1 instanceof cArea3D) {
arg1 = arg1.cross(arguments[1], arguments[3]);
}
arg1 = arg1.tocNumber();
if (arg0 instanceof cError) {
return arg0;
}
if (arg1 instanceof cError) {
return arg1;
}
let res = AscCommonExcel.cFormulaFunction.POWER.prototype.Calculate(arg);

var _v = Math.pow(arg0.getValue(), arg1.getValue());
if (isNaN(_v)) {
return new cError(cErrorType.not_numeric);
} else if (_v === Number.POSITIVE_INFINITY) {
return new cError(cErrorType.division_by_zero);
if (res) {
return res;
}
return new cNumber(_v);

return new cError(cErrorType.wrong_value_type);
};

/**
Expand Down
170 changes: 170 additions & 0 deletions tests/cell/spreadsheet-calculation/FormulaTests.js
Original file line number Diff line number Diff line change
Expand Up @@ -779,6 +779,82 @@ $(function () {
assert.ok(oParser.parse());
assert.strictEqual(oParser.calculate().getValue(), Math.pow(2, 52));

oParser = new parserFormula("(0)^(0)", "A1", ws);
assert.ok(oParser.parse(), "(0)^(0)");
assert.strictEqual(oParser.calculate().getValue(), 1, "Result of (0)^(0)"); // ms - #NUM!, js - 1, LO - 1, gs - 1

oParser = new parserFormula("(0)^(1)", "A1", ws);
assert.ok(oParser.parse(), "(0)^(1)");
assert.strictEqual(oParser.calculate().getValue(), 0, "Result of (0)^(1)");

oParser = new parserFormula("(0)^(-1)", "A1", ws);
assert.ok(oParser.parse(), "(0)^(-1)");
assert.strictEqual(oParser.calculate().getValue(), "#DIV/0!", "Result of (0)^(-1)");

oParser = new parserFormula("(0)^(1/3)", "A1", ws);
assert.ok(oParser.parse(), "(0)^(1/3)");
assert.strictEqual(oParser.calculate().getValue(), 0, "Result of (0)^(1/3)");

oParser = new parserFormula("(0)^(-1/3)", "A1", ws);
assert.ok(oParser.parse(), "(0)^(-1/3)");
assert.strictEqual(oParser.calculate().getValue(), "#DIV/0!", "Result of (0)^(-1/3)");

oParser = new parserFormula("(0)^(-3)", "A1", ws);
assert.ok(oParser.parse(), "(0)^(-3)");
assert.strictEqual(oParser.calculate().getValue(), "#DIV/0!", "Result of (0)^(-3)");

oParser = new parserFormula("(1)^(-3)", "A1", ws);
assert.ok(oParser.parse(), "(1)^(-3)");
assert.strictEqual(oParser.calculate().getValue(), 1, "Result of (1)^(-3)");

oParser = new parserFormula("(1)^(-1/3)", "A1", ws);
assert.ok(oParser.parse(), "(1)^(-1/3)");
assert.strictEqual(oParser.calculate().getValue(), 1, "Result of (1)^(-1/3)");

oParser = new parserFormula("(1)^(1/3)", "A1", ws);
assert.ok(oParser.parse(), "(1)^(1/3)");
assert.strictEqual(oParser.calculate().getValue(), 1, "Result of (1)^(1/3)");

oParser = new parserFormula("(-1)^(1/2)", "A1", ws);
assert.ok(oParser.parse(), "(-1)^(1/2)");
assert.strictEqual(oParser.calculate().getValue(), "#NUM!", "Result of (-1)^(1/2)");

oParser = new parserFormula("(-1)^(1/3)", "A1", ws);
assert.ok(oParser.parse(), "(-1)^(1/3)");
assert.strictEqual(oParser.calculate().getValue(), -1, "Result of (-1)^(1/3)");

oParser = new parserFormula("(-1)^(-1/3)", "A1", ws);
assert.ok(oParser.parse(), "(-1)^(-1/3)");
assert.strictEqual(oParser.calculate().getValue(), -1, "Result of (-1)^(-1/3)");

oParser = new parserFormula("(-1)^(1/4)", "A1", ws);
assert.ok(oParser.parse(), "(-1)^(1/4)");
assert.strictEqual(oParser.calculate().getValue(), "#NUM!", "Result of (-1)^(1/4)");

oParser = new parserFormula("(-1)^(1/5)", "A1", ws);
assert.ok(oParser.parse(), "(-1)^(1/5)");
assert.strictEqual(oParser.calculate().getValue(), -1, "Result of (-1)^(1/5)");

oParser = new parserFormula("(-8)^(1/3)", "A1", ws);
assert.ok(oParser.parse(), "(-8)^(1/3)");
assert.strictEqual(oParser.calculate().getValue(), -2, "Result of (-8)^(1/3)");

oParser = new parserFormula("(-8)^(-1/3)", "A1", ws);
assert.ok(oParser.parse(), "(-8)^(-1/3)");
assert.strictEqual(oParser.calculate().getValue(), -0.5, "Result of (-8)^(-1/3)");

oParser = new parserFormula("(-8)^(1/4)", "A1", ws);
assert.ok(oParser.parse(), "(-8)^(1/4)");
assert.strictEqual(oParser.calculate().getValue(), "#NUM!", "Result of (-8)^(1/4)");

oParser = new parserFormula("(-8)^(1/5)", "A1", ws);
assert.ok(oParser.parse(), "(-8)^(1/5)");
assert.strictEqual(oParser.calculate().getValue().toFixed(2), "-1.52", "Result of (-8)^(1/5)");

oParser = new parserFormula("(-8)^(-1/5)", "A1", ws);
assert.ok(oParser.parse(), "(-8)^(-1/5)");
assert.strictEqual(oParser.calculate().getValue().toFixed(2), "-0.66", "Result of (-8)^(-1/5)");

oParser = new parserFormula('-10', "A1", ws);
assert.ok(oParser.parse());
assert.strictEqual(oParser.calculate().getValue(), -10);
Expand Down Expand Up @@ -3182,6 +3258,100 @@ $(function () {

});

QUnit.test("Test: \"POWER\"", function (assert) {
oParser = new parserFormula("POWER(0,0)", "A1", ws);
assert.ok(oParser.parse(), "POWER(0,0)");
assert.strictEqual(oParser.calculate().getValue(), 1, "Result of POWER(0,0)"); // ms - #NUM!, js - 1, LO - 1, gs - 1

oParser = new parserFormula("POWER(0,1)", "A1", ws);
assert.ok(oParser.parse(), "POWER(0,1)");
assert.strictEqual(oParser.calculate().getValue(), 0, "Result of POWER(0,1)");

oParser = new parserFormula("POWER(0,-1)", "A1", ws);
assert.ok(oParser.parse(), "POWER(0,-1)");
assert.strictEqual(oParser.calculate().getValue(), "#DIV/0!", "Result of POWER(0,-1)");

oParser = new parserFormula("POWER(0,1/3)", "A1", ws);
assert.ok(oParser.parse(), "POWER(0,1/3)");
assert.strictEqual(oParser.calculate().getValue(), 0, "Result of POWER(0,1/3)");

oParser = new parserFormula("POWER(0,-1/3)", "A1", ws);
assert.ok(oParser.parse(), "POWER(0,-1/3)");
assert.strictEqual(oParser.calculate().getValue(), "#DIV/0!", "Result of POWER(0,-1/3)");

oParser = new parserFormula("POWER(0,-3)", "A1", ws);
assert.ok(oParser.parse(), "POWER(0,-3)");
assert.strictEqual(oParser.calculate().getValue(), "#DIV/0!", "Result of POWER(0,-3)");

oParser = new parserFormula("POWER(1,-3)", "A1", ws);
assert.ok(oParser.parse(), "POWER(1,-3)");
assert.strictEqual(oParser.calculate().getValue(), 1, "Result of POWER(1,-3)");

oParser = new parserFormula("POWER(1,-1/3)", "A1", ws);
assert.ok(oParser.parse(), "POWER(1,-1/3)");
assert.strictEqual(oParser.calculate().getValue(), 1, "Result of POWER(1,-1/3)");

oParser = new parserFormula("POWER(1,1/3)", "A1", ws);
assert.ok(oParser.parse(), "POWER(1,1/3)");
assert.strictEqual(oParser.calculate().getValue(), 1, "Result of POWER(1,1/3)");

oParser = new parserFormula("POWER(-1,1/2)", "A1", ws);
assert.ok(oParser.parse(), "POWER(-1,1/2)");
assert.strictEqual(oParser.calculate().getValue(), "#NUM!", "Result of POWER(-1,1/2)");

oParser = new parserFormula("POWER(-1,1/3)", "A1", ws);
assert.ok(oParser.parse(), "POWER(-1,1/3)");
assert.strictEqual(oParser.calculate().getValue(), -1, "Result of POWER(-1,1/3)");

oParser = new parserFormula("POWER(-1,-1/3)", "A1", ws);
assert.ok(oParser.parse(), "POWER(-1,-1/3)");
assert.strictEqual(oParser.calculate().getValue(), -1, "Result of POWER(-1,-1/3)");

oParser = new parserFormula("POWER(-1,1/4)", "A1", ws);
assert.ok(oParser.parse(), "POWER(-1,1/4)");
assert.strictEqual(oParser.calculate().getValue(), "#NUM!", "Result of POWER(-1,1/4)");

oParser = new parserFormula("POWER(-1,1/5)", "A1", ws);
assert.ok(oParser.parse(), "POWER(-1,1/5)");
assert.strictEqual(oParser.calculate().getValue(), -1, "Result of POWER(-1,1/5)");

oParser = new parserFormula("POWER(-8,1/3)", "A1", ws);
assert.ok(oParser.parse(), "POWER(-8,1/3)");
assert.strictEqual(oParser.calculate().getValue(), -2, "Result of POWER(-8,1/3)");

oParser = new parserFormula("POWER(-8,-1/3)", "A1", ws);
assert.ok(oParser.parse(), "POWER(-8,-1/3)");
assert.strictEqual(oParser.calculate().getValue(), -0.5, "Result of POWER(-8,-1/3)");

oParser = new parserFormula("POWER(-8,1/4)", "A1", ws);
assert.ok(oParser.parse(), "POWER(-8,1/4)");
assert.strictEqual(oParser.calculate().getValue(), "#NUM!", "Result of POWER(-8,1/4)");

oParser = new parserFormula("POWER(-8,1/5)", "A1", ws);
assert.ok(oParser.parse(), "POWER(-8,1/5)");
assert.strictEqual(oParser.calculate().getValue().toFixed(2), "-1.52", "Result of POWER(-8,1/5)");

oParser = new parserFormula("POWER(-8,-1/5)", "A1", ws);
assert.ok(oParser.parse(), "POWER(-8,-1/5)");
assert.strictEqual(oParser.calculate().getValue().toFixed(2), "-0.66", "Result of POWER(-8,-1/5)");

oParser = new parserFormula('POWER("8",2)', "A1", ws);
assert.ok(oParser.parse(), 'POWER("8",2)');
assert.strictEqual(oParser.calculate().getValue(), 64, 'Result of POWER("8",2)');

oParser = new parserFormula('POWER("8","2")', "A1", ws);
assert.ok(oParser.parse(), 'POWER("8","2")');
assert.strictEqual(oParser.calculate().getValue(), 64, 'Result of POWER("8","2")');

oParser = new parserFormula('POWER("-8","2")', "A1", ws);
assert.ok(oParser.parse(), 'POWER("-8","2")');
assert.strictEqual(oParser.calculate().getValue(), 64, 'Result of POWER("-8","2")');

oParser = new parserFormula('POWER("8s",2)', "A1", ws);
assert.ok(oParser.parse(), 'POWER("8s",2)');
assert.strictEqual(oParser.calculate().getValue(), "#VALUE!", 'Result of POWER("8s",2)');
});

QUnit.test("Test: \"POWER(2,8)\"", function (assert) {
oParser = new parserFormula("POWER(2,8)", "A1", ws);
assert.ok(oParser.parse());
Expand Down

0 comments on commit 178b87f

Please sign in to comment.