Floating Point Currency

See also FloatingPointFractions.

Refers to the use of floating-point types (float or double in CeeLanguage/CeePlusPlus/JavaLanguage/etc.) to store currency values, especially whenever the IeeeSevenFiftyFour floating point standard is used. As IEEE 754 is a binary (radix-2) standard; it cannot represent arbitrary decimal fractions exactly. Only those fractions whose denominator is a power of 2 (1/2, 3/8, 23415/65536, etc.) can be represented exactly; all other rational fractions must use a repeating binary. 0.1 in decimal is 0.00011001100110011001100110011 in binary, with the "0011" repeated forever.

This can lead to all sorts of errors in programs which do financial analyses.

Decimal Math

I have seen "decimal libraries" that seem better for currency than floating point. They perform the math more like we did in school. They are less efficient than floating point because the calculations are done in base 10 instead of the base 2 that machines prefer. But the added accuracy can often justify it.

Although some languages have decimal math built in, the add-on decimal libraries often use strings to store the numbers. This allows hundreds of places of precision if need be, although usually an upper limit of say 20 decimal places is selected as the (overridable) default.

About once or twice a year I encounter problems with floating point in calculating currency or business rates, and require ugly code to work around it. Being a few pennies off can cause significant accounting problems. Accountants cannot lose pennies. There have been scams where pennies were siphoned off of millions of accounts such that no one account lost more than a few cents, yet a crime involving many thousands of dollars was committed.

-- top

While this has been the topic of several movies, I don't know of an actual instance where this actually happened.

CobolLanguage has native monetary types, and is perhaps one of the reasons for its endurance in finance and accounting.

You have NotaNumber $ on Your account ;)

Gaming systems, especially larger casino environments with thousands of slot-type machines, provide endless amusement for math blunder watchers. Most of our "primitive" gadgets transmit meter readings using BCD (BinaryCodedDecimal?) and our dollar/cents computations use special math routines using BCD/business math. Iterative stuff. No rounding except as sanctioned by design.

In the newer (NewImproved?) units, there is a temptation (an iterative temptation, actually) to "use modern floating point" for our accounting/reporting requirements. And two or three times a year we have to demonstrate the error-prone nature of that beast.

It gets better. Gaming meter values have one thing that arbitrary-precision decimal numbers don't: a rollover point (which also may vary from one value to the next), so that for example (250000.00 - 350000.00) gives 900000.00. It gets even more interesting when you're combining meter values with different rollover points. Finally, multiplication and division of two meter values is utterly meaningless. At least nobody I know of has tried to drag multiple currencies into it.
Solution: Use fix-point math, which boils down to simple integer math on cents (or whatever the smallest unit of the currency involved is). This way, everything is efficient, yet no penny is lost ever.

Nope. Fixed point math forces rounding (and often the wrong kind of rounding) on each calculation. Just because you can't shave a penny into quarter pennies doesn't mean your interest calculation should throw all quarter pennies away.

So what alternative is there?

Arbitrary precision decimal math. It's what banks and insurance companies use.

Let's say someone makes a single deposit of $1 000.01 into a 3.33% APY 1-year CD account. (And to make the math simpler, let's say there's another three-hundred-million-dollar "internal account" at the bank that is used to make these interest payments). (Would slight different starting numbers make the effect more dramatic?)

With floating-point math, Somehow we've lost a fraction of a penny somewhere.

With fixed-point math: The fixed-point math is the only way I know to guarantee that the total value of 2 accounts doesn't change when I move any quantity from one to the other.

Please tell me about any alternative.

One approach that seems to work fairly well for non-large floating-point numbers is to round after each and every calculation. This way, errors don't accumulate. It still tends to have problems if you do division. I've seen fudge factors added to division results to make sure rounding near 50-cent fractions happens as expected.

  x = getNumberFoo()
  y = getNumberBar()
  a = x + y
  a = round(a, 2)	// round to pennies
  b = a * 1.10
  b = round(b, 2)  
  c = b / 5.0
  c = c + 0.00000001	// fudge factor
  c = round(c, 2)

A good article on this and related subjects is at http://www.codeproject.com/dotnet/ExtremeFloatingPoint1.asp?df=100&forumid=172674&exp=0&select=1121627

It's DotNet-centric, but the principles are applicable elsewhere.

CommonLisp's rational numbers seem like a good solution to the accuracy problem.
-- Excel uses floating point currency.

-- Foreign Exchange currency conversions are specified by explicit conventions to use Decimal Fixed Point Arithmetic (not integer arithmetic). This ensures that all rounding errors are consistent. The 8 place decimals either derive from paper calculations or some well-known mini computer system. However, most people just use Excel. This ensures that all rounding errors are consistent...

Reminds me of Consistent Mounds of Muck (CmmAcronymAlternatives)

External Links:
See also:
CategoryDevelopmentAntiPattern CategoryMath

EditText of this page (last edited August 14, 2010) or FindPage with title or text search