Here's a handy class for applications needing a way to deal with mathematical expressions input by the user. It accepts an NSString consisting of a well-formed mathematical expression, evaluates it, and returns the result. It supports arbitrary named variables, so it is also perfect for graph plotting applications.

- Basic operators: +, -, * (multiply) and / (divide)
- Mod operator: %
- Exponentiation operator: ^
- Negation: unary -
- Assignment: =
- Log functions: log(), log2(), ln(), exp()
- Transcendental functions: sin(), cos(), tan(), asin(), acos(), atan(), sinh(), cosh(), tanh(), asinh(), acosh(), atanh()
- Square root function: sqrt()
- Rounding functions: ceil(), floor(), round(), trunc(), rint(), near()
- Angular conversion functions: dtor(), rtod()
- Absolute value function: abs()
- Constants: pi

Parenthesis are used to group subexpressions to set the order of execution, and can be nested to any depth. All computation is carried out using double precision floating point. If there is an error (such as a syntax error in the expression), an exception is raised. Arguments to transcendental functions are in radians; dtor and rtod convert between degrees and radians and vice versa. All functions map directly to their counterparts in the IEEE floating point arithmetic implementation (i.e. <math.h> or <fp.h>). Note that all function names are reserved words and can't be used as variable names. Variable names are unlimited in length and can consist of any combination of letters and numbers but must start with a letter. Note however that the symbol table is very simple and does not use hashing - thus shorter names will give marginally better performance. The parser itself was generated using BISON but uses a hand-coded lexer. The code generated by BISON is good but doesn't look too pretty - luckily by using the Cocoa wrapper you don't have to even look at it.

Expression | Numerical result |
---|---|

"3+4" | 7 |

"5*6" | 30 |

"4+(3.5*8)" | 32 |

"100/3" | 33.333333333 |

"sin(0.5)" | 0.479425538 |

"2.5^3" | 15.625 |

"cos(1/20)+sin(1/30)+cos(1/50)" | 2.031877428 |

"(1+2.2)*(3.1+6.6)" | 31.04 |

"(2*(3/(4+(5-3))))" | 1 |

"sqrt(2)" | 1.4142136 |

If you only have a casual need to parse an expression, the simplest way is to use the supplied category method on NSString:

NSString* mathstring = @"tan(dtor(45))"; double result = [mathstring evaluateMath]; // returns 0.999999999999...

This instantiates a parser internally, evaluates the expression, discards the parser and returns the result. The only thing you lose with using it this way is the ability to set up variables, since the internal symbol table is created then freed and any variables are discarded. Variables are very powerful and useful however - especially if you want to plot a function. To allow the use of variables, you need to instantiate (and possibly retain) a GCMathParser object.

GCMathParser* parser = [GCMathParser parser]; NSString* expression = @"sin(x)"; double x, y; for( x = -pi; x <= pi; x += 0.01 ) { [parser setSymbolValue:x forKey:@"x"]; y = [parser evaluate:expression]; // do something with x and y here, for example plot it. }

This example shows how a variable's value, in this case "x", can be set directly. Another way to do this is to evaluate an expression such as "x=3.6" which both creates the variable "x" and assigns its value. This is marginally less efficient than setting the variable value directly because the assignment expression has to be parsed each time. Variables that are referenced but never have a value assigned are legal - they will have a value of 0.

The demo is very simple - it simply allows you to type an expression and evaluate it. You can also optionally choose whether the parser is kept around or not so you can explore the use of variables.

© 2006-2008 Graham Cox