About me

About me

Feeds

RSS feed

Faro-encoding numbers

9th January 2016

I recently had an application in which I wanted to encode two positive integers, a and b, as a single encoded integer, c, with the following constraints:

  • Usually the two integers would be small (less than 100), but they could each be as large as a million.
  • The encoded integer c should be as small as possible.
  • It should be possible to decode the integers without any additional information.

For example, one possible solution is to calculate 1000000 * a + b, but this doesn't satisfy the second condition, because for a=1 and b=2, c will be 1000002.

The solution

The solution I came up with I've called Faro-Encoding, named after the Faro Shuffle, the technique for interleaving two piles of cards into a single pile. It forms the basis for many card tricks.

The Faro-Encoding works as follows:

  • Express the two numbers in binary.
  • Interleave the two bitstrings, right-aligned, so their bits alternate.
  • Convert the result to a decimal integer.

Faro-Encode

The Faro-Encode routine encodes two or more numbers:

(defun faro-encode (&rest numbers)
 (let ((n (length numbers))
       (base 1)
       (result 0))
   (loop
     (when (every #'zerop numbers) (return result))
     (dotimes (i n)
       (incf result (* base (logand (nth i numbers) 1)))
       (setf (nth i numbers) (ash (nth i numbers) -1))
       (setq base (* 2 base))))))

Here's an example:

CL-USER> (faro-encode 30 17)
854

Faro-Decode

The Faro-Decode routine takes an extra parameter to specify how many numbers have been encoded, and returns an array of the results:

(defun faro-decode (n encoded)
  (let ((a (make-array n :initial-element 0))
        (base 1))
    (loop
     (when (zerop encoded) (return a))
     (dotimes (i n)
       (multiple-value-bind (d r) (truncate encoded 2)
         (when (plusp r) (incf (aref a i) base))
         (setq encoded d)))
     (setq base (* 2 base)))))

Here's an example:

CL-USER> (faro-decode 2 854)
#(30 17)

blog comments powered by Disqus