# 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

29 March 2014