|
|
Adolfo Di Mare
|
An efficient and simple C++ class to handle money
quantities is presented. The class uses scaled
double 's to represent money data
variables.
|
Se presenta una eficiente y simple clase C++ para manipular datos que representan dinero. La clase se implementa usando números de punto flotante dobles. |
I use C to program information systems where handling money
quantities is quite common. Using double
's to
represent money quantities is not good enough, because decimals
are not represented correctly and sometimes round-off errors
occur. A while ago a friend of mine gave
me a very good idea to overcome this problem: he works using Canon
BASIC, and he has always used floor(double*100.0)
to
represent money quantities. Any amount is represented as a
double
with no fractional part. With this trick no
decimals are lost because the double
type, with its
15+
digit precision, is used as a compiler supported
long long
. You need to be careful when
multiplying and dividing, but in many applications these
operations are rare.
For example, $25.35 is represented as the double
2535.0
, using a scale factor of 100
(for
two decimal places). The problem I kept facing in my C programs
was to remember when to multiply by 100
and when not
to. For example, to add two double
's that represent
money quantities there is no need to multiply by 100
:
$25.35 + $35.75 <==> 2535.0 + 3575.0 == 6110.0 <==> $61.10
Also, one should never multiply by the scale factor when
multiplying a money
quantity:
$100 * (1.0+0.06) <==> 10000.0 * (1.06) == 10600.0 <==> $106
It is just too easy to forget to multiply by the scale factor when
using double
's as money
. We human beings
forget too much, so we need the computer to remember for us.
When I started programming in C++, I realized that a C++
money
class was the solution for these problems.
However, I needed my money
class to be as efficient
as possible; otherwise who would use it?
money
class
1234
will be
stored in a pair of bytes using the same bit pattern as the
0x1234
hexadecimal constant. As most computers use
eight bit bytes, each byte will hold two BCD digits. Many bit
patterns are not valid when interpreted as BCD numbers:
0xFFFF
, 0x0A0A
, 0x123A
, are
all invalid BCD quantities because in decimal notation we can use
only the digits 0...9
.
I chose not to use Borland's BCD class for many reasons. It does
not provide specific support to handle money quantities. For
example, whenever you multiply and divide two money
variables you have to figure out what happens with the remaining
digits that go further than the number of cents. The header file
in Borland C++ v2.0 sucks in the <iostream.h>
header file which slows down compilation quite a bit. I still
don't use streams, and I don't like to be forced to use them if I
don't have to. As much of the BCD library needs to be loaded when
using BCDs, this increases the size of executable files, which I
find unattractive. Finally, the source code for this class is not
included with the compiler (it is available at an extra charge); I
have learned to examine the source code for a library before using
it. The BCD class by Zortech shares all of these inconveniences.
In the Zortech C++ Tools package a money
class is
implemented, where a money quantity is a two member structure:
class money { long dollars; int cents; // ... };
In most implementations, a long
can hold only nine or
ten decimal digits, which means that the range of numbers that
this class permits is smaller the range granted by
double
's. Zortech's implementation is quite clean,
but nonetheless bulky (or bulkier than mine, if you prefer). This
class is efficient, because the operators are implemented using
integer arithmetic and each money
variable is quite
short.
I know these tools are good enough to handle money quantities.
Perhaps I didn't use them because I didn't write them. We
programmers like to use our own tools, and when the cost of
implementing them is not very big, we usually wind up rewriting
code. I feel also that my experience using scaled
double
's in C made me reluctant to use the available
options, because those implementations were not meant to solve
exactly my problem. I guess to be an inventor one needs to dislike
what is already available...
Also, I wanted my money
class to be portable, not
compiler vendor dependent.
money
class. This is
what I came up with:
money
class should be portable.
money
quantities.
money
quantities.
money
header file should be short.
money
data item.
These requirements are quite natural. Good object oriented
programming dictates that a class represents a concept that we
need to use in a straight-forward way; an efficient implementation
is always welcomed by any C++ programmer. Where I had to give in
was in the amount of storage that a money
variable
would use: eight bytes for most computers compared to six (25%
less) if one uses the Zortech implementation.
Listing 1 is the header file
"money.h"
which defines
and implements the money
class. You will find amusing
that all the methods in this class are inline
: I did
this to fulfill my
fifth requirement. There are many versions
of some of the arithmetic operators to cater for the various cases
that are usually found in real life programs.
The money
class permits a programmer to write
expressions such as the following:
In a nutshell, the programmer can freely mix money quantities with regular numbers to get the correct results. Furthermore, the compiler will warn the programmer when he tries to misusemoney mm,m = 1000; // I've got a thou' double tax = 0.23; // State Government of Insomnia m *= (1-tax); // This is what I have m = m+500; // Thanks, mommy... mm = 500; m = m + 1500 - (mm / m) * (1.0/3.0); // etc... printf("Salary = %10.2f\n", (double) ((10+mm)/m * m));
money
data items, as in:
Listing 2 is a test program for themoney m, mm; // ok double d = m*mm; // can't multiply moneys mm = d/m; // can't divide by money
money
class. You need to use your symbolic debugger
to see what is going on at each point in the program.
long
's,
but the difficulty in doing so stopped me from pursuing this
approach (note that the Zortech tools money
type is
implemented using integer arithmetic).
As I knew that a money
variable would be a
double
, the main problem to solve implementing this
class was to keep track of when to multiply by the scale factor
and when not to. This is accomplished by each of the overloaded
arithmetic operators. I also implemented the
money::FIX()
member functions to get rid of the
excess decimals whenever this is needed.
When the preprocesssor constant MONEY_ROUNDING
is
defined, the exccess decimals in a double
are rounded
when a double
is assigned to a money
variable. Otherwise the excess decimals are truncated:
The programmer cannot selectively choose whether to round or not case by case: it is an all or nothing affair because the decision must be made at compile time.money m(1.5199); // $1.52, when MONEY_ROUNDING money m(1.5199); // $1.51, when not MONEY_ROUNDING
The preprocessor constant MONEY_DECIMALS
defines how
many decimals a money
item has. The member function
money::SCALE()
is implemented using a preprocessor
trick that returns the scale factor used to multiply a
double
to make it a money
quantity. If
three decimals are needed for money
items, then the
scale factor would be 1,000 = 10^3
. In some
countries the inflation is so high that the number of decimals is
negative; in this case the scale factor would be a number less
than one. As money::SCALE()
is an inline
function, the compiler can optimize out the division by the scale
factor in some cases. If the programmer doesn't define
MONEY_DECIMALS
, then a default value of 2 decimals is
used. In my programs, I define MONEY_DECIMALS
before
including the <money.h>
file:
The vector constructor#define MONEY_DECIMALS 4 // must use a decimal number #include "money.h" // or TENPOW bombs.
money::money()
does not
initialize a money
item, because in many cases doing
so is wasteful. Money items can be regarded by the programmer as
regular numbers. The compiler should be able to optimize out this
constructor if it is used.
The class money
implements most arithmethic
operators, but it does not implement the following:
It just does not make sense to use them in a program; if you use them you will get a compile time error (a disatisfied programmer could add them to the class easily).money operator* (const money&, const money&); money operator/ (const double, const money&);
A careful examination of the implementation of each of the
arithmetic operators in file
"money.h"
will show that
the class is programmed to minimze the number of times that each
double
needs to be scaled up by the scale factor.
The comparison operators are defined only for money
items. This means that when a money
data type is
compared to a double
, the compiler will promote the
double
to a money
variable using the
constructor money::money(double)
. If this is not what
the programmer intended, an explicit typecast can be used:
The functiondouble d = 15.253; // 15.253 money m = 15.25; // $ 15.25 if (d == m) { // TRUE: d becomes money(d) } if (d == (double) m) { // FALSE: 15.253 != 15.25 }
flatten(money, cents, rounding)
is very
useful to round up a money quantity to the nearest value that can
be paid with coins. For example, in
Costa Rica there are no one cent
coins, because the smallest coin is worth 25 cents of a
colón (which we call a "peseta"). In the following example
a money
item is rounded up to pesetas:
The completemoney m = 125.80; // ¢ 125.80 colones money mm = flatten(m); // ¢ 125.75 colones
money
class is implemented in the header
file called
"money.h"
using
inline
functions, to permit the compiler to optimize
out any floating point operations when it can. I decided not to
provide more operators for money
items, because the
type converter money::operator double()
allows
the standard math functions to be used with money
items. The header file <money.h>
includes only
two files, <math.h>
and
<float.h>
, which have the prototypes for
functions floor()
, ceil()
,
fmod()
, and DBL_DIG
. If you want to, you
can declare every double
variable in
"money.h"
as a
long double
, to use bigger money
quantities.
As implemented, the money
class should be quite
portable because it does not make use of any odd C++ constructs.
Depending on the compiler being used, it is quite possible to
optimize out many of the inline
operators, and thus
yield efficient programs.
money
class is a tiny C++ class that lets the
programmer use money
items with ease. The
implementation is as efficient as using floating point values in
arithmetic expressions. There is no reason to prevent you from
using it right away.
money
Class
http://www.di-mare.com/adolfo/p/src
http://www.di-mare.com/adolfo/p/src/money.h
http://www.di-mare.com/adolfo/p/src/money.c
/* @(#) money.h Copymiddle 1991 Adolfo Di Mare */ /* */ /* Yet Another Money C++ Class */ /* */ /* Use freely but acknowledge author and publication. */ /* DO NOT SELL IT. The author reserves all rigths! */ /* email: adolfo@di-mare.com */ /* Compiler: Borland C++ v 2.0 */ /* [should work with Turbo C++] */ #ifndef _money_h #define _money_h extern "C" { // avoid type clashes with the C library #include <math.h> /* floor() */ #include <float.h> /* DBL_DIG */ } #ifndef MONEY_DECIMALS /* number of decimals in */ #define MONEY_DECIMALS 2 /* any money quantity */ #endif /* don't use parentesis! */ #define __VAL(n) n /* 1 level indirection */ #define TENPOW(n) __VAL(1.0e##n) /* Trick to yield 10^n */ #define MONEY_DIG DBL_DIG class money { public: static int decimals() { return MONEY_DECIMALS; } static int digits() { return MONEY_DIG; } static double SCALE() { return TENPOW(MONEY_DECIMALS); } money(); // do nothing constructor money(double); // constructor from double money(const money&); // copy constructor money& operator= (const money&); // copy operator money& operator= (double); // copy from double operator double() const; // convert to double int OK() const; // check money's invariant void FIX(); // get rid of unwanted decimals friend money operator + (const money&, const money&); friend money operator + (double, const money&); friend money operator + (const money&, double); friend money operator - (const money&, const money&); friend money operator - (double, const money&); friend money operator - (const money&, double); friend money operator* (const money&, double); friend money operator* (double, const money&); friend double operator/ (const money&, const money&); friend money operator/ (const money&, double); friend money operator% (const money&, const money&); // money * money is NOT valid // double / money is INVALID friend int operator == (const money&, const money&); friend int operator != (const money&, const money&); friend int operator < (const money&, const money&); friend int operator > (const money&, const money&); friend int operator <= (const money&, const money&); friend int operator >= (const money&, const money&); friend int operator == (const money&, double); friend int operator != (const money&, double); friend int operator < (const money&, double); friend int operator > (const money&, double); friend int operator <= (const money&, double); friend int operator >= (const money&, double); friend int operator == (double, const money&); friend int operator != (double, const money&); friend int operator < (double, const money&); friend int operator > (double, const money&); friend int operator <= (double, const money&); friend int operator >= (double, const money&); money& operator += (const money&); money& operator += (double); money& operator -= (const money&); money& operator -= (double); money& operator *= (double); money& operator /= (double); friend money operator+ (const money&); friend money operator- (const money&); money& operator++(); // prefix money& operator--(); money& operator++(int); // postfix money& operator--(int); friend int operator! (const money&); friend money abs(const money&); friend money flatten( const money& m, double cents=0.25, int rounding = 1 /* TRUE */); protected: // let users change the class behaviour double m_money; }; // Constructors && assignment inline money::money() { // do nothing constructor, for efficiency } inline money::money(double d) { // construct from double m_money = d*SCALE(); FIX(); } inline money::money(const money& m) { // copy constructor m_money = m.m_money; } inline money& money::operator= (const money& m) { // copy operator m_money = m.m_money; return *this; } inline money& money::operator= (double d) { // assign from double m_money = d*SCALE(); FIX(); return *this; } inline money::operator double() const { // convert to double return m_money / SCALE(); } inline int money::OK() const { // Returns TRUE (1) when the quantity stored // in *this really corresponds to a money // quantity. money temp; temp.m_money = m_money; temp.FIX(); return ( ( temp.m_money == m_money ) && ( fabs(m_money) < (TENPOW(DBL_DIG) / SCALE()) ) ); } inline void money::FIX() { // Deletes all decimals digits beyond // the MONEY_DECIMALS decimal place. // - If the value is out of range, FIX // won't fix it. m_money = (m_money > 0.0 ? floor( m_money #ifdef MONEY_ROUNDING + 0.5 // 0.49 is also an option... #endif ) : ceil( m_money #ifdef MONEY_ROUNDING - 0.5 #endif ) ); } // add inline money operator+ (const money& m, const money& mm) { money temp; // don't mult*SCALE() temp.m_money = m.m_money + mm.m_money; return temp; } inline money operator+ (double d, const money& m) { return (money(d)+m); } inline money operator+ (const money& m, double d) { return (m+money(d)); } // substract inline money operator- (const money& m, const money& mm) { money temp; temp.m_money = m.m_money - mm.m_money; return temp; } inline money operator- (double d, const money& m) { return (money(d)-m); } inline money operator- (const money& m, double d) { return (m-money(d)); } // multiply inline money operator* (const money& m, double d) { money temp; temp.m_money = m.m_money * d; // don't mult by SCALE() temp.FIX(); // this could be delayed... return temp; } inline money operator* (double d, const money& m) { return (m*d); } // divide inline double operator/ (const money& m, const money& mm) { return m.m_money / mm.m_money; } inline money operator/ (const money& m, double d) { money temp; temp.m_money = m.m_money / d; temp.FIX(); // this could be delayed... return temp; } inline money operator% (const money& m, const money& mm) { money temp; temp.m_money = fmod(m.m_money, mm.m_money); temp.FIX(); // this could be delayed... return temp; } // compare inline int operator == (const money& m, const money& mm) { return m.m_money == mm.m_money; } inline int operator != (const money& m, const money& mm) { return m.m_money != mm.m_money; } inline int operator < (const money& m, const money& mm) { return m.m_money < mm.m_money; } inline int operator > (const money& m, const money& mm) { return m.m_money > mm.m_money; } inline int operator <= (const money& m, const money& mm) { return m.m_money <= mm.m_money; } inline int operator >= (const money& m, const money& mm) { return m.m_money >= mm.m_money; } inline int operator == (const money& m, double mm) { return m.m_money == mm; // return m.m_money == (money)mm; // take a pick !!! /* A decission that you should make is whether this equality comparison requires the double quantity to be promoted to a money item. The direct comparison is more transparent, so it is prefered in here. */ } inline int operator != (const money& m, double mm) { return !(m == mm); } inline int operator < (const money& m, double mm) { return m.m_money < mm; } inline int operator > (const money& m, double mm) { return m.m_money > mm; } inline int operator <= (const money& m, double mm) { return m.m_money <= mm; } inline int operator >= (const money& m, double mm) { return m.m_money >= mm; } inline int operator == (double m, const money& mm) { return (mm == m); } inline int operator != (double m, const money& mm) { return !(mm == m); } inline int operator < (double m, const money& mm) { return m < mm.m_money; } inline int operator > (double m, const money& mm) { return m > mm.m_money; } inline int operator <= (double m, const money& mm) { return m <= mm.m_money; } inline int operator >= (double m, const money& mm) { return m >= mm.m_money; } inline money& money::operator += (const money& m) { m_money += m.m_money; return *this; } inline money& money::operator += (double d) { m_money += d*SCALE(); FIX(); return *this; } inline money& money::operator -= (const money& m) { m_money -= m.m_money; return *this; } inline money& money::operator -= (double d) { m_money -= d*SCALE(); FIX(); return *this; } inline money& money::operator *= (double d) { m_money *= d; FIX(); return *this; } inline money& money::operator /= (double d) { m_money /= d; FIX(); return *this; } // unary op's inline money operator+(const money& m) { return m; } inline money operator-(const money& m) { money temp; temp.m_money = -m.m_money; return temp; } inline money& money::operator++() { m_money += SCALE(); #if (MONEY_DECIMALS<0) FIX(); // avoid problems because of #endif // the representation of 10^-n return *this; } inline money& money::operator--() { m_money -= SCALE(); #if (MONEY_DECIMALS<0) FIX(); #endif return *this; } inline money& money::operator++(int) { return ++(*this); } inline money& money::operator--(int) { return --(*this); } inline int operator!(const money& m) { return m.m_money == 0.0; } inline money abs(const money& m) { money temp; temp.m_money = fabs(m.m_money); return temp; } money flatten(const money& m, double cents, int rounding) { // Returns a money data item where the cents are // rounded modulo "cents". In this way cents can // be stripped of money items when the currency // does not have all the coins required to pay // every posible quantity. money temp; double c = floor(fabs(cents*money::SCALE())); // cents double r = fmod(m.m_money, c); // remainder temp.m_money = (!rounding || (2.0* r <= c) ? m.m_money - r : m.m_money - r + c ); return temp; } /* Avoid name space overcrowding */ #undef __VAL #undef TENPOW /* jic: Just In Case! */ #endif /* _money_h */
money.h
"
/* @(#) money.c 1991 Adolfo Di Mare */ /* email: adolfo@di-mare.com */ /* */ /* Test driver for money.h */ /* */ /* Compiler: Borland C++ v 2.0 */ /* [should work with Turbo C++] */ /* To see what is going on, you need to use your symbolic debugger to examine each of the declared variables. For Borland C++, I used the following watches: m_money d,f18 m,r i mm,r l elapsed s,f18 Change the compile time macros to see how money's change their behaviour. */ #define TEST #ifdef TEST /* { */ #if 0 #define MONEY_ROUNDING /* Force rounding of doubles */ #endif #define MONEY_DECIMALS 2 /* 2 decimals for money data */ extern "C++" { #include "money.h" #ifdef __TURBOC__ #include <iostream.h> #else #include <stream.h> #endif } inline ostream& operator<<(ostream &out, money& m) { return out << (double) m; } extern "C" { #include <stdlib.h> #include <time.h> #include <stdio.h> } #define RANGER #undef RANGER /* takes forever to run... */ void ranger(void); void main(void) { // To the right is the assigned value money m(25.8499); // $ 25.84 money mm; // $ #$$#@$@.98 int i = 5; // 5 long l = 6; // 7 double d = m; // 25.8399999999999999999999999999 i = m; // 25 #if 0 /* [ */ m = d; // $ 25.84 m = 7.009999999; // $ 7.oo m += 1; // $ 8.oo m += 1.245000001; // $ 9.24 m += 1L; // $ 10.24 m += 'a'; // $ 'a'+10.24 m = -d; // $ -25.84 m = -7.00999999; // $ - 7.oo m -= 1; // $ - 8.oo m -= 1.245000001; // $ - 9.24 m -= 1L; // $ -10.24 m -= 'a'; // $ -'a'-10.24 mm = 10; // $ 10.oo m = mm+4; // $ 14.oo m = mm+4.014999; // $ 14.01 m = 4.99+mm; // $ 14.99 m = 4+mm; // $ 14.oo m = m+mm; // $ 24.oo m += m; // $ 48.oo d = mm+4; // 14.oo d = mm+4.011; // 14.0099999999999998 d = 4.99+mm; // 14.9900000000000002 d = 4+mm; // 14.oo mm = 10; // $ 10.oo m = mm*4; // $ 40.oo m = mm*4.0; // $ 40.oo m = 4*mm; // $ 40.oo m = 4.0*mm; // $ 40.oo mm = 10; // $ 10.oo d = 7.00001; // 7.00000999999999962 m = d*mm+d; // $ 77.oo m = (d*mm)+d; // $ 77.oo m = d+d*mm; // $ 77.oo m = d+(d*mm); // $ 77.oo m = 10; // $ 10.oo mm = 77; // $ 77.oo m = m % mm; // $ 10.oo // $10 == 0L * $77 + [$10] m = 77; // $ 77.oo mm = 10; // $ 10.oo m = m % mm; // $ 7.oo // $77 == 7L * $10 + [$7] m++; // $ 8.oo m--; // $ 7.oo m = 11.75; // $ 11.75 m += 0.12; // $ 11.87 mm = flatten(m,0.25,1); // $ 11.75 m += 0.01; // $ 11.88 mm = flatten(m,0.25,1); // $ 12.oo m = 11.75; // $ 11.75 m += 0.12; // $ 11.87 mm = flatten(m,0.25,0); // $ 11.75 m += 0.01; // $ 11.88 mm = flatten(m,0.25,0); // $ 11.75 m -= 5; m += 0.12; // $ 7.oo if (m == 0 || 0 == m) { // nep m += d; } else if (!(m == m)) { // nep m = m; } else if (m > m) { // nep m = m; } else if (m < m) { // nep m = m; } else if (m != m) { // nep m = m; } else if (m >= m) { // yep m *= 11; // $ 77.oo m += 15; // $ 92.oo } l = i = m; // 92 m = -m; // $ -92.oo mm = i*l; // $ 8,464.oo m = m % mm; // $ -92.oo d = 15.253; // 15.253 m = 15.25; // $ 15.25 if (d == m) { // FALSE: float comparison... l = 0; } // l = 92L if (d == (double) m) { // FALSE: 15.253 != 15.25 l++; } // l = 92L // simulate a TAX calculation m = 0.0; for (i = 1; i <= 100; i++) { d = i*1.005; // 0.05% tax m += d; } // $ 5,075.oo mm = 100; // $ 100.oo m /= (double) mm; // $ 50.75 m /= 3; // $ 16.91 m *= 3; // $ 50.73 mm = mm/mm; // 1.00 d = m * (m / mm); // 2573.5300000000002 d = 1.0/3.0 * m; // 16.9100000000000001 mm = 1.0/3.0 * m; // $ 16.91 mm = 3 * mm / (3 * mm); // $1.oo mm = M_PI * mm / (M_PI * mm); // $1.oo mm = M_PI; // $3.14 mm = mm/mm + 1 - (3 * mm / (3 * mm)); // $1.oo m *= M_E * mm / (mm * M_E) - 1; // $0.oo // m == 0.0 && mm == $1.oo for (i = 1; i <= 100; i++) { mm /= 3; // $ 0.33 m = m+mm; // Add a third mm = 1; } // $ 33.oo d = m; // 33.00 mm = m / 330; // $ 0.10 clock_t now; double elapsed; // time statistics, on a 33 MHz 386 m = 0; now = clock(); for (l = 0; l <= 10000l; l++) { m += 1.01; // Add $1.01 } elapsed = (clock()-now) / CLK_TCK; d = elapsed; // 3.51 secs m = 1; now = clock(); for (l = 0; l <= 10000l; l++) { m *= 1.0001; // Mult } elapsed = (clock()-now) / CLK_TCK; d = elapsed; // 3.24 secs m = 1; mm = pow(10, 6); now = clock(); for (l = 0; l <= 10000l; l++) { mm = m; m /= 0.99001; // Div if (!m.OK()) { m.FIX(); // won't fix overflows } } elapsed = (clock()-now) / CLK_TCK; d = elapsed; // 8.46 secs d = m % m + 33; // 33.00 m = d; // $ 33.oo mm = d / 330; // $ 0.10 d = (10+mm)/m * m; // 10.089... // Must use (double) type cast printf ("Salary = %10.2f\n", (double) ((10+mm)/m * m)); cout <<"Salary = " << (double) ((10+mm)/m * m) << '\n'; // valid only if you define // ostream& operator<< (ostream&, money&) cout <<"Salary = " << (10+mm)/m * m << '\n'; // m = d / m; // should not compile... // m = m * m; // won't compile: AMBIGUITY ERROR!!! #ifdef RANGER ranger(); #endif // RANGER #endif /* ] */ exit(0); } void ranger(void) { /* Shows that indeed a double can hold up to DBL_DIG digits of precission. */ // This should take forever to calculate... char view[] = "0123456789/123456"; double s,t; double tenpow,inc; int i; tenpow = pow(10, DBL_DIG); // 10^15 inc = 100.0; // pick yours s = floor(tenpow+inc); // 1,000,000,000,000,000 + inc for (;;) { t = s; s += inc; // i = (int) log10(t-tenpow); if (s == t) { i = (int) log10(t-tenpow); cout << "BOOM t = " << t << '\n'; cout << "BOOM s = " << s << '\n'; cout << "BOOM inc = " << s << '\n'; cout << "BOOM i = " << i << '\n'; view[i] = 0; cout << "view = " << view << '\n'; return; } } return; } // ranger #endif /* TEST */ /* } */
[1] | Wright, Maynard A.:
Complex Function Library,
The C Users Journal,
Vol.8 No.9,
pp [45-53],
September 1990.
|
[2] | Shapiro, Jim:
Whe have mail,
The C Users Journal,
(a comment on [1]),
Vol.9 No.5,
pp [142,144],
May 1991.
|
[3] | Timothy Prince:
Pennies in Long Double,
The C Users Journal,
Vol.9 No.1,
pp [77-78,83-84,86],
January 1991.
|
[4] | Smith III, Thad:
Whe have mail,
The C Users Journal,
(a comment on [3]),
Vol.9 No.4,
pp [126,128],
April 1991.
|
[-] | Abstract
|
[-] | Available tools
|
[-] | Defining requirements
|
[-] | Implementation details
|
[-] | Conclusion
|
[-] | Funding
|
[-] | Acknowledgments
|
|
|
[-] | Listing 1: The money Class
|
[-] | Listing 2: Test driver for "money.h "
|
|
|
Bibliography
|
|
Indice
|
|
Acerca del autor
|
|
Acerca de este documento
|
|
Principio
Indice
Final
|
Adolfo Di Mare <adolfo@di-mare.com>
Referencia: | Di Mare, Adolfo:
Yet Another C++ Money Class,
The C Users Journal,
Vol.10 No.4,
pp [58-64],
April 1992.
|
Internet: |
http://www.di-mare.com/adolfo/p/money.htm
|
Autor: | Adolfo Di Mare
<adolfo@di-mare.com>
|
Contacto: | Apdo 4249-1000, San José Costa Rica Tel: (506) 207-4020 Fax: (506) 438-0139 |
Revisión: | ECCI-UCR, Octubre 1997
|
Visitantes: |
|
|