Initial commit

This commit is contained in:
Developer
2025-04-21 16:03:20 +02:00
commit 2832896157
22874 changed files with 3092801 additions and 0 deletions

View File

@@ -0,0 +1,7 @@
{
"extends": "standard",
"plugins": [
"standard",
"promise"
]
}

View File

@@ -0,0 +1,5 @@
FROM node:12.14-alpine3.11
WORKDIR /home/math-expression-evaluator
COPY . .
RUN npm i

View File

@@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2015 Ankit G.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,85 @@
# math-expression-evaluator
An extremely efficient, flexible and amazing evaluator for Math expression in Javascript.([Documentation](http://bugwheels94.github.io/math-expression-evaluator/))
## Use cases
|Input|Result|Explanation|
|:---:|:---:| --- |
|**2+3-1**|4| Addition and Subtraction operator |
|**2\*5/10**|1| Multiplication and Division operator |
|**tan45** *or* **tan(45)**|1| Trigonometric Function ( tan in Degree mode) |
|**tan45** *or* **tan(45)**|1.619775190543862| Trigonometric Function ( tan in Radian mode) |
|**Pi1,15,n** *or* **Pi(1,15,n)**|1307674368000| Product of Sequence |
|**Sigma1,15,n** *or* **Sigma(1,15,n)**|120| Sum of Sequence( also called summation) |
|**2^3**|8| Exponent( note this operator is left associative like MS Office) |
|**5P3**|60| Permutaion Method to calculate all the permutaions |
|**sincostan90** *or* **sin(cos(tan(90)))**|0.017261434031253| Multiple functions with or without parenthesis (both works) |
### [Fiddle Yourself](https://jsbin.com/romatuc/edit?html,output)
## Installation
### Node JS
**Using npm**
npm install math-expression-evaluator
### Browser
**Using bower**
bower install math-expression-evaluator
### How to run test
npm test
## Supported symbols
|Symbol|Explanation|
|:---:|:---:|
|**+**| Addition Operator eg. 2+3 results 5 |
|**-**| Subtraction Operator eg. 2-3 results -1 |
|**/**| Division operator eg 3/2 results 1.5 |
|**\***| Multiplication Operator eg. 2\*3 results 6 |
|**Mod**| Modulus Operator eg. 3 Mod 2 results 1 |
|**(**| Opening Parenthesis |
|**)**| Closing Parenthesis |
|**Sigma**| Summation eg. Sigma(1,100,n) results 5050 |
|**Pi**| Product eg. Pi(1,10,n) results 3628800 |
|**n**| Variable for Summation or Product |
|**pi**| Math constant pi returns 3.14 |
|**e**| Math constant e returns 2.71 |
|**C**| Combination operator eg. 4C2 returns 6 |
|**P**| Permutation operator eg. 4P2 returns 12 |
|**!**| factorial operator eg. 4! returns 24 |
|**log**| logarithmic function with base 10 eg. log 1000 returns 3 |
|**ln**| natural log function with base e eg. ln 2 returns .3010 |
|**pow**| power function with two operator pow(2,3) returns 8 |
|**^**| power operator eg. 2^3 returns 8 |
|**root**| underroot function root 4 returns 2 |
|**sin**| Sine function |
|**cos**| Cosine function |
|**tan**| Tangent function |
|**asin**| Inverse Sine function |
|**acos**| Inverse Cosine function |
|**atan**| Inverse Tangent function |
|**sinh**| Hyperbolic Sine function |
|**cosh**| Hyperbolic Cosine function |
|**tanh**| Hyperbolic Tangent function |
|**asinh**| Inverse Hyperbolic Sine function |
|**acosh**| Inverse Hyperbolic Cosine function |
|**atanh**| Inverse Hyperbolic Tangent function |
## Features
### Amazing support for Sigma and Pi
This is a fantastic feature of this calculator that it is capable of evaluating expressions containing **Sigma and Pi**.
Passing `Sigma(1,100,n)` will evaluate to 5050 as n is summationed from 1 to 100.
and Pi(1,15,n) will evaluate to 1307674368000 as n is multiplied from 1 to 15 which is equal to 15!
### Parenthesis less expression
If a expression is readable by human then it is readable by this evaluator. There is no need to wrap every function inside parenthesis.
For eg. sin90 will work totally fine instead of sin(90)
##Changelog
### Removed lodash.indexof and used native Array.prototype.indexOf hence dropping suppports for IE8 and below.
This will reflect in next release named v1.2.16

View File

@@ -0,0 +1,754 @@
/** math-expression-evaluator version 1.3.7
Dated:2020-12-20 */
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.mexp = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
var Mexp=require('./postfix_evaluator.js');
Mexp.prototype.formulaEval = function () {
"use strict";
var stack=[],pop1,pop2,pop3;
var disp=[];
var temp='';
var arr=this.value;
for(var i=0;i<arr.length;i++){
if(arr[i].type===1||arr[i].type===3){
disp.push({value:arr[i].type===3?arr[i].show:arr[i].value,type:1});
}
else if(arr[i].type===13){
disp.push({value:arr[i].show,type:1});
}
else if(arr[i].type===0){
disp[disp.length-1]={value:arr[i].show+(arr[i].show!="-"?"(":"")+disp[disp.length-1].value+(arr[i].show!="-"?")":""),type:0};
}
else if(arr[i].type===7){
disp[disp.length-1]={value:(disp[disp.length-1].type!=1?"(":"")+disp[disp.length-1].value+(disp[disp.length-1].type!=1?")":"")+arr[i].show,type:7};
}
else if(arr[i].type===10){
pop1=disp.pop();
pop2=disp.pop();
if(arr[i].show==='P'||arr[i].show==='C')disp.push({value:"<sup>"+pop2.value+"</sup>"+arr[i].show+"<sub>"+pop1.value+"</sub>",type:10});
else disp.push({value:(pop2.type!=1?"(":"")+pop2.value+(pop2.type!=1?")":"")+"<sup>"+pop1.value+"</sup>",type:1});
}
else if(arr[i].type===2||arr[i].type===9){
pop1=disp.pop();
pop2=disp.pop();
disp.push({value:(pop2.type!=1?"(":"")+pop2.value+(pop2.type!=1?")":"")+arr[i].show+(pop1.type!=1?"(":"")+pop1.value+(pop1.type!=1?")":""),type:arr[i].type});
}
else if(arr[i].type===12){
pop1=disp.pop();
pop2=disp.pop();
pop3=disp.pop();
disp.push({value:arr[i].show+"("+pop3.value+","+pop2.value+","+pop1.value+")",type:12});
}
}
return disp[0].value;
};
module.exports=Mexp;
},{"./postfix_evaluator.js":5}],2:[function(require,module,exports){
"use strict";
var Mexp = require('./math_function.js')
function inc(arr, val) {
for (var i = 0; i < arr.length; i++) {
arr[i] += val
}
return arr
}
var token = ['sin', 'cos', 'tan', 'pi', '(', ')', 'P', 'C', ' ',
'asin', 'acos', 'atan', '7', '8', '9', 'int',
'cosh', 'acosh', 'ln', '^', 'root', '4', '5', '6', '/', '!',
'tanh', 'atanh', 'Mod', '1', '2', '3', '*',
'sinh', 'asinh', 'e', 'log', '0', '.', '+', '-', ',', 'Sigma', 'n', 'Pi', 'pow']
var show = ['sin', 'cos', 'tan', '&pi;', '(', ')', 'P', 'C', ' ',
'asin', 'acos', 'atan', '7', '8', '9', 'Int',
'cosh', 'acosh', ' ln', '^', 'root', '4', '5', '6', '&divide;', '!',
'tanh', 'atanh', ' Mod ', '1', '2', '3', '&times;',
'sinh', 'asinh', 'e', ' log', '0', '.', '+', '-', ',', '&Sigma;', 'n', '&Pi;', 'pow']
var eva = [Mexp.math.sin, Mexp.math.cos, Mexp.math.tan, 'PI', '(', ')', Mexp.math.P, Mexp.math.C, ' '.anchor,
Mexp.math.asin, Mexp.math.acos, Mexp.math.atan, '7', '8', '9', Math.floor,
Mexp.math.cosh, Mexp.math.acosh, Math.log, Math.pow, Math.sqrt, '4', '5', '6', Mexp.math.div, Mexp.math.fact,
Mexp.math.tanh, Mexp.math.atanh, Mexp.math.mod, '1', '2', '3', Mexp.math.mul,
Mexp.math.sinh, Mexp.math.asinh, 'E', Mexp.math.log, '0', '.', Mexp.math.add, Mexp.math.sub, ',', Mexp.math.sigma, 'n', Mexp.math.Pi, Math.pow]
var preced = {
0: 11,
1: 0,
2: 3,
3: 0,
4: 0,
5: 0,
6: 0,
7: 11,
8: 11,
9: 1,
10: 10,
11: 0,
12: 11,
13: 0,
14: -1 // will be filtered after lexer
} // stores precedence by types
var type = [0, 0, 0, 3, 4, 5, 10, 10, 14,
0, 0, 0, 1, 1, 1, 0,
0, 0, 0, 10, 0, 1, 1, 1, 2, 7,
0, 0, 2, 1, 1, 1, 2,
0, 0, 3, 0, 1, 6, 9, 9, 11, 12, 13, 12, 8]
/*
0 : function with syntax function_name(Maths_exp)
1 : numbers
2 : binary operators like * / Mod left associate and same precedence
3 : Math constant values like e,pi,Cruncher ans
4 : opening bracket
5 : closing bracket
6 : decimal
7 : function with syntax (Math_exp)function_name
8: function with syntax function_name(Math_exp1,Math_exp2)
9 : binary operator like +,-
10: binary operator like P C or ^
11: ,
12: function with , seperated three parameters and third parameter is a string that will be mexp string
13: variable of Sigma function
*/
var type0 = {
0: true,
1: true,
3: true,
4: true,
6: true,
8: true,
9: true,
12: true,
13: true,
14: true
} // type2:true,type4:true,type9:true,type11:true,type21:true,type22
var type1 = {
0: true,
1: true,
2: true,
3: true,
4: true,
5: true,
6: true,
7: true,
8: true,
9: true,
10: true,
11: true,
12: true,
13: true
} // type3:true,type5:true,type7:true,type23
var type1Asterick = {
0: true,
3: true,
4: true,
8: true,
12: true,
13: true
}
var empty = {}
var type3Asterick = {
0: true,
1: true,
3: true,
4: true,
6: true,
8: true,
12: true,
13: true
} // type_5:true,type_7:true,type_23
var type6 = {
1: true
}
var newAr = [
[],
['1', '2', '3', '7', '8', '9', '4', '5', '6', '+', '-', '*', '/', '(', ')', '^', '!', 'P', 'C', 'e', '0', '.', ',', 'n', ' '],
['pi', 'ln', 'Pi'],
['sin', 'cos', 'tan', 'Del', 'int', 'Mod', 'log', 'pow'],
['asin', 'acos', 'atan', 'cosh', 'root', 'tanh', 'sinh'],
['acosh', 'atanh', 'asinh', 'Sigma']
]
function match(str1, str2, i, x) {
for (var f = 0; f < x; f++) {
if (str1[i + f] !== str2[f]) {
return false
}
}
return true
}
Mexp.addToken = function (tokens) {
for (var i = 0; i < tokens.length; i++) {
var x = tokens[i].token.length
var temp = -1
// newAr is a specially designed data structure index of 1d array = length of tokens
newAr[x] = newAr[x] || [];
for (var y = 0; y < newAr[x].length; y++) {
if (tokens[i].token === newAr[x][y]) {
temp = token.indexOf(newAr[x][y])
break
}
}
if (temp === -1) {
token.push(tokens[i].token)
type.push(tokens[i].type)
if (newAr.length <= tokens[i].token.length) {
newAr[tokens[i].token.length] = []
}
newAr[tokens[i].token.length].push(tokens[i].token)
eva.push(tokens[i].value)
show.push(tokens[i].show)
} else { // overwrite
token[temp] = tokens[i].token
type[temp] = tokens[i].type
eva[temp] = tokens[i].value
show[temp] = tokens[i].show
}
}
}
function tokenize(string) {
var nodes = [];
var length = string.length;
var key, x, y;
for (var i = 0; i < length; i++) {
if (i < length - 1 && string[i] === ' ' && string[i + 1] === ' ') {
continue
}
key = ''
for (x = (string.length - i > (newAr.length - 2) ? newAr.length - 1 : string.length - i); x > 0; x--) {
if (newAr[x] === undefined) continue;
for (y = 0; y < newAr[x].length; y++) {
if (match(string, newAr[x][y], i, x)) {
key = newAr[x][y]
y = newAr[x].length
x = 0
}
}
}
i += key.length - 1
if (key === '') {
throw (new Mexp.Exception('Can\'t understand after ' + string.slice(i)))
}
var index = token.indexOf(key);
nodes.push({
index: index,
token: key,
type: type[index],
eval: eva[index],
precedence: preced[type[index]],
show: show[index]
})
}
return nodes;
}
Mexp.lex = function (inp, tokens) {
'use strict'
var changeSignObj = {
value: Mexp.math.changeSign,
type: 0,
pre: 21,
show: '-'
}
var closingParObj = {
value: ')',
show: ')',
type: 5,
pre: 0
}
var openingParObj = {
value: '(',
type: 4,
pre: 0,
show: '('
}
var str = [openingParObj]
var ptc = [] // Parenthesis to close at the beginning is after one token
var inpStr = inp
var allowed = type0
var bracToClose = 0
var asterick = empty
var prevKey = ''
var i;
if (typeof tokens !== 'undefined') {
Mexp.addToken(tokens)
}
var obj = {}
var nodes = tokenize(inpStr);
for (i = 0; i < nodes.length; i++) {
var node = nodes[i];
if (node.type === 14) {
if (i > 0 &&
i < nodes.length - 1 &&
nodes[i + 1].type === 1 &&
(nodes[i - 1].type === 1 || nodes[i - 1].type === 6))
throw new Mexp.Exception('Unexpected Space')
continue
}
var index = node.index
var cToken = node.token
var cType = node.type
var cEv = node.eval
var cPre = node.precedence
var cShow = node.show
var pre = str[str.length - 1]
var j
for (j = ptc.length; j--;) { // loop over ptc
if (ptc[j] === 0) {
if ([0, 2, 3, 4, 5, 9, 11, 12, 13].indexOf(cType) !== -1) {
if (allowed[cType] !== true) {
console.log(inp, node, nodes, allowed)
throw (new Mexp.Exception(cToken + ' is not allowed after ' + prevKey))
}
str.push(closingParObj)
allowed = type1
asterick = type3Asterick
inc(ptc, -1).pop()
}
} else break
}
if (allowed[cType] !== true) {
throw (new Mexp.Exception(cToken + ' is not allowed after ' + prevKey))
}
if (asterick[cType] === true) {
cType = 2
cEv = Mexp.math.mul
cShow = '&times;'
cPre = 3
i = i - cToken.length
}
obj = {
value: cEv,
type: cType,
pre: cPre,
show: cShow
}
if (cType === 0) {
allowed = type0
asterick = empty
inc(ptc, 2).push(2)
str.push(obj)
str.push(openingParObj)
} else if (cType === 1) {
if (pre.type === 1) {
pre.value += cEv
inc(ptc, 1)
} else {
str.push(obj)
}
allowed = type1
asterick = type1Asterick
} else if (cType === 2) {
allowed = type0
asterick = empty
inc(ptc, 2)
str.push(obj)
} else if (cType === 3) { // constant
str.push(obj)
allowed = type1
asterick = type3Asterick
} else if (cType === 4) {
inc(ptc, 1)
bracToClose++
allowed = type0
asterick = empty
str.push(obj)
} else if (cType === 5) {
if (!bracToClose) {
throw (new Mexp.Exception('Closing parenthesis are more than opening one, wait What!!!'))
}
bracToClose--
allowed = type1
asterick = type3Asterick
str.push(obj)
inc(ptc, 1)
} else if (cType === 6) {
if (pre.hasDec) {
throw (new Mexp.Exception('Two decimals are not allowed in one number'))
}
if (pre.type !== 1) {
pre = {
value: 0,
type: 1,
pre: 0
} // pre needs to be changed as it will the last value now to be safe in later code
str.push(pre)
inc(ptc, -1)
}
allowed = type6
inc(ptc, 1)
asterick = empty
pre.value += cEv
pre.hasDec = true
} else if (cType === 7) {
allowed = type1
asterick = type3Asterick
inc(ptc, 1)
str.push(obj)
}
if (cType === 8) {
allowed = type0
asterick = empty
inc(ptc, 4).push(4)
str.push(obj)
str.push(openingParObj)
} else if (cType === 9) {
if (pre.type === 9) {
if (pre.value === Mexp.math.add) {
pre.value = cEv
pre.show = cShow
inc(ptc, 1)
} else if (pre.value === Mexp.math.sub && cShow === '-') {
pre.value = Mexp.math.add
pre.show = '+'
inc(ptc, 1)
}
} else if (pre.type !== 5 && pre.type !== 7 && pre.type !== 1 && pre.type !== 3 && pre.type !== 13) { // changesign only when negative is found
if (cToken === '-') { // do nothing for + token
// don't add with the above if statement as that will run the else statement of parent if on Ctoken +
allowed = type0
asterick = empty
inc(ptc, 2).push(2)
str.push(changeSignObj)
str.push(openingParObj)
}
} else {
str.push(obj)
inc(ptc, 2)
}
allowed = type0
asterick = empty
} else if (cType === 10) {
allowed = type0
asterick = empty
inc(ptc, 2)
str.push(obj)
} else if (cType === 11) {
allowed = type0
asterick = empty
str.push(obj)
} else if (cType === 12) {
allowed = type0
asterick = empty
inc(ptc, 6).push(6)
str.push(obj)
str.push(openingParObj)
} else if (cType === 13) {
allowed = type1
asterick = type3Asterick
str.push(obj)
}
inc(ptc, -1)
prevKey = cToken
}
for (j = ptc.length; j--;) { // loop over ptc
if (ptc[j] === 0) {
str.push(closingParObj)
inc(ptc, -1).pop()
} else break // if it is not zero so before ptc also cant be zero
}
if (allowed[5] !== true) {
throw (new Mexp.Exception('complete the expression'))
}
while (bracToClose--) {
str.push(closingParObj)
}
str.push(closingParObj)
// console.log(str);
return new Mexp(str)
}
module.exports = Mexp
},{"./math_function.js":3}],3:[function(require,module,exports){
"use strict";
var Mexp = function (parsed) {
this.value = parsed
}
Mexp.math = {
isDegree: true, // mode of calculator
acos: function (x) {
return (Mexp.math.isDegree ? 180 / Math.PI * Math.acos(x) : Math.acos(x))
},
add: function (a, b) {
return a + b
},
asin: function (x) {
return (Mexp.math.isDegree ? 180 / Math.PI * Math.asin(x) : Math.asin(x))
},
atan: function (x) {
return (Mexp.math.isDegree ? 180 / Math.PI * Math.atan(x) : Math.atan(x))
},
acosh: function (x) {
return Math.log(x + Math.sqrt(x * x - 1))
},
asinh: function (x) {
return Math.log(x + Math.sqrt(x * x + 1))
},
atanh: function (x) {
return Math.log((1 + x) / (1 - x))
},
C: function (n, r) {
var pro = 1
var other = n - r
var choice = r
if (choice < other) {
choice = other
other = r
}
for (var i = choice + 1; i <= n; i++) {
pro *= i
}
return pro / Mexp.math.fact(other)
},
changeSign: function (x) {
return -x
},
cos: function (x) {
if (Mexp.math.isDegree) x = Mexp.math.toRadian(x)
return Math.cos(x)
},
cosh: function (x) {
return (Math.pow(Math.E, x) + Math.pow(Math.E, -1 * x)) / 2
},
div: function (a, b) {
return a / b
},
fact: function (n) {
if (n % 1 !== 0) return 'NaN'
var pro = 1
for (var i = 2; i <= n; i++) {
pro *= i
}
return pro
},
inverse: function (x) {
return 1 / x
},
log: function (i) {
return Math.log(i) / Math.log(10)
},
mod: function (a, b) {
return a % b
},
mul: function (a, b) {
return a * b
},
P: function (n, r) {
var pro = 1
for (var i = Math.floor(n) - Math.floor(r) + 1; i <= Math.floor(n); i++) {
pro *= i
}
return pro
},
Pi: function (low, high, ex) {
var pro = 1
for (var i = low; i <= high; i++) {
pro *= Number(ex.postfixEval({
n: i
}))
}
return pro
},
pow10x: function (e) {
var x = 1
while (e--) {
x *= 10
}
return x
},
sigma: function (low, high, ex) {
var sum = 0
for (var i = low; i <= high; i++) {
sum += Number(ex.postfixEval({
n: i
}))
}
return sum
},
sin: function (x) {
if (Mexp.math.isDegree) x = Mexp.math.toRadian(x)
return Math.sin(x)
},
sinh: function (x) {
return (Math.pow(Math.E, x) - Math.pow(Math.E, -1 * x)) / 2
},
sub: function (a, b) {
return a - b
},
tan: function (x) {
if (Mexp.math.isDegree) x = Mexp.math.toRadian(x)
return Math.tan(x)
},
tanh: function (x) {
return Mexp.sinha(x) / Mexp.cosha(x)
},
toRadian: function (x) {
return x * Math.PI / 180
}
}
Mexp.Exception = function (message) {
this.message = message
}
module.exports = Mexp
},{}],4:[function(require,module,exports){
var Mexp = require('./lexer.js');
Mexp.prototype.toPostfix = function () {
'use strict';
var post = [], elem, popped, prep, pre, ele;
var stack = [{ value: "(", type: 4, pre: 0 }];
var arr = this.value;
for (var i = 1; i < arr.length; i++) {
if (arr[i].type === 1 || arr[i].type === 3 || arr[i].type === 13) { //if token is number,constant,or n(which is also a special constant in our case)
if (arr[i].type === 1)
arr[i].value = Number(arr[i].value);
post.push(arr[i]);
}
else if (arr[i].type === 4) {
stack.push(arr[i]);
}
else if (arr[i].type === 5) {
while ((popped = stack.pop()).type !== 4) {
post.push(popped);
}
}
else if (arr[i].type === 11) {
while ((popped = stack.pop()).type !== 4) {
post.push(popped);
}
stack.push(popped);
}
else {
elem = arr[i];
pre = elem.pre;
ele = stack[stack.length - 1];
prep = ele.pre;
var flag = ele.value == 'Math.pow' && elem.value == 'Math.pow';
if (pre > prep) stack.push(elem);
else {
while (prep >= pre && !flag || flag && pre < prep) {
popped = stack.pop();
ele = stack[stack.length - 1];
post.push(popped);
prep = ele.pre;
flag = elem.value == 'Math.pow' && ele.value == 'Math.pow';
}
stack.push(elem);
}
}
}
return new Mexp(post);
};
module.exports = Mexp;
},{"./lexer.js":2}],5:[function(require,module,exports){
var Mexp=require('./postfix.js');
Mexp.prototype.postfixEval = function (UserDefined) {
'use strict';
UserDefined=UserDefined||{};
UserDefined.PI=Math.PI;
UserDefined.E=Math.E;
var stack=[],pop1,pop2,pop3;
var disp=[];
var temp='';
var arr=this.value;
var bool=(typeof UserDefined.n!=="undefined");
for(var i=0;i<arr.length;i++){
if(arr[i].type===1){
stack.push({value:arr[i].value,type:1});
}
else if(arr[i].type===3){
stack.push({value:UserDefined[arr[i].value],type:1});
}
else if(arr[i].type===0){
if(typeof stack[stack.length-1].type==="undefined"){
stack[stack.length-1].value.push(arr[i]);
}
else stack[stack.length-1].value=arr[i].value(stack[stack.length-1].value);
}
else if(arr[i].type===7){
if(typeof stack[stack.length-1].type==="undefined"){
stack[stack.length-1].value.push(arr[i]);
}
else stack[stack.length-1].value=arr[i].value(stack[stack.length-1].value);
}
else if(arr[i].type===8){
pop1=stack.pop();
pop2=stack.pop();
stack.push({type:1,value:arr[i].value(pop2.value,pop1.value)});
}
else if(arr[i].type===10){
pop1=stack.pop();
pop2=stack.pop();
if(typeof pop2.type==="undefined"){
pop2.value=pop2.concat(pop1);
pop2.value.push(arr[i]);
stack.push(pop2);
}
else if (typeof pop1.type==="undefined") {
pop1.unshift(pop2);
pop1.push(arr[i]);
stack.push(pop1);
}
else{
stack.push({type:1,value:arr[i].value(pop2.value,pop1.value)});
}
}
else if(arr[i].type===2||arr[i].type===9){
pop1=stack.pop();
pop2=stack.pop();
if(typeof pop2.type==="undefined"){
pop2=pop2.concat(pop1);
pop2.push(arr[i]);
stack.push(pop2);
}
else if (typeof pop1.type==="undefined") {
pop1.unshift(pop2);
pop1.push(arr[i]);
stack.push(pop1);
}
else{
stack.push({type:1,value:arr[i].value(pop2.value,pop1.value)});
}
}
else if(arr[i].type===12){
pop1=stack.pop();
if (typeof pop1.type!=="undefined") {
pop1=[pop1];
}
pop2=stack.pop();
pop3=stack.pop();
stack.push({type:1,value:arr[i].value(pop3.value,pop2.value,new Mexp(pop1))});
}
else if(arr[i].type===13){
if(bool){
stack.push({value:UserDefined[arr[i].value],type:3});
}
else stack.push([arr[i]]);
}
}
if (stack.length>1) {
throw(new Mexp.Exception("Uncaught Syntax error"));
}
return stack[0].value>1000000000000000?"Infinity":parseFloat(stack[0].value.toFixed(15));
};
Mexp.eval=function(str,tokens,obj){
if (typeof tokens==="undefined") {
return this.lex(str).toPostfix().postfixEval();
}
else if (typeof obj==="undefined") {
if (typeof tokens.length!=="undefined")
return this.lex(str,tokens).toPostfix().postfixEval();
else
return this.lex(str).toPostfix().postfixEval(tokens);
}
else
return this.lex(str,tokens).toPostfix().postfixEval(obj);
};
module.exports=Mexp;
},{"./postfix.js":4}]},{},[1])(1)
});

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,10 @@
version: '3.1'
services:
math-expression-evaluator:
volumes:
- ./:/home/math-expression-evaluator
- /home/math-expression-evaluator/node_modules
build:
context: .
dockerfile: ./Dockerfile
command: tail -F anything

