lib/decimals.ss
```(module decimals mzscheme

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

(provide/contract
[number->decimal-string
;; convert a number into a decimal string
(number? . -> . any)]
[number->format-decimal
;; convert a number into a formatted decimal string
((flat-named-contract "<Real or Rational>"
(lambda (x)
(or (inexact? x) (integer? x) (real? x))))
natural-number/c
. ->d .
(lambda (_ n) ;; is the decimal point at the right place in the string
(lambda (str)
(and (string? str)
(char=? (string-ref str (- (string-length str) n 1)) #\.)))))]
[integer->format-decimal
;; convert a number into a formatted decimal string
(integer?
natural-number/c
. ->d .
(lambda (_ n) ;; is the decimal point at the right place in the string
(lambda (str)
(and (string? str)
(char=? (string-ref str (- (string-length str) n 1)) #\.)))))])

;; Number N -> String
;; turn the number x into a string with num digits after the decimal point
(define (number->format-decimal x num)
(if (integer? x)
(integer->format-decimal x num)
(let* ([str (number->decimal-string x)]
[split (regexp-match "([0-9]*)\\.([0-9]*)" str)])
(cond
((pair? split)
(format "~a.~a" (cadr split)
(else
(error 'number->format-decimal
"whoops, can't handle this: ~a -> ~a"
x split))))))

;; Integer -> String
;; As above, but just for integers.
(define (integer->format-decimal n num)
(format "~a.~a" n (make-string (inexact->exact num) #\0)))

; ---------------------------------------------------------------------------
; Number -> String
; turns a number into a string with decimal representation
; Matthew's code
(define (number->decimal-string x)
(cond
[(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)))]
[else
(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 5-power)).
;; Print number as decimal.
(let* ([10-power (max 2-power 5-power)]
[scale (* (expt 2 (- 10-power 2-power))
(expt 5 (- 10-power 5-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)
(string-append
(make-string (- len orig-len) #\0)
s)
s)])
(format "~a~a.~a"
(if (negative? n) "-" "")
(substring padded-s 0 (- len 10-power))
(substring padded-s (- len 10-power) len)))
;; d has factor(s) other than 2 and 5.
;; Print as a fraction.
(number->string x)))))))])))
```