Java-Gaming.org    
Featured games (91)
games approved by the League of Dukes
Games in Showcase (576)
games submitted by our members
Games in WIP (497)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1] 2
  ignore  |  Print  
  Free maths expression parser?  (Read 5127 times)
0 Members and 1 Guest are viewing this topic.
Offline CommanderKeith
« Posted 2009-03-14 12:39:29 »

Hi,

Does anybody know of a mathematical expression evaluator that can calculate expressions like "2(1.05^(1/5))"? So it needs to be able to do Math.pow(x, y) using ^ and it would also be cool if it could do implicit multiplication (like 2(1+3)).

It's for a commercial project.

I've been searching but can only find commercial API's like JEP and JFormula. There must be a free one out there...   Undecided

Thanks a lot,
keith

Offline pjt33
« Reply #1 - Posted 2009-03-14 13:08:22 »

If you're using Java 1.6 then can't you use the built-in JavaScript implementation?
Offline CommanderKeith
« Reply #2 - Posted 2009-03-14 18:25:16 »

Thanks for pointing that out, but it doesn't look like javascript can do 2^3, since when I do 2^3 on this site (http://www.merlyn.demon.co.uk/js-logic.htm) it gives me 6 rather than 8!

Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline cylab

JGO Knight


Medals: 34



« Reply #3 - Posted 2009-03-14 18:33:53 »

^ is the Xor operator in java and javascript (and possibly other languages too)

Mathias - I Know What [you] Did Last Summer!
Offline CommanderKeith
« Reply #4 - Posted 2009-03-15 02:41:55 »

Ah ok, that explains it! thanks

Offline woogley
« Reply #5 - Posted 2009-03-15 20:54:46 »

For some reason, this challenge was appealing to me.. so I wrote a parser for this.

It supports the following operators: ()^*/+- (parentheses can be nested)

You can try it out here, to see if you can break it, make it calculate the wrong answer, etc:
http://woogley.net/misc/MathEval/Test.jar (self-executing JAR)

And you can grab the code here:
http://woogley.net/misc/MathEval/MathEval.java

Hope it helps
Offline irreversible_kev

Junior Member





« Reply #6 - Posted 2009-03-15 21:27:52 »

to see if you can break it,

1: 1-1-1
2: (1)(1)
3: (1)^(1/2)
4: +1
5: (1/3)3 <- not really sure if that is valid input

It seems fairly intelligent otherwise

Cheesy
Offline woogley
« Reply #7 - Posted 2009-03-15 22:07:54 »

1: 1-1-1
2: (1)(1)
3: (1)^(1/2)
4: +1
5: (1/3)3 <- not really sure if that is valid input

Thanks! Nothing like a good ego killer Smiley

Just kidding.. I appreciate you posting the bugs (and identifying that invalid input). All of the above have been fixed

Please let me know if you find any more bugs
Offline Riven
« League of Dukes »

JGO Overlord


Medals: 605
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #8 - Posted 2009-03-15 22:22:27 »

My parser handles this, how about yours:

-1+-2-3 = -6
-1--2-3 = -2

And in that code I don't see any operator precedence.. ?

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline woogley
« Reply #9 - Posted 2009-03-15 22:26:59 »

My parser handles this, how about yours:

-1+-2-3 = -6
-1--2-3 = -2

And in that code I don't see any operator precedence.. ?

Did you try those expressions with the Test jar? My parser handles both correctly, so I don't see your point?

Also, from the code:

