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

_numtostring



>I need to turn an integer into a string -
>
>Does anyone out there know how to make the trap _numtostring work?
>
>Format is too slow.  Without _numtostring it looks like I will have to iterate
>over the digits of an integer and then push the individual chars into
> a vector. 
>
>thanks
>Daniel

Hey, what timing! I just happened to have a similar need for speed yesterday.
You're right - format (and prin1-to-string) is much too slow on floats.
The following code is about 5 times faster. It uses #_NumToString via the
macro with-returned-pstrs. (I tried macro-expanding the code and hand-tuning it
since I knew that the number will always be 12 characters or less, but the
code actually got slower! Why...?) Note that this only works for numbers less
than 2^32; larger numbers are subjected to mod 2^32. 

  ;; "magnitude of the integer is converted modulo 2^32"
  ;; -- Inside Macintosh I-490
  ;; so result will never be longer than 12 characters

Also note that the definition of the trap _numtostring in packages.lisp
has a spelling error: thenum should be the-num (or vice versa).

I have not tested this code extensively yet; there may be bugs. No warrantees
expressed, implied, impressed, replied, etc. Enjoy!

(deftrap _numtostring ((thenum :signed-long) (thestring (:pointer (:string 255))))
   nil
   (:no-trap (ccl::%gen-trap #xA9EE :d0 the-num :a0 thestring :word 0)))
                                           ^ should be thenum

(defun integer-to-string (number)
  "Converts an integer to a string, using the toolbox."
  (with-returned-pstrs ((string ""))
    (#_numtostring number string)
    (%get-string string)
    ))

(defun float-to-string (number fractional-digits)
  "Converts a floating-point number to a string, ~
   with a given number of digits following the decimal point."
  (let* ((integral (floor number))
         (int-string (integer-to-string integral)))
    ;; dont mess around with fractions if you dont have to
    (if (zerop fractional-digits)
      (concatenate 'string int-string ".")
      (let* ((fractional (round (* (expt 10 fractional-digits)
                                   (- number integral))))
             (fract-string (integer-to-string fractional))
             ;; pad fraction with enough zeros to separate it from decimal
             (pad-string (make-string (- fractional-digits (length fract-string))
                                      :initial-element #\0)))
        (concatenate 'string int-string "." pad-string fract-string)
        ))))