Decimal to Binary Clojure

Viewed 670

I'm following this pseudo code to convert decimal to binary recursively.

findBinary(decimal)
   if (decimal == 0)
      binary = 0
   else
      binary = decimal % 2 + 10 * (findBinary(decimal / 2)

This is what I have tried:

(defn binary [n]
  (loop [res 0]
    (if (= n 0)
    res
    (recur (res (* (+ (mod n 2) 10) (binary (quot n 2)))) )
    )
  )
)

But I get this error :

ClassCastException java.lang.Long cannot be cast to clojure.lang.IFn  user/binary (form-init9002795692676588773.clj:6)

Any ideas how to fix the code to complete the task?

4 Answers

I realize, that this is about the journey and not the result. But to have it mentioned: Long/toString can give you a string from a number with a wide variety of radixes.

(Long/toString 123 2)
; → "1111011"

Here's a slightly different approach which allows recur to be used:

(defn find-binary [d]
  (loop [ decimal  d
          digits   '() ]
    (if (= decimal 0)
      (Integer. (clojure.string/join (map str digits)))
      (recur (quot decimal 2) (conj digits (mod decimal 2))))))

In the loop we build up a collection of binary digits, adding each new digit at the beginning of the list so that we end up with the digits in the desired order left-to-right in the list. When the terminating condition is reached we convert the collection-of-digits to a collection-of-strings, join the collection of strings together into single string, and convert the string back to an integer.

Your psuedo code can be expressed pretty directly in clojure:

(defn find-binary [decimal]
  (if (= decimal 0)
    0
    (+ (mod decimal 2) (* 10 (find-binary (quot decimal 2))))))

Examples:

user=> (find-binary 1)
1
user=> (find-binary 2)
10
user=> (find-binary 25)
11001
user=> (find-binary 255)
11111111

The error in your version is here:

  (recur (res (* (+ (mod n 2) 10) (binary (quot n 2))))

Specifically, the complaint is that you are trying to use res (which has the value 0) as a function.

To be honest, I'm not sure how to do this with loop-recur. When I try it complains about recur not being from the tail position. Perhaps another answer can enlighten us!

Using recur:

;; returns a binary number string of the given decimal number
(defn find-binary [decimal]
  (loop [n decimal
         res ""]
    (if (= n 0)
        res
        (recur (quot n 2)
               (str (mod n 2) res)))))

But without loop:

(defn find-binary [decimal & {:keys [acc] :or {acc ""}}]
    (if (= decimal 0)
        acc
        (find-binary (quot decimal 2) :acc (str (mod decimal 2) acc))))

The original attempt was the following, but it can't go far in the size of decimal:

(defn find-binary [decimal]
  (loop [n decimal ;; number to be binarized
         res '()   ;; collector list
         pos 0]    ;; position of binary number
    (if (= n 0)
        (reduce #'+ res) ;; sum up collector list
        (recur (quot n 2)
               (cons (* (int (Math/pow 10 pos)) 
                        (mod n 2))
                     res)
               (+ 1 pos)))))

For large numbers use:

Related