How to convert to dollars and cents - rounded and with comma separators

advertisements

The following code excerpt will add up a column of numbers and yield results that are several decimal points long. Could anyone please give an example of how to convert the results into dollars and cents, rounding to the second decimal -- i.e., 1.555 should round up to 1.56; and 1.554 should round down to 1.55. Also, I'd like to insert comma separators every three digits to the left of the decimal point -- e.g., 1124412.555 should be converted to 1,124,412.56.

(let ((sum 0))
  (while (re-search-forward "[0-9]*\\.?[0-9]+" nil t)
    (setq sum (+ sum (string-to-number (match-string 0)))))
  (insert "\n\nTotal Hours:  " (format "%s" sum ))
  (insert "\n\nTotal Fee for Services Rendered:  " (format "%s" (* 250 sum)))
  (insert "\n\nOne-third of total fee:  " (format "%s" (/ (* 250 sum) 3))))

2.0
0.2
0.1
4.75
4.0
6.5
0.1

Total Hours:  17.650000000000002

Total Fee for Services Rendered:  4412.500000000001

One-third of total fee:  1470.8333333333337


Based upon the answers provided by @Drew and @abo-abo, the following is a revised draft that now appears to be working correctly:

08884.75585
78774.1235
6.545

Total Hours:  87,665.42

Total Fee:  $21,916,356.09

One-Third:  $7,305,452.03

(let ((sum 0))
  (while (re-search-forward "[0-9]*\\.?[0-9]+" nil t)
    (setq sum (+ sum (string-to-number (match-string 0)))))
    (setq total-hours (group-number (number-conversion (format "%s" sum ))))
    (setq services-rendered (group-number (number-conversion (format "%s" (* 250 sum)))))
    (setq one-third (group-number (number-conversion (format "%s" (/ (* 250 sum) 3)))))
  (insert "\n\nTotal Hours:  " total-hours)
  (insert "\n\nTotal Fee:  $" services-rendered)
  (insert "\n\nOne-Third:  $"  one-third) )

;; @abo-abo
(defun number-conversion (str)
  (let ((x (read str)))
    (format "%0.2f" (* 0.01 (round (* 100 x)))) ))

;; http://www.emacswiki.org/emacs/ElispCookbook#toc23
(defun group-number (num &optional size char)
    "Format NUM as string grouped to SIZE with CHAR."
    ;; Based on code for `math-group-float' in calc-ext.el
    (let* ((size (or size 3))
           (char (or char ","))
           (str (if (stringp num)
                    num
                  (number-to-string num)))
           (pt (or (string-match "[^0-9a-zA-Z]" str) (length str))))
      (while (> pt size)
        (setq str (concat (substring str 0 (- pt size))
                          char
                          (substring str (- pt size)))
              pt (- pt size)))
      str))


I believe abo-abo's (* 0.01 (round (* 100 x))) can lead to surprises in corner cases (because 0.01 cannot be represented exactly in the internal floating point representation). A simpler solution for the rounding is:

(format "%0.2f" x)