rounding and formatting with printf

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
0.699999999999999999989157978275

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;
000000000011124

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;
0000011124

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!

Advertisements
This entry was posted in Uncategorized. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s