Giter Club home page Giter Club logo

math-expression-evaluator's Introduction

math-expression-evaluator

An extremely efficient, flexible and amazing evaluator for Math expression in Javascript.

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)

Installation

Node JS

Using npm

npm install math-expression-evaluator

Browser

Using bower

bower install math-expression-evaluator

Usage

Using eval method of mexp object

const mexp = new Mexp() var value = mexp.eval(exp); // 2 + 2

Using constituents of eval methods of mexp object

  1. Create mexp object

     const mexp = new Mexp
    
  2. Parse an expression and then add additional detail to the tokens using

     var lexed = mexp.lex("expression");
    

    which returns an array of token which will be further processed by methods toPostfix and postfixEval

  3. Now, that array is needed to be converted to postfix notation using

     var postfixed = mexp.toPostfix(lexed);  
    

    which converts the array to postfix notation and return new array

  4. Now to get the value of expression use postfixEval

     var result = mexp.postfixEval(postfixed);  
    

    where result contains the result.

Extending tokens

  1. Defining a token

    A token is defined similar way as 1.x version. You may refer to test file on examples on how to add tokens. Since this package is TS compatible, you will get autocomplete on mexp.addToken

  2. Adding tokens using addToken method of mexp object

     const mexp = new Mexp()
     mexp.addToken([token1, token2]) // tokens once added will be preserved in later evaluations
    
  3. Adding tokens using eval method of mexp object

     const mexp = new Mexp()
     mexp.eval("expression", [token1, token2]) // tokens once added will be preserved in later evaluations
    
  4. Adding token using constituents of eval method of mexp object

     const mexp = new Mexp()
     const answer = mexp.postfixEval(mexp.toPostfix(mexp.lexed("expression", [token1, token2]))) // tokens once added will be preserved in later evaluations
     console.log(answer)
    

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
& Bitwise AND eg. 3&1 results 1
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

math-expression-evaluator's People

Contributors

arjundashrath avatar bugwheels94 avatar dependabot[bot] avatar moox avatar mstokes-f5 avatar raviqqe avatar sschuberth avatar thespyder avatar wtgtybhertgeghgtwtg avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

math-expression-evaluator's Issues

Something is wrong with Result

Hello, sir. Here is a problem:

  1. ES:
 const Mexp = require('math-expression-evaluator');
 const math = new Mexp();
 console.log( math.eval(`44.23 + 65.53`) ); 
  1. We expect the result is 109.76;

  2. However, the result is still 109.75999999999999 .

We hope it will be fixed. I look forward to hearing from you soon.
Thx. Best wishes.

JS strict mode for math-expression-evaluator? - svelte and rollup

Steps to reproduce:

  • npx degit sveltejs/template my-svelte-project
  • cd my-svelte-project
  • npm install
  • npm install math-expression-evaluator
  • add import mexp from 'math-expression-evaluator' to App.svelte
  • use mexp.eval in App.svelte
  • npm run dev

Result:

Uncaught ReferenceError: assignment to undeclared variable i
tokenize lexer.js:162
lex lexer.js:230
eval postfix_evaluator.js:93
create_fragment$2 App.svelte:15
init index.mjs:1486
App bundle.js:2678
app main.js:3
<anonymous> bundle.js:2697

Disabling strict helps:
Setting the optionoutput.strict to false in rollup.config.js

Can math-expression-evaluator be adaptable to JS strict mode?

Memory leak with 0.5sin instead of 0.5*sin

Hello!

There seems to be a bug when you write 0.5sin(1) instead of 0.5*sin(1), which leads to the page freezing with memory leaks and eventually runs out of memory.

To reproduce:

  1. Go to the fiddle yourself page
  2. Add print("0.5sin(5)")
  3. Run script

image

image

Multiplication and division by negative numbers is broken

