Clojure numbers default to their host implementation, which refers to the JVM in most cases. So, 1
is of type java.lang.Long
, and 2.5
or 0.1
is of the java.lang.Double
type:
(type 1) java.lang.Long (type 0.1) java.lang.Double
Clojure supports Java's primitive number types of byte
, char
, int
, long
, and float
. These symbols also correspond to Clojure functions, which convert to a native type. This is useful when dealing with a function where a particular type hints at a primitive number:
(defn double' ^long [^long n] (+ n n)) (double' (int 4)) 8
Clojure also supports native JVM numeric types, such as Byte, Short, Integer, Long, BigInteger, Float, Double, and BigDecimal. Larger numbers in Clojure have custom types because they require a greater internal memory representation or a different method of processing. The clojure.lang.BigInt
class is used whenever we need to represent integers that are larger than 64 bits. It is also used for rational numbers that can't be represented with terminating decimals:
(type 10000000000000000000000) clojure.lang.BigInt (* 2.9 10000000000000000000000) 2.8999999999999998E22 (type (* 2.9 10000000000000000000000)) java.lang.Double (type 1/3) clojure.lang.Ratio (def a 5/6) a 5/6 (* a 9) 15/2 (* 2 7.936e-16) 1.5872E-15
Math operations work seamlessly both on converting values as necessary and maintaining their precision. However, this only applies when the numbers fit within Clojure's numeric types and default memory sizes (or when performing an interoperation between Clojure and Java). If you fall outside these memory ranges, your numbers might experience truncation, promotion, overflow, underflow, or rounding errors (you can read more at http://dev.clojure.org/display/design/Documentation+for+1.3+Numerics):
java.lang.Double
to java.lang.BigDecimal
or java.lang.Integer
to java.lang.Long
.int
and long
primitive values when the result is larger than its 32 bit representation.In The Joy Of Clojure, by Manning, Michael Fogus describes how to evade preceding the conditions when you need to (you can read more at https://www.joyofclojure.com/). This is done using Clojure's clojure.lang.Ratio
type, (that is, the Rational Type) to attain perfect accuracy in your calculations. The ratio?
, rational?
, and rationalize
functions help you determine whether your number(s) are rational and convert them to a rational type (or ratio) if the need arises. Fogus recommends that with really large or really small numbers, if you need to maintain precision, check the associative and distributive properties of the numbers resulting from your calculations. By associative, we mean that it doesn't matter how we group our numbers:
(def a (rationalize 1.0e50)) (def b (rationalize -1.0e50)) (def c (rationalize 17.0e00)) (+ (+ a b) c) 17 (+ a (+ b c)) 17
A distributive property signals an indifference to how we distribute a multiplicative factor. With the help of the following code, we can multiply a
by the sum of b
and c
. Or, we can multiply a
by b
, and then add it to a
times c
. Both should yield the same result:
(let [a (rationalize 0.1) b (rationalize 0.2) c (rationalize 0.3)] (= (* a (+ b c)) (+ (* a b) (* a c)))) true
18.191.157.197