View File

@@ -0,0 +1,67 @@
{
"_from": "math-expression-evaluator@^1.2.14",
"_id": "math-expression-evaluator@1.3.7",
"_inBundle": false,
"_integrity": "sha512-nrbaifCl42w37hYd6oRLvoymFK42tWB+WQTMFtksDGQMi5GvlJwnz/CsS30FFAISFLtX+A0csJ0xLiuuyyec7w==",
"_location": "/math-expression-evaluator",
"_phantomChildren": {},
"_requested": {
"type": "range",
"registry": true,
"raw": "math-expression-evaluator@^1.2.14",
"name": "math-expression-evaluator",
"escapedName": "math-expression-evaluator",
"rawSpec": "^1.2.14",
"saveSpec": null,
"fetchSpec": "^1.2.14"
},
"_requiredBy": [
"/reduce-css-calc"
],
"_resolved": "https://registry.npmjs.org/math-expression-evaluator/-/math-expression-evaluator-1.3.7.tgz",
"_shasum": "1b62225db86af06f7ea1fd9576a34af605a5b253",
"_spec": "math-expression-evaluator@^1.2.14",
"_where": "D:\\developments\\teaser-inertia\\nova-components\\NovaLeader\\node_modules\\reduce-css-calc",
"author": {
"name": "Ankit",
"email": "ankitbug94@gmail.com"
},
"bugs": {
"url": "https://github.com/redhivesoftware/math-expression-evaluator/issues"
},
"bundleDependencies": false,
"deprecated": false,
"description": "A flexible math expression evaluator",
"devDependencies": {
"eslint": "^6.6.0",
"eslint-config-standard": "^10.2.1",
"eslint-plugin-import": "^2.2.0",
"eslint-plugin-node": "^4.2.2",
"eslint-plugin-promise": "^3.5.0",
"eslint-plugin-standard": "^3.0.1",
"grunt": "^0.4.5",
"grunt-browserify": "^3.8.0",
"grunt-contrib-uglify": "^0.9.1",
"grunt-contrib-watch": "^1.0.0",
"grunt-eslint": "^19.0.0",
"mocha": "^2.2.5"
},
"homepage": "https://github.com/redhivesoftware/math-expression-evaluator#readme",
"keywords": [
"math",
"expression",
"evaluator",
"parser"
],
"license": "MIT",
"main": "src/formula_evaluator.js",
"name": "math-expression-evaluator",
"repository": {
"type": "git",
"url": "git+https://github.com/redhivesoftware/math-expression-evaluator.git"
},
"scripts": {
"test": "mocha"
},
"version": "1.3.7"
}