Simple expressions such as 1/-1 or 1*-1 can not be evaluated.

  • It is a regression since a0f978c
  • PR with auto tests here #76
    On master, the tests failed with Cannot read properties of undefined (reading 'value')
    Full log:
    1) Testing Unit dividing by negative number :
       TypeError: Cannot read properties of undefined (reading 'value')
        at t.w [as postfixEval] (C:\Users\pierr\git\contribs\web\math-expression-evaluator\dist\es\index.js:1:6463)
        at t.eval (C:\Users\pierr\git\contribs\web\math-expression-evaluator\dist\es\index.js:1:10931)
        at Context.<anonymous> (C:\Users\pierr\git\contribs\web\math-expression-evaluator\test\index.js:183:21)
        at callFn (C:\Users\pierr\git\contribs\web\math-expression-evaluator\node_modules\mocha\lib\runnable.js:326:21)
        at Test.Runnable.run (C:\Users\pierr\git\contribs\web\math-expression-evaluator\node_modules\mocha\lib\runnable.js:319:7)
        at Runner.runTest (C:\Users\pierr\git\contribs\web\math-expression-evaluator\node_modules\mocha\lib\runner.js:422:10)
        at C:\Users\pierr\git\contribs\web\math-expression-evaluator\node_modules\mocha\lib\runner.js:528:12
        at next (C:\Users\pierr\git\contribs\web\math-expression-evaluator\node_modules\mocha\lib\runner.js:342:14)
        at C:\Users\pierr\git\contribs\web\math-expression-evaluator\node_modules\mocha\lib\runner.js:352:7
        at next (C:\Users\pierr\git\contribs\web\math-expression-evaluator\node_modules\mocha\lib\runner.js:284:14)
        at Immediate._onImmediate (C:\Users\pierr\git\contribs\web\math-expression-evaluator\node_modules\mocha\lib\runner.js:320:5)
        at processImmediate (node:internal/timers:466:21)
    

Whitelisting math operations / symbols

We would like to use the math-expression-evaluator for a calculator input field which only needs basic math operations (addition, subtraction, multiplication and divison). Is there a possibility to "whitelist" the allowed operations only?

Is @types/math-expression-evaluator using the wrong return type for `eval`?

I'm unsure if this issue should go here or in the Definitely Typed repo.

According to the types eval returns a string:

eval

static eval(exp: string, tokens?: Token[], pair?: object): string;

I managed to find that this repo returns a string for "Infinity" here: postfix_evaluator.js

Shouldn't the return type then be number | string?

Will eval return a string for any other cases?

If not, perhaps we could change eval to return the global Infinity number?

Then the types at Definitely Typed could be change to have eval return number

[Help requested] Troubles with tokens

Hey I just started using your library recently for rather regular evaluations that have a simple answer, but now i kind of just added a figure system that takes the figures off the server and makes them countable using a stringified code that comes from the server response.


const figureItem: Token[] = figureTokens.map(figure => ({
      type: 6,
      value: figure.result,
      token: figure.code,
      show: figure.code,
      precedence: 6
    }));

    try {
      const value = newStatement ? mexp.eval(newStatement, figureItem, {}) : undefined;

      return {
        statement: newStatement,
        acreage: value !== undefined ? value : 0,
        statementIsValid: true,
      };
    }

Here is the log from the figureItem.

precedence: 0
show: "s3921839"
​​token: "s3921839"
​​type: 6
​​value: 30

What I basically want this thing to do is that when the newStatement is 5+5+ "s3921839"(userwritten figure code) I want the evaluation to be 40.

If you could help id be very grateful thank you !

root method not calculate with custom token

I am trying to convert a number nagative to positive under root function. I register a custom token name positive who handle calculation.
my token is { type: 0, token: 'positive', show: 'positive', value: function (a) { return Math.abs(a); } }
when my formula is "positive(2-6)" is calculate fine and give me result 4.
but when my formula is "root(positive(2-6))" is not throw error but the result is NaN.

Support percent

Would be amazing if you could support percentages
mxp.eval('10% + 40%')

-3^(1*2) wrong result

It returns -6. It should return -9.
Also -3^(1+1) returns -4. It should return -9. But 0-3^(1+1) return correct answers. (The same for the first example)

remove incomplete fix for floating point issues

Suggest removing the code:
return parseFloat(stack[0].value.toFixed(15))
from src/postfix_evaluator.ts
because it only partially solves the issue floating point math, and because there are better work-arounds.
The following code demonstrates both that floating point issues exist, and also that the addToken functionality already allows end-users to fix the issue according to their needs.

import Mexp from './dist/index.js';
import Big from 'big.js';
var mexp = new Mexp();

console.log(mexp.eval('.1 + .2')); // 0.3
console.log(mexp.eval('5.33 + 5.2')); // 10.530000000000001

mexp.addToken([{
    type:2,
    token:"+",
    show:"+",
    value:function(a,b){
        return Big(a).plus(b).toNumber();
    }
}])

console.log(mexp.eval('.1 + .2')); // 0.3
console.log(mexp.eval('5.33 + 5.2')); // 10.53

lne^2

Should be: lne^2 = ln(e^2) = 2. Not lne^2 = (lne)^2 = 1
Also: log10^2 = log(10^2)=2. Not log10^2 = (log10)^2 = 1

Adding custom token type

I am trying add a formula token like

max(1,2,3,4,5) which will show 5
or min(2,5,6,8,1) which will show 1

Any way to implement these types of tokens.

prevent string combine

Does it possible to make mexp.eval("1 2"); throw error instead of result equal to 1 2

Thanks

Typos in documentation

The documentation here has some typos
in the supported math symbols section,

\       Multiplication Operator eg. 23 results 6

should be

*       Multiplication Operator eg. 2*3 results 6

in the Adding token using constituents of eval method of mexp object section,
"lex method takes list of tokens as explained here as second second arguments"

should be

"lex method takes list of tokens as explained here as second second arguments"

in the Adding tokens using eval method of mexp object section,

var value = =mexp.eval(exp,[token1,token2,...],pair);  

should be

var value = mexp.eval(exp,[token1,token2,...],pair);  

in the Functions with two parameters section,
the phrase "two number/argument" should be "two numbers/arguments", as well as in Functions with three parameters

indexOf semver

@ankit31894 Last commit indexOf broke a lot of projects.

Now it works, but I would suggest you to use for instance lodash.indexof instead of your patched code, because this code is well tested.

Please be more semver compatible.

artbitrary return of infinity

At the line located here, an arbitrary decision is decided to return a value of infinity when the number exceeds 10^15

return stack[0].value > 1000000000000000 ? 'Infinity' : parseFloat(stack[0].value.toFixed(15))

Could this be configurable in the evaluate function? Could it just be eliminated? There's plenty of calculations where numbers greater than 10^15 would be part of the equation. Whats the reason for the infinity return?

Source directory published to npm

Someone pointed out to me that the source directory is published to npm. Don't do that as it's not used by anything and is bloat.

Running any evaluations a reasonable amount of times per second produces a forever-rising CPU usage

Here I am again, with my obscure usage of your awesome library haha.

So, recently I bumped it to the latest version, about 3 weeks ago if my memory serves me. Ever since a couple users of my site have noticed a problem with math automations - they start to lag massively with the growing amount of calls to Mexp.

I have been able to reproduce the issue on your JSBin too, replace the script tag with my code, and open the performance monitor in devtools and you will be able to see it. Be careful however, it may crash the tab.

<script>
      const mexp = new Mexp()
  function yourFunction(){
    // do whatever you like here
    print("2+1")
    print("2+2")
    print("2+3")
    print("2+4")
    print("2+5")
    print("2+6")
    print("2+7")
    print("2+8")
    setTimeout(yourFunction, 17);
}

yourFunction();

  function print(str){
    document.body.appendChild(document.createTextNode(str+" evaluates to "+mexp.eval(str)));
    document.body.appendChild(document.createElement("hr"));
  }
</script>

This has not happened before to my knowledge, so some commit has introduced this bug. I'd really appreciate it if you could look into it soon, since a lot of user-generated stuff on my site is using Mexp and it would be quite annoying if most projects start lagging within 30 seconds of playing.

P.S. Live example :). Ignore the ugly visuals haha. Press the play button, and observe the update time counters gradually rising as the song is playing. The calculations are all very simple multiplications, and there are 6 of them. It's the equivalent of running the code I sent above, in terms of Mexp.

TypeError: thirdPartyClass.default is not a constructor

In my TypeScript source code I wrote the following:

import Mexp from 'math-expression-evaluator';
const mexp = new Mexp();

tsc outputs this:

const math_expression_evaluator_1 = require("math-expression-evaluator");
const mexp = new math_expression_evaluator_1.default();

I get the following error when trying to run the script:

const mexp = new math_expression_evaluator_1.default();
             ^

TypeError: math_expression_evaluator_1.default is not a constructor

function composition

