Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

C11 and C++20 #71

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 19 additions & 40 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@ the standard C math functions and runtime binding of variables.
## Features

- **C99 with no dependencies**.
- Can also be compiled with C++20.
- Single source file and header file.
- Simple and fast.
- Implements standard operators precedence.
- Exposes standard C math functions (sin, sqrt, ln, etc.).
- Exposes standard C math functions (sin, sqrt, log, etc.).
- Can add custom functions and variables easily.
- Can bind variables at eval-time.
- Released under the zlib license - free for nearly any use.
Expand Down Expand Up @@ -101,7 +102,7 @@ After you're finished, make sure to call `te_free()`.

int err;
/* Compile the expression with variables. */
te_expr *expr = te_compile("sqrt(x^2+y^2)", vars, 2, &err);
te_expr *expr = te_compile("sqrt(x**2+y**2)", vars, 2, &err);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the change to ** from ^? I don't necessarily oppose it, using Python frequently myself, but it's certainly not a mathematical standard practice (Mathematica, Matlab).


if (expr) {
x = 3; y = 4;
Expand Down Expand Up @@ -163,20 +164,20 @@ line. It also does error checking and binds the variables `x` and `y` to *3* and


This produces the output:

$ example2 "sqrt(x^2+y2)"
```
$ example2 "sqrt(x**2+y2)"
Evaluating:
sqrt(x^2+y2)
sqrt(x**2+y2)
^
Error near here


$ example2 "sqrt(x^2+y^2)"
$ example2 "sqrt(x**2+y**2)"
Evaluating:
sqrt(x^2+y^2)
sqrt(x**2+y**2)
Result:
5.000000

```

## Binding to Custom Functions

Expand Down Expand Up @@ -228,12 +229,12 @@ Here is some example performance numbers taken from the included
**benchmark.c** program:

| Expression | te_eval time | native C time | slowdown |
| :------------- |-------------:| -----:|----:|
| sqrt(a^1.5+a^2.5) | 15,641 ms | 14,478 ms | 8% slower |
| a+5 | 765 ms | 563 ms | 36% slower |
| a+(5*2) | 765 ms | 563 ms | 36% slower |
| (a+5)*2 | 1422 ms | 563 ms | 153% slower |
| (1/(a+1)+2/(a+2)+3/(a+3)) | 5,516 ms | 1,266 ms | 336% slower |
| :---------------------------|----------:|----------:|------------:|
| `sqrt(a**1.5+a**2.5)` | 15,641 ms | 14,478 ms | 8% slower |
| `a+5` | 765 ms | 563 ms | 36% slower |
| `a+(5*2)` | 765 ms | 563 ms | 36% slower |
| `(a+5)*2` | 1422 ms | 563 ms | 153% slower |
| `(1/(a+1)+2/(a+2)+3/(a+3))` | 5,516 ms | 1,266 ms | 336% slower |



Expand All @@ -244,7 +245,7 @@ TinyExpr parses the following grammar:
<list> = <expr> {"," <expr>}
<expr> = <term> {("+" | "-") <term>}
<term> = <factor> {("*" | "/" | "%") <factor>}
<factor> = <power> {"^" <power>}
<factor> = <power> {"*\*" <power>}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than having "*\*" in the markdown, it might make more since to wrap the section in a code block, if that was the reason to use *\* instead of **.

<power> = {("-" | "+")} <base>
<base> = <constant>
| <variable>
Expand All @@ -265,47 +266,26 @@ for *0.5*)
## Functions supported

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
left-to-right, but this can be changed - see below).

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* by default, see below), log10, pow, sin, sinh, sqrt, tan, tanh
- abs, acos, asin, atan, atan2, cbrt, ceil, cos, cosh, exp, floor, gamma, log, log2, log10, pow, sin, sinh, sqrt, tan, tanh

The following functions are also built-in and provided by TinyExpr:

- fac (factorials e.g. `fac 5` == 120)
- ncr (combinations e.g. `ncr(6,2)` == 15)
- npr (permutations e.g. `npr(6,2)` == 30)
- gcd (common denominator e.g. `gcd(30, 50)` == 10)

Also, the following constants are available:

- `pi`, `e`


## Compile-time options


By default, TinyExpr does exponentiation 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 exponentiation 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

- All functions/types start with the letters *te*.
Expand All @@ -316,4 +296,3 @@ then you can define `TE_NAT_LOG`.
parentheses are important, because TinyExpr will not change the order of
evaluation. If you instead compiled "x+1+5" TinyExpr will insist that "1" is
added to "x" first, and "5" is added the result second.

4 changes: 2 additions & 2 deletions example.c
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#include "tinyexpr.h"
#include "tinyexpr.c"
#include <stdio.h>

int main(int argc, char *argv[])
{
const char *c = "sqrt(5^2+7^2+11^2+(8-2)^2)";
const char *c = "sqrt(5**2 * 2 + 7**2 + 11**2 + (8 - 2)**2)";
double r = te_interp(c, 0);
printf("The expression:\n\t%s\nevaluates to:\n\t%f\n", c, r);
return 0;
Expand Down
2 changes: 1 addition & 1 deletion example3.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ double my_sum(double a, double b) {
int main(int argc, char *argv[])
{
te_variable vars[] = {
{"mysum", my_sum, TE_FUNCTION2}
{.name="mysum", .fun2=my_sum, .type=TE_FUNCTION2}
};

const char *expression = "mysum(5, 6)";
Expand Down
Loading