Diatribe Regarding Use of Floating Point Types to Represent Monetary Quantities

"... The king was in his counting house, counting out his money,
The queen was in the parlor, eating bread and honey. ..."
    -- from a nursery song
The class definition problem on the final included a price member that
represented a money amount. In the answer key, the type used was "double".

I was dismayed by that, and by the apparent likelihood that many
instructors choose to have students represent money amounts with
the double type-- presumably because it seems like an easy way
to represent the cents part of dollars-and-cents.

Let me put this as delicately as I can, using all the diplomacy
that I'm known for:

	This is wrong, Wrong, WRONG, ***W*R*O*N*G***.

First of all, double and its puny sidekick float were never ever
intended to be used for quantities that involve COUNTING. They
are meant for quantities that derive from MEASUREMENT and
therefore are inherently approximations and associated
with a certain PRECISION.

MONEY is not measured. It is COUNTed. That's why the people
on the front lines of money management are called acCOUNTants.
Integers are for counting. That's why they're essentially the
signed versions of COUNTING numbers, numbers so called because,
well, they're for counting.

The source of confusion is that damn decimal point and the two
digits that go beyond it, representing cents.

Let's play some harp music and go back, back into the misty mists
of a different time (but the same galaxy) .....

Once upon a time, back when the youngsters in this department were
in diapers, we used a highly civilized language called PL/I. This
was before the discovery of TYPES-- in those days (realize, this
is the era of Gerald Ford, younguns) we had ATTRIBUTES. Among these
attributes were
	FLOAT(n)		/* n digits of precision */
  and
	FIXED DECIMAL(n,m)	/* n digits total, m after the decimal point */

Sheee-it. We even had computers that had Decimal Arithmetic instructions.

Well, back then if you had to represent money like your salary
you could use attributes like
	FIXED DECIMAL(7,2)
or, for, say the national debt,
	FIXED DECIMAL(15,2)

Then along came the 8080 instruction set and low-level languages like C
and all those attributes went the way of disco, leisure suits, and
peanut farmer presidents.

And so here we are, THIRTY years later, wondering how to map
FIXED DECIMAL(15,2) to the C++ primitive types.

Yes, there's a decimal point. But double/float is not the answer.

There are actually two possible answers:
	a) use int and count your pennies-- yes, a penny saved
	   is a penny earned and if you need to print a somewhat
	   nice looking int-COUNT of pennies just write:
		cout << "$" << (x/100) << "." << (x%100<10?"0":"") << x%100;
	   Messy? Yes. But if you don't like it, sign the petition to bring
	   back PL/I at http://www.bringbackpl1.org/
	   It is a nice use of the conditional expression, though, no?

	b) take advantage of the poverty of C++'s primitive types and
	   use this as a perfect opportunity to introduce a great
	   example for class definition -- define a money class
	   (as countless others have done before you)

I conclude this tirade (is anyone still with me here?) with an
illustration of why both Bill Gates and Warren Buffet would be
appalled to learn that some in Brooklyn College use double for
representing money.

Below is a program that starts with a quantity roughly equal
to their reputed worth (at least before the current meltdown)
and adds $100 -- one penny at a time -- to this quantity.
It turns out that there is a 0.1% error. Geez, 0.1% of
$500,000,000 is $500,000. Not quite up to Madoff standards
but I doubt that Gates or Buffet would like any of their money
managers to have an error like that.

Now, please, before you counter with the defense that double
will do just fine with mom-and-pop shop accounting, let me
remind you that even a small discrepancy can send accountants
into a tizzy (things ARE supposed to balance you know) and
furthermore, the example below was just one I happened to
construct-- there could well be similar or worse ones involving
less stratospheric dollar amounts. The point is, using double in
this sort of application is unstable and inappropriate and should
never be taught.

	-- David A.

------------------------------------------------------------------------------

LINUX> cat b2.cpp
#include 
#include 
using namespace std;

int main() {
	double	initialBalance,runningBalance,amountAdded;

	// Warren's or Bill's worth: 500,000,000,000.00: half a trillion dollars and one cent

	initialBalance = 500000000000.01; // 500,000,000,000.01: half a trillion dollars and one cent
	runningBalance = initialBalance;

	for (int i=0; i<10000; i++) {	// add ten thousand pennies ($100)
		runningBalance+=0.01;
		amountAdded+=0.01;
	}

	cout << endl << endl;
	cout << "  initialBalance=" << setprecision(15) << initialBalance << " (original)" << endl;
	cout << "  runningBalance=" << setprecision(14) << runningBalance << " (after adding)" << endl << endl;

	cout << "runningBalance-initialBalance=" << setprecision(5) << left <<  (runningBalance-initialBalance) << " (difference after adding)"<< endl;
	cout << "                  amountAdded=" << setprecision(8) << amountAdded << " (independent sum of what was added)"<< endl << endl;

	double discrepancy= (runningBalance-initialBalance)-amountAdded;
	cout << "  discrepancy=" << setprecision(1) << discrepancy << endl;
	cout << " %discrepancy=" << setprecision(1) << 100.0*discrepancy/amountAdded << endl;

	return 0;
}
LINUX> a.out


 initialBalance=500000000000.01 (original)
 runningBalance=500000000100.11 (after adding)

runningBalance-initialBalance=100.1 (difference after adding)
                 amountAdded=100 (independent sum of what was added)

 discrepancy=0.1
%discrepancy=0.1
LINUX>








Amazing! A Belorussian translation.