# Numberto: Expressions

Numberto has new features!

In previous post

I wrote about simple clojure library numberto for experiments with numbers.

New version of *numberto* has a bunch of new features.

### Expressions

Expressions package provides two functions: `eval-infix`

to evaluate infix expression

and `infix->prefix`

to build prefix lisp-style expression from mathematical notation.

Let's give it alias for simplicity

```
(def e eval-infix)
```

Evaluate simple math expression

```
(e "1+2") => 3
```

or more complex

```
(e "1+2*(3-4/2)") => 3
```

handle priorities

```
(e "2+2*2") => 6
```

and left/right associativity

```
(e "1024/2/2/2/2") => 64
(e "2^3^4") => 2417851639229258349412352N
```

Oh, what's this? Long numbers? Sure, ratios and floats supported as well

```
(e "1/3") => 1/3
(e "1.1/0.9") => 1.2222222222222223
```

Unary operations

```
(e "(-1)^100") => 1
```

functions and symbols

```
(e "sin(e) + sqrt(pi)") => 2.183235141408425
```

vararg functions

```
(e "sum(1,2,3,sum())/max(1,2)") => 3
```

You can also provide bindings for unknown functions and symbols

```
(e "factorial(n)/20"
{:bindings
{"factorial" #(reduce *' (range 1 (inc %)))
"n" 10}})
=> 181440
```

Worth to mention that you can easily redefine existing

or define your own new unary, binary operations, functions

and symbols. Just add additional properties to `eval-infix`

```
;; return current time in millis
(e "now()" {:bindings {"now" #(.getTime (java.util.Date.))}}) => some long number
;; override priorities
(e "1+2*3" {:binary-ops {"+" {:function + :priority 100}}}) => 9
```

`infix->prefix`

has exactly the same functionality, but it builds prefix expression instead.

```
(infix->prefix "(1+2)*3-(4/avg(3,5)-sum(1))")
=>
"(- (* (+ 1 2) 3) (- (/ 4 (avg 3 5)) (sum 1)))"
```

It can be useful if you googled some formula but bored to translate it manually to clojure.

For example, take the Simpson's rule

```
(infix->prefix "(b-a)/6*(f(a)+4*f((a+b)/2)+f(b))")
=>
"(* (/ (- b a) 6) (+ (+ (f a) (* 4 (f (/ (+ a b) 2)))) (f b)))"
```

#### Implementation

Would be good to try instaparse for such purpose,

but I decided to use custom implementation using standard

Shunting-yard algorithm.

Just couple of hacks added to handle unaries and vararg functions.

Code is awful. If you really want to dig in – run debug mode.

```
(binding [*DEBUG* true]
(e "1+2"))
```

#### Limitations

- No way to define non-prefix unary operation, like "10!" or "|10|"
- Can not handle simplified math form, like "2x^2 + 3^x + 5".

Multiplication sign should be declared explicitly - Not able to simplify ops in lisp-style expression.
`(* (* 1 2) 3)`

instead of`(* 1 2 3)`

- False positives handling. Some stupid expressions indicates about error
`(e "1+")`

, some not`(e "1+()1)`

. I still working on this, but it is not critical.

### Solvers

Here is the puzzle:

You have four numbers [3, 4, 5, 6].

You have four binary operations [+, -, *, /] and parentheses ()How to insert operations between numbers to get number 42?

Hah, that simple `3*4 + 5*6 = 42`

Ok, get `42`

, but you forced to use one division `/`

.

Not so obvious?

```
(solve-insert-ops-num [3 4 5 6] 42) =>
([42N "3+45-6"] [42N "3/4*56"] [42N "3*4+5*6"])
```

If you use `solve-insert-ops`

function it gives all possible values can be obtained by inserting operations between numbers.

```
(solve-insert-ops [3 4 5 6]) => ;; long list
```

Default implementation uses 4 basic operations, no parens and no restrictions. Instead, you can override options

to use parens, specify level

```
(solve-insert-ops-num [3 4 5 6] 42 {:parens 1}) =>
([42N "3+45-6"] [42N "(3+45)-6"] [42N "3+(45-6)"]
[42N "3/4*56"] [42N "(3/4)*56"] [42N "3/(4/56)"]
[42N "3*4+5*6"] [42N "(3*4)+5*6"] [42N "3*4+(5*6)"])
```

limit some operations

```
(solve-insert-ops-num [3 4 5 6] 42 {:rules [[:max "*" 1]]}) =>
([42N "3+45-6"] [42N "3/4*56"])
```

`:max`

, `:min`

, `:max-in-a-row`

, `:min-in-a-row`

options are supported.

Add new operations (supported by expressions package)

```
(solve-insert-ops-num [3 4 5 6] 80
{:ops ["+" "-" "*" "/" "^"]
:rules [[:max "^" 1]]}) =>
([80N "3^4+5-6"])
```

Keep in mind, always limit time consuming operations (*like* `^`

) as it builds all possible permutations and you can wait your answer forever.

There are also couple of *new* interesting things, like

getting digits of `pi`

, `e`

, `sqrt(n)`

, ratio numbers up to desired level and other. Check it out

Source: Mykhailo Kozik