Clojure Ratios

Computers do math really quickly. Yet, computers struggle with all kinds of things with math. Take, for example, the simple fraction: 2/3. This should be easy to store right? In most languages, it isn’t.
We’re going to use 2/3 throughout all our examples. We’ll use the literal 2/3 instead of (/ 2 3) because it’s more compact, and is equivalent:
(= 2/3 (/ 2 3))
;;=> true
2/3
;;=> 2/3
If you’ve programmed in most languages, you probably expected output like 0.6666667. In Clojure, we need to force that with a cast:
(float 2/3)
;;=> 0.6666667
After casting, we can see they’re not equal:
(= 2/3 (float 2/3))
;;=> false
So, what was that 2/3 we saw? Let’s inspect its type, and its value. I don’t want to write that more than once, so here’s a cool little helper function:
(defn value-and-type
[& args]
(map (juxt identity type) args))
Here it is in action:
(value-and-type 2/3 (float 2/3))
;;=> ([2/3 clojure.lang.Ratio]
;; [0.6666667 java.lang.Float])
Aha! The 2/3 is a special Clojure Ratio type. What can we do with a Ratio?
Determine whether a value is one:
(ratio? 2/3)
;;=> true
(ratio? 3/3)
;;=> false
Note that rational? is a little more inclusive:
(rational? 3/3)
;;=> true
Inspect its numerator and denominator:
(numerator 2/3)
;;=> 2
(denominator 2/3)
;;=> 3
Do math operations without losing precision:
(value-and-type
(* 2/3 3)
(* (float 2/3) 3))
;;=> ([2N clojure.lang.BigInt]
;; [2.0000000596046448 java.lang.Double])
That is pretty great!
You can attempt to turn a floating point number into a ratio. Beware!
(value-and-type
(rationalize 2/3)
(rationalize (float 2/3)))
;;=> ([2/3 clojure.lang.Ratio]
;; [416666679084301/625000000000000
;; clojure.lang.Ratio])
You may have guessed the following would fare better because our computers are binary, and you’d be right:
(value-and-type
(rationalize (float 1/2))
(rationalize (float 3/2)))
;;=> ([1/2 clojure.lang.Ratio]
;; [3/2 clojure.lang.Ratio])
However, for even 2/3, BigInt can save the day!
(value-and-type
(rationalize (/ 2N 3N)))
;;=> ([2/3 clojure.lang.Ratio])



