Dunaj extends available math facilities with means to specify precision of arithmetic operations and to round numbers. A pluggable mechanism for using random number generators is introduced, and math related API was extended with functions of an angle, exponentiations and logarithms.

Instead of using prefixes and suffixes like in Clojure, facilities for unchecked and precise math are in Dunaj specified in separate namespaces. Common arithmetic functions are provided in dunaj.math namespace, with unchecked functions and arithmetic functions with arbitrary precisions defined in dunaj.math.unchecked and dunaj.math.precise respectively.

List of available math functions is extended with exponentiation, logarithms functions and several miscellaneous ones. A separate namespace called dunaj.math.angle contains math functions of an angle, with floating point numbers. Precision of these functions is as implemented by host. Both circular and hyperbolic functions are available.

For objects that have a canonical numeric representation, Dunaj provides a function called `num`.

 Data types that have a canonical numeric representation provide constructors that accept a numeric value as an argument.
``````
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

(num 10)
;;=> 10

(num \\Q)
;;=> 81

(num #inst \"2013-10-20\")
;;=> 1382227200000

(instant 1382227200000)
;;=> #<BasicInstant 2013-10-20T00:00:00.000000000-00:00>

(num #uuid \"462e019f-e7f2-4971-8ba6-14150556f147\")
;;=> 93284838311908100738254531818413289799

(uuid 93284838311908100738254531818413289799)
;;=> #uuid \"462e019f-e7f2-4971-8ba6-14150556f147\"
``````

## Precision and Rounding

In Dunaj, a precision is defined as a map with following keys:

• `:precision` - Any integer. Nonnegative in case of `:significant` type. Defaults to `0`.

• `:type` - `:significant` or `:decimal`. Defaults to `:significant`.

• `:mode` - `:ceiling`, `:floor`, `:half-up`, `:half-down`, `:half-even`, `:up`, `:down` and `:unnecessary`. Defaults to `:half-up`.

 `0` precision with `:significant` type means that any number of significant digits is OK

A precision config map can be used in rounding with `round` or used in `with-precision` to set precision for BigDecimal operations. A convenience functions `floor` and `ceil` are provided too.

Rounding
``````
1
2
3
4
5
6
7
8
9
10
11
12

(round 123.456 {:precision 5})
;;=> 123.46

(round 123.456 :precision 5 :mode :down)
;;=> 123.45

;; one arg round uses {:type :decimal :precision 0 :mode :half-up} precision
(round 123.456)
;;=> 123.0

(round 123.456 {})
;;=> 123.456
``````
Setting precision
``````
1
2
3
4
5
6
7

(with-precision {:precision 10}
(/ 1M 3))
;;=> 0.3333333333M

(with-precision {:precision 5 :mode :up}
(/ 1M 3))
;;=> 0.33334M
``````

## Random Number Generators

While convenience functions `rand`, `rand-integer` and `rand-nth` are provided, Dunaj offers more powerful means to generate random numbers.

Random numbers are generated by a random number generator (rng), which produces collection of random bytes. The random number generator is created with the `rng` function. Dunaj provides four rng types, each having its own rng factory:

• `secure-rng` - A thread safe secure rng with host-specific algorithm and providers

• `seedable-rng` - A thread safe rng with the ability to specify initial seed and with a guarantee that the same seed yields same sequence of items in the first reduction of the rng. Slower compared to other rngs.

• `splittable-rng` - A non thread safe rng which is however intended for fork-join tasks, as it is able to split into two separate rngs. Can be seeded with same guarantees as in seedable-rng.

• `thread-local-rng` - A fast thread local rng.

The `IRngFactory` protocol serves as an extension point for custom rngs. To generate numbers of other types, the dunaj.math.random namespace provides several transducers to convert a collection of bytes to the collection of integers, floats, etc.

``````
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

(ns foo.bar
(:api dunaj)
(:require [dunaj.math.random :refer
[rng secure-rng splittable-rng seedable-rng floats integers]]))

(defn t5
[x]
(seq (take 5 x)))
#'foo.bar/t5

(t5 (rng))
;;=> (119 115 42 -52 -65)

(t5 (rng splittable-rng))
;;=> (-87 68 95 -22 -67)

;; different values for each call
(t5 (rng splittable-rng))
;;=> (61 2 -5 -70 -58)

;; same sequence of values if seed is given
(t5 (rng splittable-rng :seed 37))
;;=> (77 -63 -96 60 -45)

(t5 (rng splittable-rng :seed 37))
;;=> (77 -63 -96 60 -45)

;; a specific rng algorithm
(t5 (rng secure-rng :algorithm :SHA1PRNG))
;;=> (-5 20 -46 40 86)

(t5 (floats (rng seedable-rng :seed 37)))
;;=> (0.6213673786196462 0.11767774115427432 0.3057012221689267 0.2779979466319322 0.8238345844110927)

(t5 (integers (rng seedable-rng :seed 37)))
;;=> (2484939960054915017 -1407233582011305665 -2505961012080803273 6132965348399674666 2831527535557967913)

(t5 (integers 900 1000 (rng)))
;;=> (952 997 998 970 977)
``````