Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
55 changes: 39 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,32 +10,55 @@ $ go get -u github.com/nyttikord/gomath@latest
```
You can replace `latest` with any valid tags.

### Calculate
### General parsing

To parse an expression and calculate it, use `gomath.ParseAndCalculate(string, *gomath.Options) (string, error)`.
To parse an expression, use `gomath.Parse(string) (gomath.Result, error)`.
The string is a valid expression, like `1+2` or `2(1/3+4)^5`.
It returns the result of the expression in a string according to the given options.

The result will give you everything needed to perform operations like the exact representation or the ability to convert
Comment thread
anhgelus marked this conversation as resolved.
Outdated
it to $\LaTeX$ code.

```go
res, err := gomath.ParseAndCalculate("1+2", &gomath.Options{})
err == nil // true
res == "3" // true
res, err := gomath.Parse("1/2+1")
// check the error
res.String == "3/2" // true
res.IsExact // true because 1.5 is the exact representation of 3/2
res.LaTeX == `\frac{1}{2} + 1` // true
res.Approx(5) == "1.50000" // true
```

You can modify the result's type with `gomath.Options`.
Set `Decimal` to `true` if you want to have a decimal approximation.
You can specify the number of digits with `Precision`.
You can also call `gomath.ParseAndCalculate(string, *gomath.Options) (string, error)` to directly get the string
representation with the given options or `gomath.ParseAndConvertToLatex(string, *gomath.Options) (string, error)` to get
the $\LaTeX$ code.

### Creating a function

### Convert to LaTeX
You can create a function with `gomath.NewFunction(string) (gomath.Function, int, error)`.
The string is a valid expression representing a function.
It is composed by the arguments and the expression of the function.
You must separate each argument with a coma (`,`) and separate the arguments and the expression with `->`.
```
x, y -> x^y
```
is a valid expression representing a function.
The returned int is the number of arguments.

To parse an expression and convert it into $\LaTeX$, use `gomath.ParseAndConvertToLatex(string, *gomath.Options) (string, error)`.
The string is a valid expression like `1+2` or `2(1/3+4)^5`.
It returns the result of the expression in a string according to the given options.
Then, you can evaluate the function by passing a map containing every argument.
gomath will send you the result (an instance of `gomath.Result`) of the evaluation.

```go
res, err := gomath.ParseAndConvertToLatex("(1+2/3)/2", &gomath.Options{})
err == nil // true
res == `\frac{1 + \frac{2}{3}}{2}` // true
f, _, err := gomath.NewFunction("x, y -> x^y")
if err != nil {
panic(err) // will not panic because the expression is valid
}
res, err := f(map[string]string{
"x": "5",
"y": "2"
})
if err != nil {
panic(err) // will not panic because the expression is valid and every argument is set
}
res.String == "25" // true
```

### Special case
Expand Down
50 changes: 50 additions & 0 deletions function.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package gomath

import (
"errors"
"fmt"
"strings"
)

var (
ErrInvalidFunction = errors.New("invalid function")
ErrInvalidFunctionCall = errors.New("invalid function call")
)

type Function func(map[string]string) (Result, error)
Comment thread
leo-210 marked this conversation as resolved.

// NewFunction creates a new Function by parsing the given string. It must follow this scheme:
//
// arg1, arg2, arg3... -> expr
//
// Example:
//
// gomath.NewFunction("x, y -> x^y")
//
// It returns the Function and the number of arguments.
func NewFunction(s string) (Function, int, error) {
splits := strings.Split(s, "->")
if len(splits) != 2 {
return nil, 0, errors.Join(ErrInvalidFunction, errors.New("a function is defined by 'args -> expression'"))
}
before := splits[0]
expression := strings.TrimSpace(splits[1])
var params []string
for _, p := range strings.Split(before, ",") {
params = append(params, strings.TrimSpace(p))
}
return func(args map[string]string) (Result, error) {
if len(params) != len(args) {
return nil, errors.Join(ErrInvalidFunctionCall, errors.New("not all parameters have been defined"))
}
cp := expression
for _, p := range params {
v, ok := args[p]
if !ok {
return nil, errors.Join(ErrInvalidFunctionCall, fmt.Errorf("missing argument for %s", p))
}
cp = strings.ReplaceAll(cp, p, v)
}
return Parse(cp)
}, len(params), nil
}
35 changes: 35 additions & 0 deletions function_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package gomath

import "testing"

func TestNewFunction(t *testing.T) {
f, n, err := NewFunction("x -> x^2")
if err != nil {
t.Fatal(err)
}
if n != 1 {
t.Errorf("got %d, want 1", n)
}
result, err := f(map[string]string{"x": "5"})
if err != nil {
t.Fatal(err)
}
if result.String() != "25" {
t.Errorf("got %s, want 25", result.String())
}

f, n, err = NewFunction("x, y -> x^y")
if err != nil {
t.Fatal(err)
}
if n != 2 {
t.Errorf("got %d, want 2", n)
}
result, err = f(map[string]string{"x": "5", "y": "2"})
if err != nil {
t.Fatal(err)
}
if result.String() != "25" {
t.Errorf("got %s, want 25", result.String())
}
}
Loading