Mathematics with Clojure
This cookbook covers working with mathematics in Clojure, using built-in functions, contrib libraries, and parts of the JDK via interoperability.
This work is licensed under a Creative Commons Attribution 3.0 Unported License (including images & stylesheets). The source is available on Github.
Preliminaries
This cookbook covers Clojure 1.11 (or later) and the
clojure.math
namespace introduced in that release.
It's assumed that either you have the following in
your source code's ns
macro:
(:require [clojure.math :as math])
or else in the repl you've loaded it like so:
(require '[clojure.math :as math])
Recipes
Boxed and Unboxed Math
This section is adapted from Alex Miller's "Inside Clojure" blog post on boxed math warnings.
By default, Clojure treats numbers as either java.lang.Long
or
java.lang.Double
-- known as "boxed numbers" -- rather than the underlying
primitives long
and double
. Values are passed around as java.lang.Object
.
In performance-sensitive code, you may want to use the primitive types
directly and Clojure supports type hints for this purpose.
(defn sum-squares [a b]
(+ (* a a) (* b b)))
In this function, both a
and b
are java.lang.Object
and when you call
(sum-squares 3 4)
both 3
and 4
are boxed (as java.lang.Long
) and
the math is compiled into a sequence of calls to methods in clojure.lang.Numbers
that accept java.lang.Object
arguments.
We can improve efficiency by using type hints for both the arguments and the return type:
(defn sum-squares ^long [^long a ^long b]
(+ (* a a) (* b b)))
This lets Clojure produce a more efficient version of the function that accepts primitive arguments and produces a primitive result.
A useful Var in this context is *unchecked-math*
which controls whether
the compiler will generate checked or unchecked math operations. It can
also warn you about boxed math operations.
user=> (set! *unchecked-math* :warn-on-boxed)
:warn-on-boxed
user=> (def x 3)
#'user/x
user=> (def y 4)
#'user/y
user=> (* x y)
Boxed math warning, NO_SOURCE_PATH:1:1 - call: public static java.lang.Number clojure.lang.Numbers.unchecked_multiply(java.lang.Object,java.lang.Object).
12
You can also set *unchecked-math*
to true
, which will cause the compiler
to generate primitive math operations, if it can, without checking for overflow.
Simple Math
clojure.core
provides a number of basic math operations as functions:
(+ 3 4) ;=> 7
(- 3 4) ;=> -1
(* 3 4) ;=> 12
(/ 3 4) ;=> 3/4 (an exact ratio)
(/ 3.0 4) ;=> 0.75
(double (/ 3 4)) ;=> 0.75 (convert a ratio to a double)
(inc 5) ;=> 6
(dec 5) ;=> 4
For doing integer division and getting remainders (modulus), see the
docs for
quot,
rem, and
mod, which are all provided
in clojure.core
.
abs
, min
, and max
are also provided in clojure.core
and are optimized
for both long
and double
primitive types, as well as working with boxed
numbers.
For exponents, square roots, rounding, ceiling, floor, etc, see the
clojure.math
namespace:
(math/pow 2 3) ;=> 8.0
(math/sqrt 9) ;=> 3.0
(math/round 3.4) ;=> 3
(math/round 3.6) ;=> 4
(math/ceil 3.4) ;=> 4.0
(math/floor 3.6) ;=> 3.0
Prior to Clojure 1.11, you could use the Java platform's java.lang.Math
class
for these operations, e.g., (Math/pow 2 3)
.
Trigonometry
Use what clojure.math
provides, for example:
math/PI ;=> 3.14159...
(math/sin x)
(math/cos x)
(math/tan x)
As with Simple Math above, prior to Clojure 1.11, you could use the Java
platform's java.lang.Math
class for these operations, e.g., (Math/sin x)
.
Combinatorics
For combinatoric functions (such as combinations
and
permutations
), see the
math.combinatorics
contrib library.