MathParser.inc ─ Advanced mathematical expression parser -
RyDeR` - 02.02.2012
Introduction
It has been quite a while since I last released something as I was running out of ideas and didn't know what to script nor program, but luckily, ****** PM'ed me about some useful ideas and finally picked this one out. This include simply parses mathematical expressions in a correct way. You can dynamically add your own operators, constants and functions as you wish. More examples and features below.
Functions
Here's a quick list of the main functions you can use:
pawn Код:
stock Float: Math::ParseExpression(szExpr[], &e_Error: iError = ERROR_NONE, &iIdx = 0, const iSize = sizeof(szExpr));
stock Math::AddFunction(const szName[], const szFunc[], const iParams);
stock Math::RemoveFunction(const szName[]);
stock Math::AddConstant(const szConst[], const Float: fValue);
stock Math::RemoveConstant(const szConst[]);
stock Math::AddOperator(const szOp[], const szFunc[], const iPrecedence, const e_Assoc: iAssoc);
stock Math::RemoveOperator(const szOp[]);
A list of the defines:
pawn Код:
#if !defined PRECISION
#define PRECISION 3
#endif
#define MAX_OPERATORS (32)
#define MAX_OPERATOR_LENGTH (8)
#define MAX_OPERATOR_FUNCTION_LENGTH (20)
#define MAX_CONSTANTS (32)
#define MAX_CONSTANT_LENGTH (20)
#define MAX_FUNCTIONS (32)
#define MAX_FUNCTION_LENGTH (16)
#define MAX_FUNCTION_FUNCTION_LENGTH (20)
#define MAX_FUNCTION_PARAMS (8)
#define MAX_FUNCTION_PARAMS_LENGTH (32)
If you define
PRECISION before this include, you can have your own decimal precision value instead.
And the error types:
pawn Код:
enum e_Error {
ERROR_NONE,
ERROR_LOGICAL_VALUE,
ERROR_LOGICAL_OPERATOR,
ERROR_LOGICAL_PARANTHESES,
ERROR_PARAMETER_FUNCTION
};
Examples
Basic examples
First of all, the following operators, constants and functions are pre-added:
pawn Код:
Math::AddOperator("E", "E", 25, RIGHT_TO_LEFT);
Math::AddOperator("^", "Pow", 20, RIGHT_TO_LEFT);
Math::AddOperator("*", "Mul", 15, LEFT_TO_RIGHT);
Math::AddOperator("/", "Div", 15, LEFT_TO_RIGHT);
Math::AddOperator("%", "Mod", 15, LEFT_TO_RIGHT);
Math::AddOperator("+", "Add", 10, LEFT_TO_RIGHT);
Math::AddOperator("-", "Sub", 10, LEFT_TO_RIGHT);
Math::AddConstant("pi", 3.141592);
Math::AddConstant("e", 2.718281);
Math::AddFunction("log", "Log", 2);
Math::AddFunction("sqrt", "Sqrt", 1);
Let's start with a simple example:
pawn Код:
new
szExpr[128] = "3 + 0x4 * 0x2 / (1 - 0b00000101) ^ 2 ^ 3"
;
printf("Solution: %." #PRECISION "f", Math::ParseExpression(szExpr));
Will print
Solution: 3.000.
PRECISION decides the amount of numbers after the comma which is
3 in this case. Please note you can also use hexadecimal and binary notation.
Example with the pre-added function(s):
pawn Код:
new
szExpr[128] = "log(32, 2.0)"
;
printf("Solution: %." #PRECISION "f", Math::ParseExpression(szExpr));
Will print
5.000.
We can also use constants and expressions in our function parameters:
pawn Код:
new
szExpr[128] = "(sqrt(log(32.0, 2.0) - 1) ^ 2 ^ 3) * 4"
;
printf("Solution: %." #PRECISION "f", Math::ParseExpression(szExpr));
Will print
1024.000.
Let's use some constants:
pawn Код:
new
szExpr[128] = "e ^ pi"
;
printf("Solution: %." #PRECISION "f", Math::ParseExpression(szExpr));
Is the same as
2.718 ^ 3.141 and results
23.119.
And some other examples:
pawn Код:
new
szExpr[128] = "((3 * (2 * (sqrt(25) + log(0x2000, 2.0) + 3) * 3 ^ (3 % 2))) / 0b00100000 * e)"
;
printf("Solution: %." #PRECISION "f", Math::ParseExpression(szExpr));
Will print
32.106
pawn Код:
new
szExpr[128] = "5E+6 + 20.556"
;
printf("Solution: %." #PRECISION "f", Math::ParseExpression(szExpr));
Will print
5000020.500 (rounded)
How to customize?
It's very easy to define your own operators, functions or constants. Let's start with the operator:
pawn Код:
Math::AddOperator("<<", "SHL", 5, LEFT_TO_RIGHT); // To be called before parsing (ex. OnGameModeInit)
Math::Operator SHL(const Float: fValue1, const Float: fValue2) { // To be added somewhere in your script
return float(floatround(fValue1) << floatround(fValue2));
}
You might be wondering like "what the hell are those parameters for"? The answer is quite simple, each operator has its own precedence and associativity. I usually look
here for the data I need, but as you may have noticed, the precedences are a bit different. I just use them in reverse order with other values (as the value doesn't really matter, just make sure it's bigger or smaller).
pawn Код:
Math::AddFunction("dist", "Dist", 4); // To be called before parsing (ex. OnGameModeInit)
Math::Function Dist(const Float: fX1, const Float: fX2, const Float: fY1, const Float: fY2) { // To be added somewhere in your script
return floatsqroot(floatpower(fX1 - fX2, 2.0) + floatpower(fY1 - fY2, 2.0));
}
This one is quite obvious I guess. In the first parameter you add the name you want to use in your expression, the second one the function to call, in the last parameter the number of parameters the function has.
pawn Код:
Math::AddConstant("MAX_PLAYERS", MAX_PLAYERS); // To be added somewhere in your script
Same here. In the first parameter the name you want to use in your expression and in the second one the value of it.
Let's use them all:
pawn Код:
new
szExpr[128] = "(dist(5, -9, pi, e) << 10) / MAX_PLAYERS"
;
printf("Solution: %." #PRECISION "f", Math::ParseExpression(szExpr));
Will print us
28.672 when you consider
MAX_PLAYERS to be
500.
What if I enter an invalid expression?
The answer is simple, the
iError variable will change from
ERROR_NONE to an error index from
e_Error. You can retrieve the error index by adding a second parameter to
Math::ParseExpression. Example:
pawn Код:
new
szExpr[128] = "5 + 5 + ",
e_Error: iError
;
printf("Solution: %." #PRECISION "f", Math::ParseExpression(szExpr, iError));
Will set iError to
ERROR_LOGICAL_VALUE in this case because you don't have any value added after the
+ operator.
Download
MathParser.inc
Changelog
- 04/02/2011 ─ v0.1.0:
- Fixes:
- Bug regarding decimal and hexadecimal values.
- Removes:
- The E (scientific notation) function is removed and is replaced with an operator instead.
- A small, unnecessary debugging code.
- Adds:
- Due to this bugfix, it is now possible to use E (scientific notation) as an operator which means you can now use this syntax:
pawn Код:
new
szExpr[128] = "5E-3"
;
printf("Solution: %." #PRECISION "f", Math::ParseExpression(szExpr));
Will print us 0.005.
pawn Код:
new
szExpr[128] = "5.5128E+5"
;
printf("Solution: %." #PRECISION "f", Math::ParseExpression(szExpr));
And this will print us 551280.000
Notes
I'm not sure if I explained everything, but this is pretty much it. This include may contains bugs so please report if you find one. Also please note to allocate enough cells in your
szExpr string-array containing your expression in case it replaces (functions, constants) and the length becomes something longer than the total size of your expression string.
Re: MathParser.inc ─ Advanced mathematical expression parser -
BlackBank - 02.02.2012
Wow, very nice and usefull!
Re: MathParser.inc ─ Advanced mathematical expression parser -
FireCat - 02.02.2012
This, actually looks helpfull (:
Respuesta: MathParser.inc ─ Advanced mathematical expression parser -
[DOG]irinel1996 - 02.02.2012
RyDeR`always amazes me. 5/5
Awesome, no comments...
Re: MathParser.inc ─ Advanced mathematical expression parser -
SlashPT - 02.02.2012
Actually I won't use it... but anyways the script looks very clean and nice, I like it....
Very nice work, keep it up
Re: MathParser.inc ─ Advanced mathematical expression parser -
Lorenc_ - 03.02.2012
Very nice release RyDeR`!
Re: MathParser.inc ─ Advanced mathematical expression parser -
RyDeR` - 03.02.2012
Thanks! I'm open for suggestions and improvements, so if there are any, let me know.
Re: MathParser.inc ─ Advanced mathematical expression parser -
-ExG-VirusKiller - 03.02.2012
Again a great release from you RyDeR`
Re: MathParser.inc ─ Advanced mathematical expression parser -
Slice - 03.02.2012
Nice!
Re: MathParser.inc ─ Advanced mathematical expression parser -
RyDeR` - 03.02.2012
Thanks - glad you liked it!