Dunaj  Improving Math Facilities
version 0.7.0
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 \"20131020\")
;;=> 1382227200000
(instant 1382227200000)
;;=> #<BasicInstant 20131020T00:00:00.00000000000:00>
(num #uuid \"462e019fe7f249718ba614150556f147\")
;;=> 93284838311908100738254531818413289799
(uuid 93284838311908100738254531818413289799)
;;=> #uuid \"462e019fe7f249718ba614150556f147\"
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 to0
. 
:type
:significant
or:decimal
. Defaults to:significant
. 
:mode
:ceiling
,:floor
,:halfup
,:halfdown
,:halfeven
,:up
,:down
and:unnecessary
. Defaults to:halfup
.
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
withprecision
to set precision
for BigDecimal operations. A convenience functions
floor
and
ceil
are provided too.
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 :halfup} precision
(round 123.456)
;;=> 123.0
(round 123.456 {})
;;=> 123.456
1
2
3
4
5
6
7
(withprecision {:precision 10}
(/ 1M 3))
;;=> 0.3333333333M
(withprecision {:precision 5 :mode :up}
(/ 1M 3))
;;=> 0.33334M
Random Number Generators
While convenience functions rand
,
randinteger
and randnth
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:

securerng
 A thread safe secure rng with hostspecific algorithm and providers 
seedablerng
 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. 
splittablerng
 A non thread safe rng which is however intended for forkjoin tasks, as it is able to split into two separate rngs. Can be seeded with same guarantees as in seedablerng. 
threadlocalrng
 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 securerng splittablerng seedablerng floats integers]]))
(defn t5
[x]
(seq (take 5 x)))
#'foo.bar/t5
;; default rng is threadlocalrng
(t5 (rng))
;;=> (119 115 42 52 65)
(t5 (rng splittablerng))
;;=> (87 68 95 22 67)
;; different values for each call
(t5 (rng splittablerng))
;;=> (61 2 5 70 58)
;; same sequence of values if seed is given
(t5 (rng splittablerng :seed 37))
;;=> (77 63 96 60 45)
(t5 (rng splittablerng :seed 37))
;;=> (77 63 96 60 45)
;; a specific rng algorithm
(t5 (rng securerng :algorithm :SHA1PRNG))
;;=> (5 20 46 40 86)
(t5 (floats (rng seedablerng :seed 37)))
;;=> (0.6213673786196462 0.11767774115427432 0.3057012221689267 0.2779979466319322 0.8238345844110927)
(t5 (integers (rng seedablerng :seed 37)))
;;=> (2484939960054915017 1407233582011305665 2505961012080803273 6132965348399674666 2831527535557967913)
(t5 (integers 900 1000 (rng)))
;;=> (952 997 998 970 977)