View File

@@ -0,0 +1,41 @@
var Mexp=require('./postfix_evaluator.js');
Mexp.prototype.formulaEval = function () {
"use strict";
var stack=[],pop1,pop2,pop3;
var disp=[];
var temp='';
var arr=this.value;
for(var i=0;i<arr.length;i++){
if(arr[i].type===1||arr[i].type===3){
disp.push({value:arr[i].type===3?arr[i].show:arr[i].value,type:1});
}
else if(arr[i].type===13){
disp.push({value:arr[i].show,type:1});
}
else if(arr[i].type===0){
disp[disp.length-1]={value:arr[i].show+(arr[i].show!="-"?"(":"")+disp[disp.length-1].value+(arr[i].show!="-"?")":""),type:0};
}
else if(arr[i].type===7){
disp[disp.length-1]={value:(disp[disp.length-1].type!=1?"(":"")+disp[disp.length-1].value+(disp[disp.length-1].type!=1?")":"")+arr[i].show,type:7};
}
else if(arr[i].type===10){
pop1=disp.pop();
pop2=disp.pop();
if(arr[i].show==='P'||arr[i].show==='C')disp.push({value:"<sup>"+pop2.value+"</sup>"+arr[i].show+"<sub>"+pop1.value+"</sub>",type:10});
else disp.push({value:(pop2.type!=1?"(":"")+pop2.value+(pop2.type!=1?")":"")+"<sup>"+pop1.value+"</sup>",type:1});
}
else if(arr[i].type===2||arr[i].type===9){
pop1=disp.pop();
pop2=disp.pop();
disp.push({value:(pop2.type!=1?"(":"")+pop2.value+(pop2.type!=1?")":"")+arr[i].show+(pop1.type!=1?"(":"")+pop1.value+(pop1.type!=1?")":""),type:arr[i].type});
}
else if(arr[i].type===12){
pop1=disp.pop();
pop2=disp.pop();
pop3=disp.pop();
disp.push({value:arr[i].show+"("+pop3.value+","+pop2.value+","+pop1.value+")",type:12});
}
}
return disp[0].value;
};
module.exports=Mexp;

