Edit

thodg/cl-positional-numbers

Branch :

  • Properties
  • Git HTTP https://git.kmx.io/thodg/cl-positional-numbers.git
    Git SSH git@git.kmx.io:thodg/cl-positional-numbers.git
    Public ? true
    Name
    Description

    Positional numbers notation for Common Lisp.

    Users
    -
    +
    thodg
    Tags

  • positional.lisp
  • (in-package :cl)
    
    (defpackage :positional
      (:use :cl)
      (:export
       #:*integer-base*
       #:integer-base
       #:base-parse
       #:base-positional
       #:parse
       #:positional))
    
    (in-package :positional)
    
    (defgeneric base-parse (base input))
    (defgeneric base-positional (base number))
    
    (defvar *integer-base*
      "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz")
    
    (defun integer-base (base)
      (cond ((< base (length *integer-base*))
             (subseq *integer-base* 0 base))
            (t
             (error "Undefined integer base ~D" base))))
    
    #+nil (integer-base 10)
    #+nil (integer-base 16)
    
    (defmethod base-parse ((base integer) input)
      (base-parse (integer-base base) input))
    
    (defmethod base-parse ((base string) (input string))
      (let ((base-len (length base))
            (input-len (length input))
            (result 0)
            (i 0))
        (loop
           (unless (< i input-len)
             (return))
           (let* ((char (char input i))
                  (pos (position char base :test #'char=)))
             (unless pos
               (error "Invalid char ~S for base ~S." char base))
             (setf result (+ (* result base-len) pos)))
           (incf i))
        result))
    
    (defun parse (input &optional (base 10))
      (base-parse base input))
    
    #+nil (parse "123")
    #+nil (parse "DEADBEEF" 16)
    
    (defmethod base-positional ((base string) (number integer))
      (let* ((base-n (length base))
             (out-n (ceiling (log number base-n)))
             (out (make-string out-n :initial-element (char base 0)))
             (i (1- out-n)))
        (loop
           (when (= number 0)
             (return out))
           (when (< i 0)
             (error "bad math"))
           (multiple-value-bind (q r) (floor number base-n)
             (setf number q
                   (char out i) (char base r)))
           (decf i))))
    
    #+nil (base-positional (integer-base 16) 100)
    
    (defmethod base-positional ((base integer) number)
      (base-positional (integer-base base) number))
    
    (defun positional (number &optional (base 10))
      (base-positional base number))
    
    #+nil (positional 123)
    #+nil (positional 3735928559 16)