1  
2  
3  
4  
// Loop through all operators in order of precedence,
// recalculate the expression after each operation,
// repeat until there is nothing left to do
for (j = 0;j < OPERATORS.length();j++) {


Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Riven
« League of Dukes »

JGO Overlord


Medals: 605
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #10 - Posted 2009-03-15 22:34:15 »

Hm... my bad..


anyway this one fails to evaluate:

-(-.1)

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline woogley
« Reply #11 - Posted 2009-03-15 22:41:32 »

anyway this one fails to evaluate:

-(-.1)

Fixed - thanks
Offline Riven
« League of Dukes »

JGO Overlord


Medals: 605
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #12 - Posted 2009-03-15 22:41:49 »

((12)+1)+1
((12))+1

Seems like the parsers barks on "(("

A quick hack could be to replace all "((" by "(1("


It also crashes on "))"

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline Riven
« League of Dukes »

JGO Overlord


Medals: 605
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #13 - Posted 2009-03-15 22:50:19 »

"1-3+4" evaluates to -6 ?! as in (1-(3+4))

Operator precendence: - and + are on the same level, just like * and /

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline woogley
« Reply #14 - Posted 2009-03-15 23:13:14 »

The parentheses thing was just being caused by using lastIndexOf (which obviously won't cover mutltiple same-level groups)

"1-3+4" evaluates to -6 ?! as in (1-(3+4))

Operator precendence: - and + are on the same level, just like * and /

Ah yes, this is an important bug, glad you pointed it out. The program was just using the "Please excuse my dear aunt sally" approach without accounting for same-level ops

All bugs above have been resolved

Thanks,
-- Matt
Offline Riven
« League of Dukes »

JGO Overlord


Medals: 605
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #15 - Posted 2009-03-15 23:32:27 »

I can only crash it on an empty string or nothing between the ( and the ).

So... although there are a few nasty hacks, I can't break it anymore with valid input.

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline CommanderKeith
« Reply #16 - Posted 2009-03-16 01:05:44 »

Wow!!!!!!!!

Thanks heaps Woogley! That's amazing, it works perfect!   Cool  Cheesy

I can't believe you just went and made it. Your powers need harnessing!

I'm using it to make a program that helps uni students learn finance. I'm tutoring 3 classes and I can see that they hate actually doing questions because working them out on a calculator is a pain in the butt, but doing it in an MS-excel style formula bar is easy.

They'll have to work out questions like "What's the net present value of paying $100 now and recieving $40 every year forever, starting in 2 years from now? The discount rate is 10%."

Then in that funky formula bar you made they can type "-100 + (40/0.1)/(1.1^2)" and read the output then select the right answer from a choice of 4.

I'll send you a link to it when I'm finished.

Thanks Riven and irreversible_kev for helping.

Offline Abuse

JGO Coder


Medals: 10


falling into the abyss of reality


« Reply #17 - Posted 2009-03-16 02:17:38 »

"1^--1" gives "empty String" error.

As it appears to have no problem evaluating "--1" on it's own, so perhaps a bug?
(though I can see why it might not be considered a bug, as it won't accept "1^+1" either - though it gives a more meaningful error)

Make Elite IV:Dangerous happen! Pledge your backing at KICKSTARTER here! https://dl.dropbox.com/u/54785909/EliteIVsmaller.png
Offline Abuse

JGO Coder


Medals: 10


falling into the abyss of reality


« Reply #18 - Posted 2009-03-16 02:33:43 »

I don't think "*1" should be considered a legal expression. (Neither "/1" or "^1" are valid)

Also, if "--1" is a valid input "+-1" should also be valid, shouldn't it?

Make Elite IV:Dangerous happen! Pledge your backing at KICKSTARTER here! https://dl.dropbox.com/u/54785909/EliteIVsmaller.png
Offline woogley
« Reply #19 - Posted 2009-03-16 03:27:48 »

@CommanderKeith
Awesome, I'm glad it's working for you Cheesy
I'd be very interested to see how you are using it

"1^--1" gives "empty String" error.

As it appears to have no problem evaluating "--1" on it's own, so perhaps a bug?
(though I can see why it might not be considered a bug, as it won't accept "1^+1" either - though it gives a more meaningful error)

Yeah, I didn't write the parser thinking anyone would use + as non-op (to denote a number as positive). I've rewritten it now so the expressions you mentioned work now

I don't think "*1" should be considered a legal expression. (Neither "/1" or "^1" are valid)

Also, if "--1" is a valid input "+-1" should also be valid, shouldn't it?

Also fixed

Thanks for pointing this out

edit: whoops, not fixed. 0+-1 actually crashes the parser with no error Smiley

edit 2: All of the bugs above have been fixed
Offline woogley
« Reply #20 - Posted 2009-03-16 03:59:13 »

Thanks for pitching in everyone, so far all of the bugs mentioned in this thread have been resolved. Since most of the debugging/testing was done by multiple people, development time for this was just a mere ~4 hours

@CommanderKeith .. sorry for stealing your thread Smiley Hopefully the snippet will make up for it

Quick recap, since it's several posts up:

- The MathEval code can be found here
- You can test some expressions with this self-executable JAR

If anyone else can break it, please share
Offline oNyx

JGO Coder


Medals: 1


pixels! :x


« Reply #21 - Posted 2009-03-16 04:22:55 »

The test jar lacks some action listener for that text field. If you add it one can just press return at the end. Wink

弾幕 ☆ @mahonnaiseblog
Offline CommanderKeith
« Reply #22 - Posted 2009-03-16 06:20:22 »

It's getting better and better. Nice job getting it done in such a short time.

You should put it up in shared code when it's finished, I'm sure it would be of use to many people, especially considering JEP costs $550 (http://www.singularsys.com/order/) and people probably only need it for the kind of calcs that you're one can do.


Offline cylab

JGO Knight


Medals: 34



« Reply #23 - Posted 2009-03-16 12:00:54 »

This is great, thanks for sharing. Variables and constants would be great though  Roll Eyes

Mathias - I Know What [you] Did Last Summer!
Offline Riven
« League of Dukes »

JGO Overlord


Medals: 605
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #24 - Posted 2009-03-16 13:34:30 »

I might opensource my parser, which also has variables and multiple-argument functions (bound to Java methods).

It was my futile attempt at making a fancy scripting language. persecutioncomplex

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline pjt33
« Reply #25 - Posted 2009-03-16 13:44:50 »

If anyone prefers a JavaCC grammar, this is largely based on the calculator in the tutorial and handles all the test cases I've seen in this thread. It also supports numbers in the format 2.6E-17.
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
86  
87  
88  
89  
90  
91  
92  
93  
94  
95  
96  
97  
98  
99  
100  
101  
102  
103  
104  
105  
106  
107  
108  
109  
110  
111  
112  
113  
114  
115  
116  
117  
118  
119  
120  
121  
122  
123  
124  
125  
options
{
   STATIC = false ;
}

PARSER_BEGIN(Calculator)
   import java.io.PrintStream ;

   class Calculator
   {
      public static void main( String[] args ) throws ParseException, TokenMgrError, NumberFormatException
      {
         Calculator parser = new Calculator(System.in);
         parser.Start( System.out );
      }
   }
PARSER_END(Calculator)

SKIP : { " " }
TOKEN : { < EOL : "\n" | "\r" | "\r\n" > }
TOKEN : { < PLUS : "+" > }
TOKEN : { < MINUS : "-" > }
TOKEN : { < TIMES : "*" > }
TOKEN : { < DIVIDE : "/" > }
TOKEN : { < POW : "^" > }
TOKEN : { < OPEN_PAR : "(" > }
TOKEN : { < CLOSE_PAR : ")" > }
TOKEN : { < NUMBER : <FP> | <FP> "E" <DIGITS> | <FP> "E-" <DIGITS> > }
TOKEN : { < #FP : <DIGITS> | <DIGITS> "." <DIGITS> | <DIGITS> "." | "." <DIGITS> > }
TOKEN : { < #DIGITS : (["0"-"9"])+ > }

void Start(PrintStream printStream) throws NumberFormatException :
{
   double value;
}
{
   (
      value=Expression() <EOL> {printStream.println(value);}
   |
      <EOL> {}
   )*
   <EOF>
}

double Expression() throws NumberFormatException :
{
   double i ;
   double value ;
}
{
   value=Term()
   (
      <PLUS> i=Term() {value += i;}
   |
      <MINUS> i=Term() {value -= i;}
   )*
   {return value;}
}

double Term() throws NumberFormatException :
{
   double i ;
   double value ;
}
{
   value=Exponential()
   (
      <TIMES> i=Exponential() {value *= i;}
   |
      <DIVIDE> i=Exponential() {value /= i;}
   |
      i=NonUnaryExponential() {value *= i;}
   )*
   {return value;}
}

double Exponential() throws NumberFormatException:
{
   double i;
   double value;
}
{
   value=Primary()
   (
      <POW> i=Primary() {value = Math.pow(value, i);}
   )*
   {return value;}
}

/* For use on the right-hand of an implicit multiplication, to avoid ambiguity in the grammar */
double NonUnaryExponential() throws NumberFormatException:
{
   double i;
   double value;
}
{
   value=NonUnaryPrimary()
   (
      <POW> i=Primary() {value = Math.pow(value, i);}
   )*
   {return value;}
}

double NonUnaryPrimary() throws NumberFormatException :
{
   Token t;
   double d;
}
{
   t=<NUMBER> {return Double.parseDouble(t.image);}
|
   <OPEN_PAR> d=Expression() <CLOSE_PAR> {return d;}
}

double Primary() throws NumberFormatException :
{
   double d ;
}
{
   d=NonUnaryPrimary() {return d;}
|
   <PLUS> d=Primary() {return d;}
|
   <MINUS> d=Primary() {return -d;}
}
Offline CommanderKeith
« Reply #26 - Posted 2009-03-17 12:54:00 »

Cool, the more options the better!

Thanks everyone for the help.

Offline Markus_Persson

JGO Wizard


Medals: 12
Projects: 19


Mojang Specifications


« Reply #27 - Posted 2009-03-17 13:57:23 »

You can try it out here, to see if you can break it, make it calculate the wrong answer, etc:

It claims 2^3^4 is 4096. It should be 2.41785164E24.

Play Minecraft!
Offline cylab

JGO Knight


Medals: 34



« Reply #28 - Posted 2009-03-17 14:44:11 »

It claims 2^3^4 is 4096. It should be 2.41785164E24.

I see your point, but thats debatable. Do math parsers using the ^ notation usually treat it as being written
[size=13pt]2[/size][size=9pt]3[/size]4
or
(23)4

?

Mathias - I Know What [you] Did Last Summer!
Offline pjt33
« Reply #29 - Posted 2009-03-17 15:07:29 »

Wikipedia suggests it should be right-associative, so here's a tweaked version of the JavaCC grammar:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
86  
87  
88  
89  
90  
91  
92  
93  
94  
95  
96  
97  
98  
99  
100  
101  
102  
103  
104  
105  
106  
107  
108  
109  
110  
111  
112  
113  
114  
115  
116  
117  
118  
119  
120  
121  
122  
123  
124  
125  
126  
127  
options
{
   STATIC = false ;
}

PARSER_BEGIN(Calculator)
   import java.io.PrintStream ;

   class Calculator
   {
      public static void main( String[] args ) throws ParseException, TokenMgrError, NumberFormatException
      {
         Calculator parser = new Calculator(System.in);
         parser.Start( System.out );
      }
   }
PARSER_END(Calculator)

SKIP : { " " }
TOKEN : { < EOL : "\n" | "\r" | "\r\n" > }
TOKEN : { < PLUS : "+" > }
TOKEN : { < MINUS : "-" > }
TOKEN : { < TIMES : "*" > }
TOKEN : { < DIVIDE : "/" > }
TOKEN : { < POW : "^" > }
TOKEN : { < OPEN_PAR : "(" > }
TOKEN : { < CLOSE_PAR : ")" > }
TOKEN : { < NUMBER : <FP> | <FP> "E" <DIGITS> | <FP> "E-" <DIGITS> > }
TOKEN : { < #FP : <DIGITS> | <DIGITS> "." <DIGITS> | <DIGITS> "." | "." <DIGITS> > }
TOKEN : { < #DIGITS : (["0"-"9"])+ > }

void Start(PrintStream printStream) throws NumberFormatException :
{
   double value;
}
{
   (
      value=Expression() <EOL> {printStream.println(value);}
   |
      <EOL> {}
   )*
   <EOF>
}

double Expression() throws NumberFormatException :
{
   double i ;
   double value ;
}
{
   value=Term()
   (
      <PLUS> i=Term() {value += i;}
   |
      <MINUS> i=Term() {value -= i;}
   )*
   {return value;}
}

double Term() throws NumberFormatException :
{
   double i ;
   double value ;
}
{
   value=Exponential()
   (
      <TIMES> i=Exponential() {value *= i;}
   |
      <DIVIDE> i=Exponential() {value /= i;}
   |
      i=NonUnaryExponential() {value *= i;}
   )*
   {return value;}
}

double Exponential() throws NumberFormatException:
{
   double i;
   double value;
}
{
   value=Primary()
   (
      <POW> i=Exponential() {return Math.pow(value, i);}
   |
      {return value;}
   )
}

/* For use on the right-hand of an implicit multiplication, to avoid ambiguity in the grammar */
double NonUnaryExponential() throws NumberFormatException:
{
   double i;
   double value;
}
{
   value=NonUnaryPrimary()
   (
      <POW> i=Exponential() {return Math.pow(value, i);}
   |
      {return value;}
   )
}

double NonUnaryPrimary() throws NumberFormatException :
{
   Token t;
   double d;
}
{
   t=<NUMBER> {return Double.parseDouble(t.image);}
|
   <OPEN_PAR> d=Expression() <CLOSE_PAR> {return d;}
}

double Primary() throws NumberFormatException :
{
   double d ;
}
{
   d=NonUnaryPrimary() {return d;}
|
   <PLUS> d=Primary() {return d;}
|
   <MINUS> d=Primary() {return -d;}
}
Pages: [1] 2
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

xsi3rr4x (14 views)
2014-04-15 18:08:23

BurntPizza (12 views)
2014-04-15 03:46:01

UprightPath (25 views)
2014-04-14 17:39:50

UprightPath (11 views)
2014-04-14 17:35:47

Porlus (28 views)
2014-04-14 15:48:38

tom_mai78101 (50 views)
2014-04-10 04:04:31

BurntPizza (109 views)
2014-04-08 23:06:04

tom_mai78101 (209 views)
2014-04-05 13:34:39

trollwarrior1 (177 views)
2014-04-04 12:06:45

CJLetsGame (184 views)
2014-04-01 02:16:10
List of Learning Resources
by Longarmx
2014-04-08 03:14:44

Good Examples
by matheus23
2014-04-05 13:51:37

Good Examples
by Grunnt
2014-04-03 15:48:46

Good Examples
by Grunnt
2014-04-03 15:48:37

Good Examples
by matheus23
2014-04-01 18:40:51

Good Examples
by matheus23
2014-04-01 18:40:34

Anonymous/Local/Inner class gotchas
by Roquen
2014-03-11 15:22:30

Anonymous/Local/Inner class gotchas
by Roquen
2014-03-11 15:05:20
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!