# A Simple Function for Formatting Currency

Programmers are often called upon to present numeric quantities formatted as money. Conceptually, this is not a tough job. It's a simple matter of generating a formatted string that corresponds to a value stored in a numeric variable.

There are complexities, of course. For example, sometimes the fractional part is truncated and sometimes it is rounded according to specific rules. There are many international currency types and many different symbols to represent them. You can't even be sure how many decimal places to use. European currencies are customarily formatted with two decimal places, but many Arab currencies require three decimals for fractional parts.

In America, commas group digits in threes and the dot is used to separate whole dollars from cents. In much of Europe, the punctuation symbols are reversed. But that's just the beginning. In India, digits are grouped in pairs, and sometimes in trios. The user who sees` Rs3,25,84,729.25 `on an e-banking display screen has no trouble parsing the amount as 3 crores, 25 lakhs, 84,729 rupees, and 25 paise.

Programmers must also contend with different ways of representing negative amounts and even the placement of currency symbols before or after numeric digits — with or without a whitespace buffer.

Clearly, programmers who deal with multiple currencies must be prepared to contend with substantial complexity. In the C and C++ world, they logically start with locales. Locales are not to my taste, however. My experience is that they lead to low-level solutions that can be hard to write, read, debug, and maintain. That's what inspired me to search for an alternate solution to the money-formatting problem.

### Learning from the Past

The first programming languages I learned were Fortran and Cobol. I frequently used picture clauses in my programs. They are simple to define and use, and they provide many formatting options. Picture clauses have worked well for decades, but for some reason, they are not part of the C++ or C library. I decided to base my C/C++ currency-formatting function on Cobol's picture clauses.

The first challenge I faced was to choose a name for my function. I settled on `mnyfmt`, which is a sort of tribute to `strlen`. Like `strlen`, `mnyfmt` is a six-letter name that starts by specifying the object the function acts upon, then describes the action it performs.

Next, I had to figure out how to round numbers. I discovered that truncation is one of more than a dozen options. I learned that bankers use a special rounding scheme called "round half to even," in which rounding goes to the closer integer number, but halves always round to an even number. For example, -12.63 rounds to -13 and -12.50 rounds to -12, but +13.50 rounds to 14.

Handling so many rounding schemes is overwhelming…so I decided to decide to set the problem aside. My function does not accept a floating-point value as an argument, but instead accepts two integer parameters. One is the integer part of the number to format, and the other is the fractional part. Programmers must do their own rounding before calling my function. The invocation reads `mnyfmt(12,50)` instead of `mnyfmt(12.50)` — note the comma that separates the two numbers. That's not a decimal point.

My first implementation was a C++ template function that received a `std::string` argument. However, I discovered that I was not using any templates, nor any `std::string` functionality, so I replaced the C++ `std::string `with a regular zero-terminated character array. I also added a parameter to mark the fractional separator. In my test programs, I used commas and dots, but there are situations where other separators could be useful.

At this point, the function prototype looked like this:

```char* mnyfmt(char *fmtstr, char dec, long intpart, int fractpart);
{
{ // test.overwrite
typedef struct struct_overwrite
{
char bytes_8[8]; // 64 bits: probably aligned
int int_neg; // -1 usually has all its bits equal to 1
} overwrite;
overwrite o = {'1','2','3','4','5','6','7','\0',-1};
assertTrue(8-1==strlen(o.bytes_8) && o.int_neg == -1);
strcpy(o.bytes_8, "1234567.."); // 2 more bytes...
assertTrue(9==strlen(o.bytes_8));
assertFalse(o.int_neg == -1 && "Adjacent memory overwritten ");
assertTrue(o.int_neg != -1);
assertTrue(CHAR_BIT == 8 && "8 bits bytes required");
}
}
```

I decided to use only one `char*` argument because I know that C strings are problematic when dealing with limited memory. For example, field `bytes_8` can hold only eight characters. When 10 are copied into it, the last two overwrite whatever values are stored after `bytes_8` — in this case, changing the value of the field `int_neg`. This type of error is particularly difficult to catch.

### Refining the Function

When the string that contains the picture clause is also the place where the formatted value will reside, the programmer needs to ensure that this variable is large enough to hold the resulting value. For most applications, a string of 96 or 128 bytes will be big enough. For what it's worth, you can represent the U.S. national debt of \$14 trillion with just 16 digits, including two for the cents.

Best practices call for the construction of tests along with code. That's why my code is peppered with `assertTrue` and `assertFalse `statements. They mimic the assertions used in JUnit, the test framework for Java. In the code shown here, they simply output the condition tested when the assertion fails.

Earlier versions of `mnyfmt` returned a pointer to the formatted string, mimicking the behavior of `strcpy`. But it turns out that it is more useful if a pointer to the first significant digit is returned, so the same picture clause can be used to format a small value like 1235.87 or a huge one like 123456789.88. `mnyfmt` always uses the hyphen as the negative sign, and it replaces a 9 in the format string. The only character in the format string that ever gets changed is a 9.

As `mnyfmt` replaces each 9 in the format string with the corresponding digit, sometimes the result begins with a decimal separator. This special case should be handled by the programmer as there is no generalized solution that can be applied by `mnyfmt`.

### More Insights

 To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.

# First C Compiler Now on Github

The earliest known C compiler by the legendary Dennis Ritchie has been published on the repository.

Quick Read

# HTML5 Mobile Development: Seven Good Ideas (and Three Bad Ones)

HTML5 Mobile Development: Seven Good Ideas (and Three Bad Ones)

Quick Read

# Building Bare Metal ARM Systems with GNU

All you need to know to get up and running... and programming on ARM

Quick Read

# Amazon's Vogels Challenges IT: Rethink App Dev

Amazon Web Services CTO says promised land of cloud computing requires a new generation of applications that follow different principles.

Quick Read

# How to Select a PaaS Partner

Eventually, the vast majority of Web applications will run on a platform-as-a-service, or PaaS, vendor's infrastructure. To help sort out the options, we sent out a matrix with more than 70 decision points to a variety of PaaS providers.

Quick Read

More "Best of the Web" >>