View File

@@ -0,0 +1,416 @@
"use strict";
var Mexp = require('./math_function.js')
function inc(arr, val) {
for (var i = 0; i < arr.length; i++) {
arr[i] += val
}
return arr
}
var token = ['sin', 'cos', 'tan', 'pi', '(', ')', 'P', 'C', ' ',
'asin', 'acos', 'atan', '7', '8', '9', 'int',
'cosh', 'acosh', 'ln', '^', 'root', '4', '5', '6', '/', '!',
'tanh', 'atanh', 'Mod', '1', '2', '3', '*',
'sinh', 'asinh', 'e', 'log', '0', '.', '+', '-', ',', 'Sigma', 'n', 'Pi', 'pow']
var show = ['sin', 'cos', 'tan', '&pi;', '(', ')', 'P', 'C', ' ',
'asin', 'acos', 'atan', '7', '8', '9', 'Int',
'cosh', 'acosh', ' ln', '^', 'root', '4', '5', '6', '&divide;', '!',
'tanh', 'atanh', ' Mod ', '1', '2', '3', '&times;',
'sinh', 'asinh', 'e', ' log', '0', '.', '+', '-', ',', '&Sigma;', 'n', '&Pi;', 'pow']
var eva = [Mexp.math.sin, Mexp.math.cos, Mexp.math.tan, 'PI', '(', ')', Mexp.math.P, Mexp.math.C, ' '.anchor,
Mexp.math.asin, Mexp.math.acos, Mexp.math.atan, '7', '8', '9', Math.floor,
Mexp.math.cosh, Mexp.math.acosh, Math.log, Math.pow, Math.sqrt, '4', '5', '6', Mexp.math.div, Mexp.math.fact,
Mexp.math.tanh, Mexp.math.atanh, Mexp.math.mod, '1', '2', '3', Mexp.math.mul,
Mexp.math.sinh, Mexp.math.asinh, 'E', Mexp.math.log, '0', '.', Mexp.math.add, Mexp.math.sub, ',', Mexp.math.sigma, 'n', Mexp.math.Pi, Math.pow]
var preced = {
0: 11,
1: 0,
2: 3,
3: 0,
4: 0,
5: 0,
6: 0,
7: 11,
8: 11,
9: 1,
10: 10,
11: 0,
12: 11,
13: 0,
14: -1 // will be filtered after lexer
} // stores precedence by types
var type = [0, 0, 0, 3, 4, 5, 10, 10, 14,
0, 0, 0, 1, 1, 1, 0,
0, 0, 0, 10, 0, 1, 1, 1, 2, 7,
0, 0, 2, 1, 1, 1, 2,
0, 0, 3, 0, 1, 6, 9, 9, 11, 12, 13, 12, 8]
/*
0 : function with syntax function_name(Maths_exp)
1 : numbers
2 : binary operators like * / Mod left associate and same precedence
3 : Math constant values like e,pi,Cruncher ans
4 : opening bracket
5 : closing bracket
6 : decimal
7 : function with syntax (Math_exp)function_name
8: function with syntax function_name(Math_exp1,Math_exp2)
9 : binary operator like +,-
10: binary operator like P C or ^
11: ,
12: function with , seperated three parameters and third parameter is a string that will be mexp string
13: variable of Sigma function
*/
var type0 = {
0: true,
1: true,
3: true,
4: true,
6: true,
8: true,
9: true,
12: true,
13: true,
14: true
} // type2:true,type4:true,type9:true,type11:true,type21:true,type22
var type1 = {
0: true,
1: true,
2: true,
3: true,
4: true,
5: true,
6: true,
7: true,
8: true,
9: true,
10: true,
11: true,
12: true,
13: true
} // type3:true,type5:true,type7:true,type23
var type1Asterick = {
0: true,
3: true,
4: true,
8: true,
12: true,
13: true
}
var empty = {}
var type3Asterick = {
0: true,
1: true,
3: true,
4: true,
6: true,
8: true,
12: true,
13: true
} // type_5:true,type_7:true,type_23
var type6 = {
1: true
}
var newAr = [
[],
['1', '2', '3', '7', '8', '9', '4', '5', '6', '+', '-', '*', '/', '(', ')', '^', '!', 'P', 'C', 'e', '0', '.', ',', 'n', ' '],
['pi', 'ln', 'Pi'],
['sin', 'cos', 'tan', 'Del', 'int', 'Mod', 'log', 'pow'],
['asin', 'acos', 'atan', 'cosh', 'root', 'tanh', 'sinh'],
['acosh', 'atanh', 'asinh', 'Sigma']
]
function match(str1, str2, i, x) {
for (var f = 0; f < x; f++) {
if (str1[i + f] !== str2[f]) {
return false
}
}
return true
}
Mexp.addToken = function (tokens) {
for (var i = 0; i < tokens.length; i++) {
var x = tokens[i].token.length
var temp = -1
// newAr is a specially designed data structure index of 1d array = length of tokens
newAr[x] = newAr[x] || [];
for (var y = 0; y < newAr[x].length; y++) {
if (tokens[i].token === newAr[x][y]) {
temp = token.indexOf(newAr[x][y])
break
}
}
if (temp === -1) {
token.push(tokens[i].token)
type.push(tokens[i].type)
if (newAr.length <= tokens[i].token.length) {
newAr[tokens[i].token.length] = []
}
newAr[tokens[i].token.length].push(tokens[i].token)
eva.push(tokens[i].value)
show.push(tokens[i].show)
} else { // overwrite
token[temp] = tokens[i].token
type[temp] = tokens[i].type
eva[temp] = tokens[i].value
show[temp] = tokens[i].show
}
}
}
function tokenize(string) {
var nodes = [];
var length = string.length;
var key, x, y;
for (var i = 0; i < length; i++) {
if (i < length - 1 && string[i] === ' ' && string[i + 1] === ' ') {
continue
}
key = ''
for (x = (string.length - i > (newAr.length - 2) ? newAr.length - 1 : string.length - i); x > 0; x--) {
if (newAr[x] === undefined) continue;
for (y = 0; y < newAr[x].length; y++) {
if (match(string, newAr[x][y], i, x)) {
key = newAr[x][y]
y = newAr[x].length
x = 0
}
}
}
i += key.length - 1
if (key === '') {
throw (new Mexp.Exception('Can\'t understand after ' + string.slice(i)))
}
var index = token.indexOf(key);
nodes.push({
index: index,
token: key,
type: type[index],
eval: eva[index],
precedence: preced[type[index]],
show: show[index]
})
}
return nodes;
}
Mexp.lex = function (inp, tokens) {
'use strict'
var changeSignObj = {
value: Mexp.math.changeSign,
type: 0,
pre: 21,
show: '-'
}
var closingParObj = {
value: ')',
show: ')',
type: 5,
pre: 0
}
var openingParObj = {
value: '(',
type: 4,
pre: 0,
show: '('
}
var str = [openingParObj]
var ptc = [] // Parenthesis to close at the beginning is after one token
var inpStr = inp
var allowed = type0
var bracToClose = 0
var asterick = empty
var prevKey = ''
var i;
if (typeof tokens !== 'undefined') {
Mexp.addToken(tokens)
}
var obj = {}
var nodes = tokenize(inpStr);
for (i = 0; i < nodes.length; i++) {
var node = nodes[i];
if (node.type === 14) {
if (i > 0 &&
i < nodes.length - 1 &&
nodes[i + 1].type === 1 &&
(nodes[i - 1].type === 1 || nodes[i - 1].type === 6))
throw new Mexp.Exception('Unexpected Space')
continue
}
var index = node.index
var cToken = node.token
var cType = node.type
var cEv = node.eval
var cPre = node.precedence
var cShow = node.show
var pre = str[str.length - 1]
var j
for (j = ptc.length; j--;) { // loop over ptc
if (ptc[j] === 0) {
if ([0, 2, 3, 4, 5, 9, 11, 12, 13].indexOf(cType) !== -1) {
if (allowed[cType] !== true) {
console.log(inp, node, nodes, allowed)
throw (new Mexp.Exception(cToken + ' is not allowed after ' + prevKey))
}
str.push(closingParObj)
allowed = type1
asterick = type3Asterick
inc(ptc, -1).pop()
}
} else break
}
if (allowed[cType] !== true) {
throw (new Mexp.Exception(cToken + ' is not allowed after ' + prevKey))
}
if (asterick[cType] === true) {
cType = 2
cEv = Mexp.math.mul
cShow = '&times;'
cPre = 3
i = i - cToken.length
}
obj = {
value: cEv,
type: cType,
pre: cPre,
show: cShow
}
if (cType === 0) {
allowed = type0
asterick = empty
inc(ptc, 2).push(2)
str.push(obj)
str.push(openingParObj)
} else if (cType === 1) {
if (pre.type === 1) {
pre.value += cEv
inc(ptc, 1)
} else {
str.push(obj)
}
allowed = type1
asterick = type1Asterick
} else if (cType === 2) {
allowed = type0
asterick = empty
inc(ptc, 2)
str.push(obj)
} else if (cType === 3) { // constant
str.push(obj)
allowed = type1
asterick = type3Asterick
} else if (cType === 4) {
inc(ptc, 1)
bracToClose++
allowed = type0
asterick = empty
str.push(obj)
} else if (cType === 5) {
if (!bracToClose) {
throw (new Mexp.Exception('Closing parenthesis are more than opening one, wait What!!!'))
}
bracToClose--
allowed = type1
asterick = type3Asterick
str.push(obj)
inc(ptc, 1)
} else if (cType === 6) {
if (pre.hasDec) {
throw (new Mexp.Exception('Two decimals are not allowed in one number'))
}
if (pre.type !== 1) {
pre = {
value: 0,
type: 1,
pre: 0
} // pre needs to be changed as it will the last value now to be safe in later code
str.push(pre)
inc(ptc, -1)
}
allowed = type6
inc(ptc, 1)
asterick = empty
pre.value += cEv
pre.hasDec = true
} else if (cType === 7) {
allowed = type1
asterick = type3Asterick
inc(ptc, 1)
str.push(obj)
}
if (cType === 8) {
allowed = type0
asterick = empty
inc(ptc, 4).push(4)
str.push(obj)
str.push(openingParObj)
} else if (cType === 9) {
if (pre.type === 9) {
if (pre.value === Mexp.math.add) {
pre.value = cEv
pre.show = cShow
inc(ptc, 1)
} else if (pre.value === Mexp.math.sub && cShow === '-') {
pre.value = Mexp.math.add
pre.show = '+'
inc(ptc, 1)
}
} else if (pre.type !== 5 && pre.type !== 7 && pre.type !== 1 && pre.type !== 3 && pre.type !== 13) { // changesign only when negative is found
if (cToken === '-') { // do nothing for + token
// don't add with the above if statement as that will run the else statement of parent if on Ctoken +
allowed = type0
asterick = empty
inc(ptc, 2).push(2)
str.push(changeSignObj)
str.push(openingParObj)
}
} else {
str.push(obj)
inc(ptc, 2)
}
allowed = type0
asterick = empty
} else if (cType === 10) {
allowed = type0
asterick = empty
inc(ptc, 2)
str.push(obj)
} else if (cType === 11) {
allowed = type0
asterick = empty
str.push(obj)
} else if (cType === 12) {
allowed = type0
asterick = empty
inc(ptc, 6).push(6)
str.push(obj)
str.push(openingParObj)
} else if (cType === 13) {
allowed = type1
asterick = type3Asterick
str.push(obj)
}
inc(ptc, -1)
prevKey = cToken
}
for (j = ptc.length; j--;) { // loop over ptc
if (ptc[j] === 0) {
str.push(closingParObj)
inc(ptc, -1).pop()
} else break // if it is not zero so before ptc also cant be zero
}
if (allowed[5] !== true) {
throw (new Mexp.Exception('complete the expression'))
}
while (bracToClose--) {
str.push(closingParObj)
}
str.push(closingParObj)
// console.log(str);
return new Mexp(str)
}
module.exports = Mexp

