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
