@enigmaoffline/node-exp-solver
Version:
Mathematical expression solver / Reverse Polish Notation calculator for NodeJS
135 lines • 5.33 kB
JavaScript
;
var __spreadArray = (this && this.__spreadArray) || function (to, from) {
for (var i = 0, il = from.length, j = to.length; i < il; i++, j++)
to[j] = from[i];
return to;
};
var aux_1 = require("./utils/aux");
var Solver = /** @class */ (function () {
function Solver() {
}
/**
* Tokenize an infix-notated expression string
* @param {string} exp - mathematical expression
* @returns {Array<string>} - tokenized expression
*/
Solver.tokenize = function (exp) {
var res = [];
var term = '';
exp
.replace(/ /g, '')
.split('')
.forEach(function (ch, index) {
switch (true) {
// negative numbers
case ch === '-' && index === 0:
case ch === '-' && term === '' && aux_1.Aux.isOP(res[res.length - 1]):
case ch === '-' && term === '' && res[res.length - 1] === '(':
term = '-';
break;
// operands
case aux_1.Aux.isOP(ch):
case aux_1.Aux.isPA(ch):
if (term !== '')
res.push(term);
res.push(ch);
term = '';
break;
// numbers
default:
term += ch;
}
});
// push remaining term to result
if (term !== '')
res.push(term);
return res;
};
/**
* Converts an infix-notated expression to reverse polish notation
* @param {Array<string>} exp - tokenized infix-notated expression
* @returns {Array<string>} - converted RPN expression
*/
Solver.toRPN = function (exp) {
var outStack = [];
var opStack = [];
while (exp.length > 0) {
var head = exp.splice(0, 1)[0];
switch (true) {
// handle parentheses
case aux_1.Aux.isPA(head):
if (head === '(')
opStack.push(head);
else {
while (opStack[opStack.length - 1] !== '(')
outStack.push(opStack.pop() || '');
opStack.pop();
}
break;
// handle operand
case aux_1.Aux.isOP(head):
while (opStack.length > 0 && (aux_1.Aux.precMap[opStack[opStack.length - 1]] > aux_1.Aux.precMap[head] ||
(aux_1.Aux.precMap[opStack[opStack.length - 1]] === aux_1.Aux.precMap[head] &&
aux_1.Aux.assoMap[head] === 0)))
outStack.push(opStack.pop() || '');
opStack.push(head);
break;
// handle number
default:
outStack.push(head);
}
}
// push remaining
while (opStack.length > 0)
outStack.push(opStack.pop() || '');
return outStack;
};
/**
* Evaluates an infix-notated expression
* @param {Array<string>} exp - tokenzied infix-notated expression
* @returns - evaluated value
*/
Solver.solve = function (exp) { return Solver.solveRec(Solver.toRPN(exp)); };
/**
* Evaluates a reverse polish notated expression
* @param {Array<string>} rpn - tokenized rpn expression
* @returns {number} - evaluated value
*/
Solver.solveRPN = function (rpn) { return Solver.solveRec(rpn); };
// private methods
/**
* Recursively solve an RPN expression
* @param {Array<string>} rpn - original RPN expression
* @param {Array<number>} stack - memory stack used for recursive computation
* @returns {number} - evaluated value
*/
Solver.solveRec = function (rpn, stack) {
if (stack === void 0) { stack = []; }
if (rpn.length === 0)
return stack[0];
else {
var head = rpn.splice(0, 1)[0];
if (aux_1.Aux.isOP(head)) {
var num1 = stack.splice(stack.length - 1, 1)[0];
var num2 = stack.splice(stack.length - 1, 1)[0];
// recursive calculation
switch (head) {
case '+':
return Solver.solveRec(rpn, __spreadArray(__spreadArray([], stack), [num2 + num1]));
case '-':
return Solver.solveRec(rpn, __spreadArray(__spreadArray([], stack), [num2 - num1]));
case '*':
return Solver.solveRec(rpn, __spreadArray(__spreadArray([], stack), [num2 * num1]));
case '/':
return Solver.solveRec(rpn, __spreadArray(__spreadArray([], stack), [num2 / num1]));
case '^':
return Solver.solveRec(rpn, __spreadArray(__spreadArray([], stack), [Math.pow(num2, num1)]));
}
}
return Solver.solveRec(rpn, __spreadArray(__spreadArray([], stack), [parseFloat(head)]));
}
};
return Solver;
}());
module.exports = Solver;
//# sourceMappingURL=index.js.map