View File

@@ -0,0 +1,131 @@
"use strict";
var Mexp = function (parsed) {
this.value = parsed
}
Mexp.math = {
isDegree: true, // mode of calculator
acos: function (x) {
return (Mexp.math.isDegree ? 180 / Math.PI * Math.acos(x) : Math.acos(x))
},
add: function (a, b) {
return a + b
},
asin: function (x) {
return (Mexp.math.isDegree ? 180 / Math.PI * Math.asin(x) : Math.asin(x))
},
atan: function (x) {
return (Mexp.math.isDegree ? 180 / Math.PI * Math.atan(x) : Math.atan(x))
},
acosh: function (x) {
return Math.log(x + Math.sqrt(x * x - 1))
},
asinh: function (x) {
return Math.log(x + Math.sqrt(x * x + 1))
},
atanh: function (x) {
return Math.log((1 + x) / (1 - x))
},
C: function (n, r) {
var pro = 1
var other = n - r
var choice = r
if (choice < other) {
choice = other
other = r
}
for (var i = choice + 1; i <= n; i++) {
pro *= i
}
return pro / Mexp.math.fact(other)
},
changeSign: function (x) {
return -x
},
cos: function (x) {
if (Mexp.math.isDegree) x = Mexp.math.toRadian(x)
return Math.cos(x)
},
cosh: function (x) {
return (Math.pow(Math.E, x) + Math.pow(Math.E, -1 * x)) / 2
},
div: function (a, b) {
return a / b
},
fact: function (n) {
if (n % 1 !== 0) return 'NaN'
var pro = 1
for (var i = 2; i <= n; i++) {
pro *= i
}
return pro
},
inverse: function (x) {
return 1 / x
},
log: function (i) {
return Math.log(i) / Math.log(10)
},
mod: function (a, b) {
return a % b
},
mul: function (a, b) {
return a * b
},
P: function (n, r) {
var pro = 1
for (var i = Math.floor(n) - Math.floor(r) + 1; i <= Math.floor(n); i++) {
pro *= i
}
return pro
},
Pi: function (low, high, ex) {
var pro = 1
for (var i = low; i <= high; i++) {
pro *= Number(ex.postfixEval({
n: i
}))
}
return pro
},
pow10x: function (e) {
var x = 1
while (e--) {
x *= 10
}
return x
},
sigma: function (low, high, ex) {
var sum = 0
for (var i = low; i <= high; i++) {
sum += Number(ex.postfixEval({
n: i
}))
}
return sum
},
sin: function (x) {
if (Mexp.math.isDegree) x = Mexp.math.toRadian(x)
return Math.sin(x)
},
sinh: function (x) {
return (Math.pow(Math.E, x) - Math.pow(Math.E, -1 * x)) / 2
},
sub: function (a, b) {
return a - b
},
tan: function (x) {
if (Mexp.math.isDegree) x = Mexp.math.toRadian(x)
return Math.tan(x)
},
tanh: function (x) {
return Mexp.sinha(x) / Mexp.cosha(x)
},
toRadian: function (x) {
return x * Math.PI / 180
}
}
Mexp.Exception = function (message) {
this.message = message
}
module.exports = Mexp

