UNPKG

@enigmaoffline/node-exp-solver

Version:

Mathematical expression solver / Reverse Polish Notation calculator for NodeJS

135 lines 5.33 kB
"use strict"; 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