Numbers and precision

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):

  • Truncation occurs when the precision of a floating point number is limited because we can't fit the necessary bits into a particular representation.
  • Promotion occurs when a number is too large for its representation. Clojure will automatically promote this number to a bigger type. For example, promoting java.lang.Double to java.lang.BigDecimal or java.lang.Integer to java.lang.Long.
  • Overflow mostly takes place by operating on int and long primitive values when the result is larger than its 32 bit representation.
  • Underflow is the opposite, occurring when a number is so small that its value is set to zero.
  • Rounding errors occur when a floating number type isn't big enough to handle the actual value that's needed. This often happens when interacting with Java libraries and is very hard to spot because the error is small. These small errors, though, can accumulate over time and negatively affect your calculations. So, pay close attention to your numbers and your calculations over time.

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
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.157.197