View File

@@ -0,0 +1,50 @@
var Mexp = require('./lexer.js');
Mexp.prototype.toPostfix = function () {
'use strict';
var post = [], elem, popped, prep, pre, ele;
var stack = [{ value: "(", type: 4, pre: 0 }];
var arr = this.value;
for (var i = 1; i < arr.length; i++) {
if (arr[i].type === 1 || arr[i].type === 3 || arr[i].type === 13) { //if token is number,constant,or n(which is also a special constant in our case)
if (arr[i].type === 1)
arr[i].value = Number(arr[i].value);
post.push(arr[i]);
}
else if (arr[i].type === 4) {
stack.push(arr[i]);
}
else if (arr[i].type === 5) {
while ((popped = stack.pop()).type !== 4) {
post.push(popped);
}
}
else if (arr[i].type === 11) {
while ((popped = stack.pop()).type !== 4) {
post.push(popped);
}
stack.push(popped);
}
else {
elem = arr[i];
pre = elem.pre;
ele = stack[stack.length - 1];
prep = ele.pre;
var flag = ele.value == 'Math.pow' && elem.value == 'Math.pow';
if (pre > prep) stack.push(elem);
else {
while (prep >= pre && !flag || flag && pre < prep) {
popped = stack.pop();
ele = stack[stack.length - 1];
post.push(popped);
prep = ele.pre;
flag = elem.value == 'Math.pow' && ele.value == 'Math.pow';
}
stack.push(elem);
}
}
}
return new Mexp(post);
};
module.exports = Mexp;

