[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: converting numbers to strings in arbitrary base (up to 36)

From: Pascal J. Bourguignon
Subject: Re: converting numbers to strings in arbitrary base (up to 36)
Date: Tue, 15 Mar 2011 20:15:23 +0100
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/23.2 (gnu/linux)

Mirko <address@hidden> writes:

> This is an elisp question:
> I can specify integers in base 2-36 using #xyr..., and I can read them from a 
> file.
> But is there a way to write an integer in arbitrary base (again, 2-36) to a 
> file?
> I looked at string-to-number, format, and calc
> In greater detail,
> I have a file where I want to keep a counter (in base 36).
> When needed, I want to open the file, read the number.
> Occasionally, I want to increment the number, and write it back out.
> I can handle reading and writing :-).  It is writing the base 36 that
> I don't know how to handle.

For bases eight, ten, and sixteen, you can use format:

    (format "#8r%o #10r%d #16r%x" 42 42 42)
    --> "#8r52 #10r42 #16r2a"

For the other bases, you must implement it yourself, or use
integer-to-base (from

(loop for b from 2 to 36
      collect (format  "#%dr%s" b (integer-to-base 42 b)))

--> ("#2r101010" "#3r1120" "#4r222" "#5r132" "#6r110" "#7r60" "#8r52"
     "#9r46" "#10r42" "#11r39" "#12r36" "#13r33" "#14r30" "#15r2C"
     "#16r2A" "#17r28" "#18r26" "#19r24" "#20r22" "#21r20" "#22r1K"
     "#23r1J" "#24r1I" "#25r1H" "#26r1G" "#27r1F" "#28r1E" "#29r1D"
     "#30r1C" "#31r1B" "#32r1A" "#33r19" "#34r18" "#35r17" "#36r16")

(defun integer-to-base (decimal base &optional width padchar
                                commachar comma-interval)
DO:      Convert  a decimal  value into  a string  contening the 
         same value expressed into the given base. 1<base<37.
         The optional WIDTH specifies the minimum length of the returned 
         string (0-left-filled), not counting a '-' sign.
    ;;TODO: Implement commachar, comma-interval
   ((not (integerp base))         (error "Invalid base (%S)." base))
   ((or (< base 2) (< 36 base))   (error "Invalid base (%d)." base))
   ((not (integerp decimal))      
    (error "For now, I only convert integer values.")))
  (let ((digits "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ")
        (buffer (make-string 32 ?0))
        (b 31)
        (sign "")
    (if (< decimal 0)
        (setq sign "-"
              decimal (abs decimal)))
    (while (< 0 decimal)
      (let ((digit   (% decimal base)))
        (aset buffer b (aref digits digit))
        (setq decimal (/ (- decimal digit) base)
              b       (- b 1))))
    (if width (if (< 32 width)
                  (setq sign (concat sign (make-string (- width 32) padchar))
                        width 32)))
    (concat sign 
            (if (and width (< (- 32 width) (+ 1 b) ))
                (substring buffer (- 32 width))
              (if (= b 31) "0" (substring buffer (+ 1 b)))))))

__Pascal Bourguignon__           
A bad day in () is better than a good day in {}.

reply via email to

[Prev in Thread] Current Thread [Next in Thread]