CMoney (Jan 27)

This past week our staff rewrote CMoney, the class that stores money values for Goldenseal accounting software. Translating a text string into a CMoney used to take 100 lines of code. Now it’s 2 lines.

When we started work on Goldenseal, personal computers were still shifting from 16-bit to 32-bit processors. Those (plus 8-bit characters) were the main data sizes, along with “floating point” numbers for decimals.

We first considered using floating point for money values, but floats have precision problems. Big numbers can get errors in the penny digits. They also were extremely slow back then.

32-bit integers can handle up to 4 billion, so they seemed possible at first. However, with pennies and negatives the cap is only $20 million. Unit costs and tax rates need fractional pennies, which shrinks capacity even further. 32 bits is just too small for practical money storage.

The next step up is 64-bit integers. They were exotic beasts at the time. Not part of the C++ standard. 64-bit required special libraries that faked it by using two 32-bit numbers. The math was hard to use, unreliable, and slow. Too flaky for accounting software.

Our staff finally built CMoney with two numbers: 32 bits for dollars, and 16 bits for pennies. A total of 24 bits, or 6 bytes in size. It gets up to $2 billion, and down to 1/100 of a cent. That was a reasonable size range for the US and Europe.

However, a few Goldenseal buyers were in countries with very small currency values. The app was too small for big overseas projects, in places with a currency unit worth a penny or less. The solution was to add an option to shift money decimals by 1, 2 or 3 places. It’s complicated code, but it met their needs.

On the opposite end, CMoney can handle 1/100 of a penny. It also stores percentages down to .0001%. Sadly, a few counties in Indiana have local income tax rates that need 5 decimal places (.00005%). Our payroll withholding can’t go there, so the software is wrong by a few cents per year.

Fast forward 30 years, and 64-bit numbers have become totally mainstream. Every OS added them years ago to get past the 4GB barriers for disk space and RAM. Now 64-bit is everywhere in the C++ standard, and fully supported.

For the past decade, we’ve considered switching CMoney to a single 64 bit value. This past week, our staff finally made the change. Math sure is easier without separate dollars and pennies!

The change gives CMoney more precision, and more capacity. It now goes down to 1/1,000 of a penny, or .00001%. One decimal smaller. Good enough for Indiana, or really small unit costs. Its maximum money value is $90 trillion. That’s 40x bigger than what Goldenseal can manage now, even with decimal shifting. If your country has inflation so bad that a house costs more than tens of trillions, you have bigger problems than just your accounting. If necessary, we can bring back decimal shifting, but it probably won’t ever be needed.

In fact, we probably won’t use the whole $90 trillion. Better to leave some space at the top, so there is less risk of math overflows. We may even add an option in Prefs to set the cap much lower. Whatever limit you want. That will prevent huge surprises when your cat sits on the keyboard. It will only affect data entry, not data storage.

Changing CMoney to 64 bits worth of millipennies was easy. It only took a few lines of code to switch to the new size. Rewriting all the math was a bit harder, but it was finished in a day. Most was obvious. CMoney source code is 1000 lines smaller now.

Unfortunately, this is accounting software. Almost every type of record includes some sort of money value. The jump from 6 bytes to 8 bytes changes the file size of almost everything. It took several days to revise code in 500+ files so they handle the increase. Everything now has an old size and a new one, since we still need to read existing Goldenseal files.

Even worse, many stored lists (arrays) include a money value. To handle the size change, we had to add an old-money version of each, plus some code to convert it to the new format. Those are finished, though we may have missed a few.

Right now we are testing the changes by converting our Goldenseal test file to the new format. It has some of every class, and any incorrect record lengths give error messages. Our staff probably has spend hundreds or thousands of hours over the years, diagnosing small file-length problems. We will be doing more of it for a while. Most likely a few more days.

TurtleSoft code can change like this because everything inside the database has a version number. Old data and new data live together peacefully inside a company file. More about that in the next post.

Dennis Kolva
Programming Director
TurtleSoft.com

Author: Dennis Kolva

Programming Director for Turtle Creek Software. Design & planning of accounting and estimating software.