View File

@@ -0,0 +1,104 @@
var Mexp=require('./postfix.js');
Mexp.prototype.postfixEval = function (UserDefined) {
'use strict';
UserDefined=UserDefined||{};
UserDefined.PI=Math.PI;
UserDefined.E=Math.E;
var stack=[],pop1,pop2,pop3;
var disp=[];
var temp='';
var arr=this.value;
var bool=(typeof UserDefined.n!=="undefined");
for(var i=0;i<arr.length;i++){
if(arr[i].type===1){
stack.push({value:arr[i].value,type:1});
}
else if(arr[i].type===3){
stack.push({value:UserDefined[arr[i].value],type:1});
}
else if(arr[i].type===0){
if(typeof stack[stack.length-1].type==="undefined"){
stack[stack.length-1].value.push(arr[i]);
}
else stack[stack.length-1].value=arr[i].value(stack[stack.length-1].value);
}
else if(arr[i].type===7){
if(typeof stack[stack.length-1].type==="undefined"){
stack[stack.length-1].value.push(arr[i]);
}
else stack[stack.length-1].value=arr[i].value(stack[stack.length-1].value);
}
else if(arr[i].type===8){
pop1=stack.pop();
pop2=stack.pop();
stack.push({type:1,value:arr[i].value(pop2.value,pop1.value)});
}
else if(arr[i].type===10){
pop1=stack.pop();
pop2=stack.pop();
if(typeof pop2.type==="undefined"){
pop2.value=pop2.concat(pop1);
pop2.value.push(arr[i]);
stack.push(pop2);
}
else if (typeof pop1.type==="undefined") {
pop1.unshift(pop2);
pop1.push(arr[i]);
stack.push(pop1);
}
else{
stack.push({type:1,value:arr[i].value(pop2.value,pop1.value)});
}
}
else if(arr[i].type===2||arr[i].type===9){
pop1=stack.pop();
pop2=stack.pop();
if(typeof pop2.type==="undefined"){
pop2=pop2.concat(pop1);
pop2.push(arr[i]);
stack.push(pop2);
}
else if (typeof pop1.type==="undefined") {
pop1.unshift(pop2);
pop1.push(arr[i]);
stack.push(pop1);
}
else{
stack.push({type:1,value:arr[i].value(pop2.value,pop1.value)});
}
}
else if(arr[i].type===12){
pop1=stack.pop();
if (typeof pop1.type!=="undefined") {
pop1=[pop1];
}
pop2=stack.pop();
pop3=stack.pop();
stack.push({type:1,value:arr[i].value(pop3.value,pop2.value,new Mexp(pop1))});
}
else if(arr[i].type===13){
if(bool){
stack.push({value:UserDefined[arr[i].value],type:3});
}
else stack.push([arr[i]]);
}
}
if (stack.length>1) {
throw(new Mexp.Exception("Uncaught Syntax error"));
}
return stack[0].value>1000000000000000?"Infinity":parseFloat(stack[0].value.toFixed(15));
};
Mexp.eval=function(str,tokens,obj){
if (typeof tokens==="undefined") {
return this.lex(str).toPostfix().postfixEval();
}
else if (typeof obj==="undefined") {
if (typeof tokens.length!=="undefined")
return this.lex(str,tokens).toPostfix().postfixEval();
else
return this.lex(str).toPostfix().postfixEval(tokens);
}
else
return this.lex(str,tokens).toPostfix().postfixEval(obj);
};
module.exports=Mexp;

View File

