Skip to content

Instantly share code, notes, and snippets.

@wobh
Last active March 26, 2019 10:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wobh/d17216216907216c300297735510e259 to your computer and use it in GitHub Desktop.
Save wobh/d17216216907216c300297735510e259 to your computer and use it in GitHub Desktop.
bijective numeration library in Common Lisp
(defpackage #:bijective-numeration
(:nicknames :bij)
(:use #:common-lisp)
(:export #:*base20-en*
#:*base26-en*
#:*base30-en*
#:*base36-en*
#:*digits*)
(:export #:weight
#:digit
#:encode
#:decode
#:digit-sum
#:lessp)
(:documentation "bijective-numeration
Provides some basic functions for mapping numbers into bijective numerations"))
;;; Irritated into being by the same meme as this:
;;; http://www.flyingcoloursmaths.co.uk/attitude-really-equal-100/
;;; https://en.wikipedia.org/wiki/Bijective_numeration
(in-package #:bijective-numeration)
(defparameter *base20-en*
"bcdfghjklmnpqrstvwxz")
(defparameter *base26-en*
"abcdefghijklmnopqrstuvwxyz")
(defparameter *base30-en*
"0123456789bcdfghjklmnpqrstvwxz")
(defparameter *base36-en*
"0123456789abcdefghijklmnopqrstuvwxyz")
(defvar *digits* *base26-en*)
(defun weight (digit)
(1+ (position digit
*digits*
:test #'char-equal)))
(defun digit (weight)
(char *digits* (1- weight)))
(defun encode (number)
(loop
with d = ()
with m = (the (integer 0) number)
with k = (length *digits*)
with f = (lambda (x) (1- (ceiling x)))
for p = m then q
until (zerop p)
for q = (funcall f (/ m k)) then (funcall f (/ p k))
for a = (digit (- p (* k q)))
do (push a d)
finally (return (concatenate 'string d))))
(defun decode (numeral)
(loop
with value = 0
with radix = (length *digits*)
for rindex = (1- (length numeral)) then (1- rindex)
for digit across numeral
do (incf value (* (weight digit)
(expt radix rindex)))
finally (return value)))
(defun lessp (&rest numerals)
(apply #'<
(mapcar #'decode
numerals)))
(defun digit-sum (numeral)
(reduce #'+ numeral :key #'weight))
;;;; Tests
(let ((subject ""))
(assert (= 0
(decode subject))))
(let ((subject 0))
(assert (string= ""
(encode subject))))
(let ((subject "a"))
(assert (= 1
(decode subject))))
(let ((subject 1))
(assert (string= "a"
(encode subject))))
(let ((subject "z"))
(assert (= 26
(decode subject))))
(let ((subject 26))
(assert (string= "z"
(encode subject))))
(let ((subject "hardwork"))
(assert (= 64779504723
(decode subject)))
(assert (= 98
(digit-sum subject))))
(let ((subject 64779504723))
(assert (string= "hardwork"
(encode subject))))
(let ((subject "knowledge"))
(assert (= 2414455635571
(decode subject)))
(assert (= 96
(digit-sum subject))))
(let ((subject 2414455635571))
(assert (string= "knowledge"
(encode subject))))
(let ((subject "attitude"))
(assert (= 14452231825
(decode subject)))
(assert (= 100
(digit-sum subject))))
(let ((subject 14452231825))
(assert (string= "attitude"
(encode subject))))
(assert (lessp "attitude" "hardwork" "knowledge"))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment