I’ve committed and seen several rounding / formatting bugs this week, so I had a look at how to do this right. It very important to do rounding and formatting correctly when dealing with money.
The problem is that floats and doubles represent most decimal fractions imprecisely,
the wrong sort of rounding can turn 0.999999 cents into 0 cents:
> printf “%.30f”, 0.7
It turns out that good old printf/sprintf/snprintf is perhaps the best way to round and format floats. The formats work much the same in C, perl, sh, python, php, etc, which is nice. `man 3 printf` for all the gory details, but it’s not much fun reading it!
An example, to multiply an amount by 100 (dollars to cents) and print it rounded to the nearest cent, right-justified and 0 padded to 15 chars, the following line of perl works nicely:
> printf “%015.0f\n”, 111.2399 * 100;
Too easy, really!
Breaking it down:
%f – print a float
%.0f – … with 0 decimal places, rounds to the nearest int
%15.0f – … right aligned and padded with spaces in a 15 character field
%015.0f – … padded with 0 digits
You can even specify the field width as an argument:
> $width = 10;
> printf “%0*.0f\n”, $width, 111.2399 * 100;
Here ends the lecture on printf. 🙂
P.S. other good rounding functions in C are C99’s round(3) and floor(3). In C89, you can round to nearest with floor(f + 0.5). Don’t use (int)(f + 0.5), it behaves differently for negative numbers, and don’t use printf(“%d”, f) to round either!