mirror of
				https://github.com/eledio-devices/thirdparty-tinyexpr.git
				synced 2025-10-31 00:32:38 +01:00 
			
		
		
		
	
							
								
								
									
										26
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								README.md
									
									
									
									
									
								
							| @@ -258,17 +258,39 @@ Valid variable names are any combination of the lower case letters *a* through | |||||||
| TinyExpr supports addition (+), subtraction/negation (-), multiplication (\*), | TinyExpr supports addition (+), subtraction/negation (-), multiplication (\*), | ||||||
| division (/), exponentiation (^) and modulus (%) with the normal operator | division (/), exponentiation (^) and modulus (%) with the normal operator | ||||||
| precedence (the one exception being that exponentiation is evaluated | precedence (the one exception being that exponentiation is evaluated | ||||||
| left-to-right). | left-to-right, but this can be changed - see below). | ||||||
|  |  | ||||||
| In addition, the following C math functions are also supported: | In addition, the following C math functions are also supported: | ||||||
|  |  | ||||||
| - abs (calls to *fabs*), acos, asin, atan, atan2, ceil, cos, cosh, exp, floor, ln (calls to *log*), log (calls to *log10*), pow, sin, sinh, sqrt, tan, tanh | - abs (calls to *fabs*), acos, asin, atan, atan2, ceil, cos, cosh, exp, floor, ln (calls to *log*), log (calls to *log10* by default, see below), log10, pow, sin, sinh, sqrt, tan, tanh | ||||||
|  |  | ||||||
| Also, the following constants are available: | Also, the following constants are available: | ||||||
|  |  | ||||||
| - `pi`, `e` | - `pi`, `e` | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ##Compile-time options | ||||||
|  |  | ||||||
|  |  | ||||||
|  | By default, TinyExpr does exponentation from left to right. For example: | ||||||
|  |  | ||||||
|  | `a^b^c == (a^b)^c` and `-a^b == (-a)^b` | ||||||
|  |  | ||||||
|  | This is by design. It's the way that spreadsheets do it (e.g. Excel, Google Sheets). | ||||||
|  |  | ||||||
|  |  | ||||||
|  | If you would rather have exponentation work from right to left, you need to | ||||||
|  | define `TE_POW_FROM_RIGHT` when compiling `tinyexpr.c`. There is a | ||||||
|  | commented-out define near the top of that file. With this option enabled, the | ||||||
|  | behaviour is: | ||||||
|  |  | ||||||
|  | `a^b^c == a^(b^c)` and `-a^b == -(a^b)` | ||||||
|  |  | ||||||
|  | That will match how many scripting languages do it (e.g. Python, Ruby). | ||||||
|  |  | ||||||
|  | Also, if you'd like `log` to default to the natural log instead of `log10`, | ||||||
|  | then you can define `TE_NAT_LOG`. | ||||||
|  |  | ||||||
| ##Hints | ##Hints | ||||||
|  |  | ||||||
| - All functions/types start with the letters *te*. | - All functions/types start with the letters *te*. | ||||||
|   | |||||||
							
								
								
									
										57
									
								
								test.c
									
									
									
									
									
								
							
							
						
						
									
										57
									
								
								test.c
									
									
									
									
									
								
							| @@ -32,6 +32,10 @@ typedef struct { | |||||||
|     double answer; |     double answer; | ||||||
| } test_case; | } test_case; | ||||||
|  |  | ||||||
|  | typedef struct { | ||||||
|  |     const char *expr1; | ||||||
|  |     const char *expr2; | ||||||
|  | } test_equ; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -517,6 +521,58 @@ void test_optimize() { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void test_pow() { | ||||||
|  | #ifdef TE_POW_FROM_RIGHT | ||||||
|  |     test_equ cases[] = { | ||||||
|  |         {"2^3^4", "2^(3^4)"}, | ||||||
|  |         {"-2^2", "-(2^2)"}, | ||||||
|  |         {"-(2)^2", "-(2^2)"}, | ||||||
|  |         {"-(2*1)^2", "-(2^2)"}, | ||||||
|  |         {"-2^2", "-4"}, | ||||||
|  |         {"2^1.1^1.2^1.3", "2^(1.1^(1.2^1.3))"}, | ||||||
|  |         {"-a^b", "-(a^b)"}, | ||||||
|  |         {"-a^-b", "-(a^-b)"} | ||||||
|  |     }; | ||||||
|  | #else | ||||||
|  |     test_equ cases[] = { | ||||||
|  |         {"2^3^4", "(2^3)^4"}, | ||||||
|  |         {"-2^2", "(-2)^2"}, | ||||||
|  |         {"-2^2", "4"}, | ||||||
|  |         {"2^1.1^1.2^1.3", "((2^1.1)^1.2)^1.3"}, | ||||||
|  |         {"-a^b", "(-a)^b"}, | ||||||
|  |         {"-a^-b", "(-a)^(-b)"} | ||||||
|  |     }; | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |     double a = 2, b = 3; | ||||||
|  |  | ||||||
|  |     te_variable lookup[] = { | ||||||
|  |         {"a", &a}, | ||||||
|  |         {"b", &b} | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     int i; | ||||||
|  |     for (i = 0; i < sizeof(cases) / sizeof(test_equ); ++i) { | ||||||
|  |         const char *expr1 = cases[i].expr1; | ||||||
|  |         const char *expr2 = cases[i].expr2; | ||||||
|  |  | ||||||
|  |         te_expr *ex1 = te_compile(expr1, lookup, sizeof(lookup)/sizeof(te_variable), 0); | ||||||
|  |         te_expr *ex2 = te_compile(expr2, lookup, sizeof(lookup)/sizeof(te_variable), 0); | ||||||
|  |  | ||||||
|  |         lok(ex1); | ||||||
|  |         lok(ex2); | ||||||
|  |  | ||||||
|  |         double r1 = te_eval(ex1); | ||||||
|  |         double r2 = te_eval(ex2); | ||||||
|  |  | ||||||
|  |         fflush(stdout); | ||||||
|  |         lfequal(r1, r2); | ||||||
|  |  | ||||||
|  |         te_free(ex1); | ||||||
|  |         te_free(ex2); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
| int main(int argc, char *argv[]) | int main(int argc, char *argv[]) | ||||||
| { | { | ||||||
| @@ -528,6 +584,7 @@ int main(int argc, char *argv[]) | |||||||
|     lrun("Dynamic", test_dynamic); |     lrun("Dynamic", test_dynamic); | ||||||
|     lrun("Closure", test_closure); |     lrun("Closure", test_closure); | ||||||
|     lrun("Optimize", test_optimize); |     lrun("Optimize", test_optimize); | ||||||
|  |     lrun("Pow", test_pow); | ||||||
|     lresults(); |     lresults(); | ||||||
|  |  | ||||||
|     return lfails != 0; |     return lfails != 0; | ||||||
|   | |||||||
							
								
								
									
										58
									
								
								tinyexpr.c
									
									
									
									
									
								
							
							
						
						
									
										58
									
								
								tinyexpr.c
									
									
									
									
									
								
							| @@ -22,6 +22,18 @@ | |||||||
|  * 3. This notice may not be removed or altered from any source distribution. |  * 3. This notice may not be removed or altered from any source distribution. | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
|  | /* COMPILE TIME OPTIONS */ | ||||||
|  |  | ||||||
|  | /* Exponentiation associativity: | ||||||
|  | For a^b^c = (a^b)^c and -a^b = (-a)^b do nothing. | ||||||
|  | For a^b^c = a^(b^c) and -a^b = -(a^b) uncomment the next line.*/ | ||||||
|  | /* #define TE_POW_FROM_RIGHT */ | ||||||
|  |  | ||||||
|  | /* Logarithms | ||||||
|  | For log = base 10 log do nothing | ||||||
|  | For log = natural log uncomment the next line. */ | ||||||
|  | /* #define TE_NAT_LOG */ | ||||||
|  |  | ||||||
| #include "tinyexpr.h" | #include "tinyexpr.h" | ||||||
| #include <stdlib.h> | #include <stdlib.h> | ||||||
| #include <math.h> | #include <math.h> | ||||||
| @@ -116,7 +128,12 @@ static const te_variable functions[] = { | |||||||
|     {"exp", exp,      TE_FUNCTION1 | TE_FLAG_PURE}, |     {"exp", exp,      TE_FUNCTION1 | TE_FLAG_PURE}, | ||||||
|     {"floor", floor,  TE_FUNCTION1 | TE_FLAG_PURE}, |     {"floor", floor,  TE_FUNCTION1 | TE_FLAG_PURE}, | ||||||
|     {"ln", log,       TE_FUNCTION1 | TE_FLAG_PURE}, |     {"ln", log,       TE_FUNCTION1 | TE_FLAG_PURE}, | ||||||
|  | #ifdef TE_NAT_LOG | ||||||
|  |     {"log", log,      TE_FUNCTION1 | TE_FLAG_PURE}, | ||||||
|  | #else | ||||||
|     {"log", log10,    TE_FUNCTION1 | TE_FLAG_PURE}, |     {"log", log10,    TE_FUNCTION1 | TE_FLAG_PURE}, | ||||||
|  | #endif | ||||||
|  |     {"log10", log10,  TE_FUNCTION1 | TE_FLAG_PURE}, | ||||||
|     {"pi", pi,        TE_FUNCTION0 | TE_FLAG_PURE}, |     {"pi", pi,        TE_FUNCTION0 | TE_FLAG_PURE}, | ||||||
|     {"pow", pow,      TE_FUNCTION2 | TE_FLAG_PURE}, |     {"pow", pow,      TE_FUNCTION2 | TE_FLAG_PURE}, | ||||||
|     {"sin", sin,      TE_FUNCTION1 | TE_FLAG_PURE}, |     {"sin", sin,      TE_FUNCTION1 | TE_FLAG_PURE}, | ||||||
| @@ -357,7 +374,46 @@ static te_expr *power(state *s) { | |||||||
|     return ret; |     return ret; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #ifdef TE_POW_FROM_RIGHT | ||||||
|  | static te_expr *factor(state *s) { | ||||||
|  |     /* <factor>    =    <power> {"^" <power>} */ | ||||||
|  |     te_expr *ret = power(s); | ||||||
|  |  | ||||||
|  |     int neg = 0; | ||||||
|  |     te_expr *insertion = 0; | ||||||
|  |  | ||||||
|  |     if (ret->type == (TE_FUNCTION1 | TE_FLAG_PURE) && ret->function == negate) { | ||||||
|  |         te_expr *se = ret->parameters[0]; | ||||||
|  |         free(ret); | ||||||
|  |         ret = se; | ||||||
|  |         neg = 1; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     while (s->type == TOK_INFIX && (s->function == pow)) { | ||||||
|  |         te_fun2 t = s->function; | ||||||
|  |         next_token(s); | ||||||
|  |  | ||||||
|  |         if (insertion) { | ||||||
|  |             /* Make exponentiation go right-to-left. */ | ||||||
|  |             te_expr *insert = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, insertion->parameters[1], power(s)); | ||||||
|  |             insert->function = t; | ||||||
|  |             insertion->parameters[1] = insert; | ||||||
|  |             insertion = insert; | ||||||
|  |         } else { | ||||||
|  |             ret = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, ret, power(s)); | ||||||
|  |             ret->function = t; | ||||||
|  |             insertion = ret; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (neg) { | ||||||
|  |         ret = NEW_EXPR(TE_FUNCTION1 | TE_FLAG_PURE, ret); | ||||||
|  |         ret->function = negate; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return ret; | ||||||
|  | } | ||||||
|  | #else | ||||||
| static te_expr *factor(state *s) { | static te_expr *factor(state *s) { | ||||||
|     /* <factor>    =    <power> {"^" <power>} */ |     /* <factor>    =    <power> {"^" <power>} */ | ||||||
|     te_expr *ret = power(s); |     te_expr *ret = power(s); | ||||||
| @@ -371,6 +427,8 @@ static te_expr *factor(state *s) { | |||||||
|  |  | ||||||
|     return ret; |     return ret; | ||||||
| } | } | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static te_expr *term(state *s) { | static te_expr *term(state *s) { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user