abc
abc

Reputation: 153

Converting a number from base 10 to another base in clojure

I am supposed to write a function of 2 arguments, that converts the first number from base 10 to base b. The returned value should be a collection.

I tried using format but I don't know how to use it if b is 2,9,0 etc..

(defn f[x y]
   (cond
     (= y 8)(format "octal %o" x)
     (= y 16)(format "hex %x" x)
     (= y 10)(format "decimal %d" x) 
     :else 0))

Upvotes: 2

Views: 4441

Answers (4)

Ivan Grishaev
Ivan Grishaev

Reputation: 1681

Here is mine pure Clojure solution:

(def charset "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")

(def num->char
  (into {} (map-indexed vector charset)))

(def char->num
  (into {} (map-indexed (comp vec reverse vector) charset)))

(def base (count charset))

(def divmod (juxt quot rem))

(defn exp [x n]
  (loop [acc 1 n n]
    (if (zero? n) acc
        (recur (* x acc) (dec n)))))

(defn encode [n]
  (loop [n n a ""]
    (let [[div mod] (divmod n base)]
      (if (zero? div)
        (str (get num->char mod) a)
        (recur div (str (get num->char mod) a))))))

(defn decode-pair [idx chr]
  (* (get char->num chr)
     (exp base idx)))

(def sum (partial reduce +))

(defn decode [s]
  (sum (map-indexed decode-pair (reverse s))))

Usage:

(encode 1000000000)
15FTGg

(decode "15FTGg")
1000000000

(-> 1000 encode decode (= 1000))
true

Upvotes: 3

NielsK
NielsK

Reputation: 6956

The following functions will do the conversion, casting to java's BigInteger so it will also work for integer values over Integer/MAX_VALUE (2147483647)

(defn to-radix
  [int r]
  (.toString (biginteger int) r))

(to-radix 255 2)
=> "11111111"

(defn from-radix
  [str r]
  (BigInteger. str r)

(from-radix "11111111" 2)
=> 255

Strings can be considered a collection of characters. Map, filter, reduce etc. will call seq to traverse it. In other cases you can just call seq yourself.

(seq (to-radix 255 2))
=> (\1 \1 \1 \1 \1 \1 \1 \1)

Upvotes: 2

nvlass
nvlass

Reputation: 685

Given that this is not some kind of exercise where you have to do the conversion manually, you can use Java's Integer.toString

e.g.

user> (Integer/toString 123456 13) ;; 123456 in base 13
"44268"

As for the sequence part you can just (seq (Integer/toString numb base) However, this will return the chars (0-9 and a-z). You'll probably want a lookup function in order to get the numbers.

Also check toString documentation for allowed radices.

If on the other hand the requirement is that you convert manually then this MO article is probably a good start.

Upvotes: 8

Leon Grapenthin
Leon Grapenthin

Reputation: 9276

(defn to-digits
  [n b]
  (loop [n n
         digits ()]
    (if (pos? n)
      (recur (quot n b)
             (conj digits (mod n b)))
      digits)))

Upvotes: 2

Related Questions