I’m Embarrassed!
October 4, 2016
The bug is easy enough to fix. Multiply the input number by 100, round, then use quotient and modulo to split the dollars and cents; the formatting is unchanged from the previous solution:
(define (dollar x)
(define (commas n)
(let ((xs (reverse (map number->string (digits n)))))
(let loop ((xs (drop 3 xs)) (zs (reverse (take 3 xs))))
(if (null? xs) (apply string-append zs)
(loop (drop 3 xs) (append (reverse (take 3 xs)) (list ",") zs))))))
(define (zero n)
(if (zero? n) "00"
(if (< n 10) (string-append "0" (number->string n))
(number->string n))))
(let* ((n (inexact->exact (round (* x 100))))
(dollars (quotient n 100))
(cents (modulo n 100)))
(string-append "$" (commas dollars) "." (zero cents))))
This correctly solves Matthew’s bug report:
> (dollar 1234567.9999) $1,234,568.00
You can run the program at http://ideone.com/xg7nFo.
Updated my python solution so it rounds instead of truncating.
def dollars(n): '''Format a number as a dollar amount string''' n = n*100 if n % 1 >= 0.5: n = int(n) + 1 else: n = int(n) s = str(n) i, d = s[:-2], s[-2:] l = [i[(c-3 if c >= 3 else 0):c] for c in range(len(i),0,-3)] o = '.'.join((','.join(reversed(l)),d)) return ''.join(('$', o)) >>> dollars(1234567.9999) '$1,234,568.00' >>> dollars(1234567.9950) '$1,234,568.00' >>> dollars(1234567.9949) '$1,234,567.99' >>> dollars(1234567.9900) '$1,234,567.99' >>> dollars(1234567.949) '$1,234,567.95' >>> dollars(1234567) '$1,234,567.00'Sorry about that. I find it’s easy to get these simple problems wrong, just by not paying enough attention. New solution looks good anyway.