[plt-scheme] Printing

From: Matthias Felleisen (matthias at ccs.neu.edu)
Date: Sat Oct 15 09:39:31 EDT 2005

This is a part of my collects, with contracts and friends, used in a  
quotster and stock evaluation program. I have meant to put such  
"contracted" code up at Planet for a while, but time just disappears.  
-- Matthias

(module decimals mzscheme

    (lib "string.ss" "srfi" "13")
    (lib "contract.ss"))

   ;; Number Natural -> String -> Boolean
   ;; is the decimal point at the right place in the string
   (define (post-number->format-decimal _ n)
     (define (formatted-number-as-string str)
       (and (string? str)
            (char=? (string-ref str (- (string-length str) n 1) #\.))))

   ;; Any -> Boolean
   (define (real-or-rational x)
     (or (inexact? x) (integer? x) (real? x)))


     ;; convert a number into a formatted decimal string
     ;; given: 10.321 wanted: "10.32"
     ((flat-named-contract 'real-or-rational real-or-rational)
      . ->d .

     ;; convert a number into a decimal string
     (number? . -> . string?)])

   ;; Number N -> String
   ;; turn the number x into a string with num digits after the decimal  
   (define (number->format-decimal x num)
     (let ([split (regexp-match "([0-9]*)\\.([0-9]*)"  
(number->decimal-string x))])
       (format "~a.~a" (cadr split) (string-pad-right (caddr split) num  

   ; Number -> String
   ; turns a number into a string with decimal representation
   ; Matthew's code
   (define (number->decimal-string x)
       [(or (inexact? x) (integer? x)) (number->string x)]
       [(not (real? x)) ;; complex
        (let ([r (real-part x)]
	     [i (imag-part x)])
	 (format "~a~a~ai"
                  (number->decimal-string r)
                  (if (negative? i) "" "+")
                  (number->decimal-string i)))]
        (let ([n (numerator x)]
              [d (denominator x)])
          ;; Count powers of 2 in denomintor
          (let loop ([v d][2-power 0])
            (if (and (positive? v) (even? v))
                (loop (arithmetic-shift v -1) (add1 2-power))
                ;; Count powers of 5 in denominator
                (let loop ([v v][5-power 0])
                  (if (zero? (remainder v 5))
                      (loop (quotient v 5) (add1 5-power))
                      ;; No more 2s or 5s. Anything left?
                      (if (= v 1)
                          ;; Denominator = (* (expt 2 2-power) (expt 5  
                          ;; Print number as decimal.
                          (let* ([10-power (max 2-power 5-power)]
                                 [scale (* (expt 2 (- 10-power 2-power))
                                           (expt 5 (- 10-power  
                                 [s (number->string (* (abs n) scale))]
                                 [orig-len (string-length s)]
                                 [len (max (add1 10-power) orig-len)]
                                 [padded-s (if (< orig-len len)
                                                (make-string (- len  
orig-len) #\0)
                            (format "~a~a.~a"
                                    (if (negative? n) "-" "")
                                    (substring padded-s 0 (- len  
                                    (substring padded-s (- len 10-power)  
                          ;; d has factor(s) other than 2 and 5.
                          ;; Print as a fraction.
                          (number->string x)))))))])))

Posted on the users mailing list.