@@ -0,0 +1,298 @@
// This test is for node JS
var assert = require('assert');
var a = require("../src/formula_evaluator.js");
describe('Testing Unit', function () {
it('should equal 2 to check a number', function () {
assert.equal(a.lex("2").toPostfix().postfixEval(), 2);
});
it('checks a math function', function () {
assert.equal(a.lex("tan(180)").toPostfix().postfixEval(), 0);
});
it('checks a parenthesis less function', function () {
assert.equal(a.lex("sin180").toPostfix().postfixEval(), 0);
});
it('checks a parenthesis less function after a space', function () {
assert.equal(a.lex("cos 180").toPostfix().postfixEval(), -1);
});
it('checks a parenthesis less function after multiple spaces', function () {
assert.equal(a.lex("cos 180").toPostfix().postfixEval(), -1);
});
it('checks consecutive operator', function () {
assert.equal(a.lex("0+-2").toPostfix().postfixEval(), -2);
});
it('checks ^ operator', function () {
assert.equal(a.lex("2^2").toPostfix().postfixEval(), 4);
});
it('checks when * is omitted before parenthesis and after', function () {
assert.equal(a.lex("2(7-4)3").toPostfix().postfixEval(), 18);
});
it('checks multiplication and exponential in series', function () {
assert.equal(a.lex("2*7^2").toPostfix().postfixEval(), 98);
});
it('checks exponential and multiplication in series', function () {
assert.equal(a.lex("2^5*2").toPostfix().postfixEval(), 64);
});
it('-3^2=-9', function () {
assert.equal(a.lex("-3^2").toPostfix().postfixEval(), -9);
});
it('3^2-2^2=5', function () {
assert.equal(a.lex("3^2-2^2").toPostfix().postfixEval(), 5);
assert.equal(
Math.round((a.eval("(4-(2-1)^2)^.5") + Number.EPSILON) * 100) / 100,
Math.round((Math.sqrt(3) + Number.EPSILON) * 100) / 100
)
});
it('formula test', function () {
assert.equal(a.lex("2").toPostfix().formulaEval(), 2);
});
it('formula test', function () {
assert.equal(a.lex("sinpi").toPostfix().formulaEval(), "sin(&pi;)");
});
it('formula test', function () {
assert.equal(a.lex("cos pi").toPostfix().formulaEval(), "cos(&pi;)");
});
it('formula test', function () {
assert.equal(a.lex("tan(pi)").toPostfix().formulaEval(), "tan(&pi;)");
});
it('formula test', function () {
assert.equal(a.lex("2(7-4)3").toPostfix().formulaEval(), "(2&times;(7-4))&times;3");
});
it('test to check the bug when number contains decimal', function () {
assert.equal(a.lex("int2.3").toPostfix().postfixEval(), "2");
});
it('test to check auto correct of parenthesis mismatch if opening>closing', function () {
assert.equal(a.lex("(2+(3-4").toPostfix().postfixEval(), "1");
});
it('check for negative of a constant', function () {
assert.equal(a.lex("-e").toPostfix().postfixEval(), -Math.E);
});
it('check for constant inside Sigma', function () {
assert.equal(a.lex("Sigma1,3,2", [{ type: 3, preced: 0, ev: "x", show: "x", token: "x" }]).toPostfix().postfixEval({ x: 2 }), 6);
});
it('check when arithmetic and n are present inside sigma', function () {
assert.equal(a.lex("Sigma1,2,n").toPostfix().postfixEval(), 3);
});
it(' should check when 4C3', function () {
assert.equal(a.lex("4C3").toPostfix().postfixEval(), 4);
});
it('check when arithmetic and n are present inside sigma', function () {
assert.equal(a.lex("Sigma1,2,(n*n)").toPostfix().postfixEval(), 5);
});
it('check when two parenthesis less functions are consecutive on one parameter', function () {
assert.equal(a.lex("sinint2.5").toPostfix().postfixEval(), a.lex("sin(int(2.5))").toPostfix().postfixEval());
});
it('check eval method with single argument', function () {
assert.equal(a.eval("5*3"), "15");
});
it('check eval method with three argument', function () {
assert.equal(a.eval("mexp*3", [{ type: 3, show: "mexp", token: "mexp", value: "mexp", preced: 0 }], { mexp: 5 }), "15");
});
it('check eval method with two argument when second one is value of constants', function () {
a.addToken([{ type: 3, show: "mexp", value: "mexp", preced: 0, token: "mexp" }]);
assert.equal(a.eval("mexp*3", { mexp: 5 }), "15");
});
it('check eval method with two argument when second one is value of constants', function () {
a.addToken([{ type: 0, show: "mexp", value: function (a) { return 5 * a; }, preced: 11, token: "mexp" }]);
assert.equal(a.lex("mexp3").toPostfix().postfixEval(), "15");
});
it('check eval method with two argument when second one is token list', function () {
assert.equal(a.eval("mexp(3)", [{ type: 0, show: "mexp(", value: function (a) { return 5 * a; }, preced: 11, token: "mexp" }]), "15");
});
it('Pi', function () {
assert.equal(a.eval("Pi1,5,n"), "120");
});
it('tan5(6+3)', function () {
assert.equal(
Math.round((a.eval("tan45(6+3)") + Number.EPSILON) * 100) / 100,
Math.round((9 + Number.EPSILON) * 100) / 100
);
});
it('tan(40+5)', function () {
assert.equal(a.eval("tan(40+5)"), "1");
});
it('checks when a 0 is missing in a decimal number', function () {
assert.equal(a.eval("5*.8"), "4");
});
it('checks root function', function () {
assert.equal(a.eval("root4"), "2");
assert.equal(
Math.round((a.eval("root(4-1^2)") + Number.EPSILON) * 100) / 100,
Math.round((Math.sqrt(3) + Number.EPSILON) * 100) / 100
)
assert.equal(
Math.round((a.eval("root(4-(2-1)^2)") + Number.EPSILON) * 100) / 100,
Math.round((Math.sqrt(3) + Number.EPSILON) * 100) / 100
)
});
it('checks + precedence before number insise parenthesis ', function () {
assert.equal(a.eval("(-2)"), "-2");
});
it('checks multiple allowable operator', function () {
assert.equal(a.eval("2+++-++-+-+3"), "-1");
assert.equal(a.eval("2*+3"), "6");
});
});
describe('These expression will check for types of returned result', function () {
it('should tell to compllete expression', function () {
assert.equal(typeof a.eval('0'), 'number')
});
});
describe('These expression will raise error', function () {
it('should tell to compllete expression', function () {
try {
a.eval("2*")
assert.equal(1, 2)
}
catch (e) {
assert.equal(e.message, "complete the expression")
}
});
it('should warn about multiple operators', function () {
try {
a.eval("2**3")
assert.equal(1, 2)
}
catch (e) {
assert.equal(e.message, "* is not allowed after *")
}
});
it('should warn about multiple operators', function () {
try {
a.eval("2*Mod*3")
assert.equal(1, 2)
}
catch (e) {
assert.equal(e.message, "Mod is not allowed after *")
}
});
it('should warn about operator inside parenthesis', function () {
try {
a.eval("(+)")
assert.equal(1, 2)
}
catch (e) {
assert.equal(e.message, ") is not allowed after +")
}
});
it('should warn about operator inside parenthesis', function () {
try {
a.eval("(2+3+)")
assert.equal(1, 2)
}
catch (e) {
assert.equal(e.message, ") is not allowed after +")
}
});
it('should warn about using space as operator', function () {
try {
console.log(a.eval("1 2"))
assert.equal(1, 2)
}
catch (e) {
assert.equal(e.message, "Unexpected Space")
}
});
it('should warn about using space as operator', function () {
try {
console.log(a.eval("1. 2"))
assert.equal(1, 2)
}
catch (e) {
assert.equal(e.message, "Unexpected Space")
}
});
});
describe('Check autoclose of parenthesis of parser', function () {
it('should tell to compllete expression', function () {
assert.equal(a.eval("((2+3*4"), "14");
});
});
describe('Ading Token', function () {
it('should tell to compllete expression', function () {
a.addToken([{
type: 2,
token: "nroot",
show: "nroot",
value: function (a, b) {
return Math.pow(a, 1 / b);
}
}])
assert.equal(a.eval("27nroot3"), 3);
a.addToken([{
type: 2,
token: "nrootlongesttoken",
show: "nrootlongesttoken",
value: function (a, b) {
return Math.pow(a, 1 / b);
}
}])
assert.equal(a.eval("27nrootlongesttoken3"), 3);
a.addToken([{
type: 2,
token: "tokenwithnumber34",
show: "tokenwithnumber34",
value: function (a, b) {
return a + b;
}
}])
assert.equal(a.eval("17tokenwithnumber347"), 24);
});
it('should tell to compllete expression', function () {
a.addToken([{
type: 2,
token: "nroot",
show: "nroot",
value: function (a, b) {
return Math.pow(a, 1 / b);
}
}])
assert.equal(a.eval("27nroot3"), 3);
});
it('should tell to compllete expression', function () {
a.addToken([{
type: 2,
token: "nrootlongesttoken",
show: "nrootlongesttoken",
value: function (a, b) {
return Math.pow(a, 1 / b);
}
}])
assert.equal(a.eval("27nrootlongesttoken3"), 3);
});
it('should tell to compllete expression', function () {
a.addToken([{
type: 2,
token: "tokenwithnumber34",
show: "tokenwithnumber34",
value: function (a, b) {
return a + b;
}
}])
assert.equal(a.eval("17tokenwithnumber347"), 24);
});
it('maximum of 5 numbers', function () {
a.addToken([{
type: 8,
token: "maxof2",
show: "maxof2",
value: function (a, b, c) {
return Math.max(a, b)
}
}])
assert.equal(a.eval("maxof2(1,maxof2(maxof2(maxof2(maxof2(2,3),5),6),7))"), 7);
});
});