I created 2 custom functions
{
type: 0,
token: "ceil",
show: "ceil",
value: function (a) {
return Math.ceil(a);
},
},
{
type: 8,
token: "min",
show: "min",
value: function (a, b) {
return Math.min(a, b);
},

independtly they works fine, but when I try this

min( 4, ceil (0.011 * 100))

I don't obtain the right value I obtain 4 and not 2

Thanks for your help and this great project

-3^2

-3^2 = 9 Should evaluate to -9

note: (-3)^2 should evaluate to 9

[Feature Request] Require Parentheses

By default functions with or without parentheses evaluate to the correct result. Can we add an option to require parentheses for evaluation otherwise the function would fail?

Overwritten user token E

Hi there,

Currently, if a user defines a token (e.g. a variable) as E, it will be overwritten by Math.E. What do you think about preventing this overwrite if a user-defined token of the same name is provided?

Cheers

Additional logs after update

Hi,

I use this package as a dependancy of cssnano in a Gulp build task from the command line. After a recent update, the build task has started producing a lot of unexpected output (~150 lines) every time cssnano runs.

I've narrowed it down to the console.log statement below. Is this something that could be disabled, perhaps with CLI flags?

console.log(string, nodes)

Precedence issue

Since you want cos0=cos(0)=1, you should make it to return cos-0=cos(-0)=1. But your program returns cos-0-cos0=cos(-0-cos(0))=cos(-1) != 0. You should correct it, to return cos-0-cos0=cos(-0)-cos(0)=1-1=0.
The same case for other functions, even log and ln.

Custom token with an arbitrary amount of inputs

Awesome library. Using it for user-definable math and some custom tokens, it's really useful and powerful. Recently I've come to an issue where I want to have a 5-input token, for example:

function scale_number(unscaled, to_min, to_max, from_min, from_max) {
    return (to_max-to_min)*(unscaled-from_min)/(from_max-from_min)+to_min;
}

I couldn't implement a version of that. Could you perhaps add support for more control over defining tokens?

Trouble with tokens

I'm having difficulty registering tokens. I am creating a number of tokens dynamically and attempting to add them to mexp. I have gotten very simple cases to work correctly, but any actual use case is triggering an error. No matter whether I use the addToken method or through eval directly, I always get the error Cannot read property 'length' of undefined at Function.push.f7Mu.Mexp.addToken (lexer.js:72) (eval method is slightly different stack trace but same error)

My token and value fields are unique per token and I am pushing the correct pairs to match up with my tokens. Are there any conditions that I'm missing or which are undocumented? Could it be that my token/value have numeric digits in them?

Thanks for the help

Some syntax errors in dist TypeScript types

When I run tsc --noEmit in my project with the installed latest version of the math-expression-evaluator (2.0.0) and TypeScript version 4.9.4, it shows me that there are some syntax errors in the dist folder of the library, seemingly because there's missing type keyword in the export statements:

node_modules/math-expression-evaluator/dist/types/postfix_evaluator.d.ts:2:1 - error TS1128: Declaration or statement expected.

2 export Constants = Record<string, number>;
  ~~~~~~

node_modules/math-expression-evaluator/dist/types/token.d.ts:2:1 - error TS1128: Declaration or statement expected.

2 export Token = {
  ~~~~~~

node_modules/math-expression-evaluator/dist/types/token.d.ts:3:21 - error TS1005: ',' expected.

3     type: tokenTypes;
                      ~

node_modules/math-expression-evaluator/dist/types/token.d.ts:4:15 - error TS1005: ',' expected.

4     value: any;
                ~

node_modules/math-expression-evaluator/dist/types/token.d.ts:5:18 - error TS1005: ',' expected.

5     token: string;
                   ~

node_modules/math-expression-evaluator/dist/types/token.d.ts:6:31 - error TS1005: ',' expected.

6     numberOfArguments?: number;
                                ~

node_modules/math-expression-evaluator/dist/types/token.d.ts:7:17 - error TS1005: ',' expected.

7     show: string;
                  ~

node_modules/math-expression-evaluator/dist/types/token.d.ts:8:23 - error TS1005: ',' expected.

8     precedence: number;
                        ~

node_modules/math-expression-evaluator/dist/types/token.d.ts:10:1 - error TS1128: Declaration or statement expected.

10 export ParsedToken = Omit<Token, 'token'> & {
   ~~~~~~

node_modules/math-expression-evaluator/dist/types/token.d.ts:11:18 - error TS1005: ',' expected.

11     hasDec?: true;
                    ~


Found 10 errors in 2 files.

Errors  Files
     1  node_modules/math-expression-evaluator/dist/types/postfix_evaluator.d.ts:2
     9  node_modules/math-expression-evaluator/dist/types/token.d.ts:2

This breaks the type checking of the code using the library.
Maybe it's something to do with how the types are built, e.g. on this line?

Could you please help me understand how to fix it? I could create a PR to remove the replacement of export type to export, but I'm unsure whether it will introduce any breaking changes or regressions.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.