Subject: Re: format floats with commas - why not?
From: Erik Naggum <>
Date: 1997/08/12
Newsgroups: comp.lang.lisp
Message-ID: <>

| So: I can format a number with commification only with ~d (and ~r, ~b,
| ~o, ~x, as per CLtL2 22.3.3 p 585), but not with ~f or ~$. What is the
| reason for not having commification with floats? It would seem only
| natural to print large numbers like $1234567.89 as $1,234,567.89.

here's a shot.

(format nil "~/dollars/" 123456789.87) => "$123,456,792.00"
(format nil "~/dollars/" 123456789.87d0) => "$123,456,789.87"
(format nil "~/dollars/" 12345678987/100) => "$123,456,789.87"

note that 123456789.87 requires more significant bits than are available in
single-precision floats and that we suffer massive loss of precision in
floating point computations.  however, this function handles rationals
correctly, which the ~$ format control is not guaranteed to do, as in:

(format nil "~$" 123456789.87) => "123456790.00"
(format nil "~$" 123456789.87d0) => "123456789.87"
(format nil "~$" 12345678987/100) => "123456790.00"

(defun dollars (stream amount colon-p atsign-p
		&optional (width 0) padchar commachar)
  "Print an amount of dollars for humans to read.
The full form is ~width,padchar,commachar:@/dollars/, where width is the
minimum width of the field (default 0), padchar is the character used to pad
to the width on the left end, and commachar is the separator between each
group of three digits.
The @ modifier controls printing of the sign of positive amounts.  If
omitted, a positive value prints without a sign.  Otherwise, a positive
amount has an explicit + sign.
The : modifier controls the position of the sign and the padding.  If
omitted, the dollar sign is printed in the leftmost position, then any
intervening pad characters, then the signed value.  Otherwise, the sign
occupies the leftmost position, and the dollar sign follows any intervening
Copyright 1997 by Erik Naggum.  Any use is permitted provided that this
copyright notice is retained and that all changes are duly identified."
  (let* ((digits 
	  (multiple-value-bind (dollars cents) (floor (abs amount) 1)
	    (format nil "~,,V:D.~2,'0D" commachar dollars (round cents 0.01))))
	 (sign (if (minusp amount) #\- (if atsign-p #\+ nil)))
	 (padding (max 0 (- width 1 (if sign 1 0) (length digits)))))
    (format stream "~@[~C~]~V,,,VA~@[~C~]~A"
	    (if colon-p sign #\$)
	    padding padchar ""
	    (if colon-p #\$ sign)

404 Give me a URL I cannot refuse.