Boost logo

Boost :

From: Daniel Frey (d.frey_at_[hidden])
Date: 2005-01-08 10:44:53


Martin wrote:
> (I know that "Currency" received 0 votes at the OOPSALA conference but maybe
> someone is interested anyway)
>
> I have implemented a type for handling decimal math and a type specialized for
> monetary values.

I strongly suggest to use a currency, as otherwise you'll likely miss
the intended audience's requirements. If you are handling monetary
values, you want as much safety as possible. This means that you must
make sure you don't add EUR and USD! Our company's implementation of the
currency class uses a 32-bit integer internally, which holds 4
characters: 3 represent the currency, the 4th is \0. Also, the 0 itself
is allowed (as the empty currency). Makes the handling of currencies
very efficient, still the interface seems to use strings/char*'s. Ugly
casting internall, though, but at least it's encapsulated :)

FWIW, I'll aks my boss on monday if it's OK to take some of the code
here if there is interest in such a library.

One thing which I invented during the implementation was already shown
in clc++m: <http://tinyurl.com/5l7tb> (links to Google archieve). After
some months of experience with it, I'm quiet satified with it. It makes
using the money class really easy:

typedef std::vector< money > V;

money balance( const V& v ) {
   money s = 0; // Note: no currency!
   for( V::const_iterator it = v.begin(); it != v.end(); ++it ) {
     s += *it;
   }
   return s;
}

bool is_debtor( const V& v )
{
   return balance( v ) < 0; // Note: no currency!
}

This throws an exception if the vector contains different currencies,
otherwise it works pretty well :)

Regards, Daniel

> Some things I would specificly like to have comments on:

> 1. Operations are not allowed on doubles. Double values always need to be
> converted into a decimal value first. e.g. x * decimal64(3.14, 2). Is this
> something that is needed?

In the banking area, it's important to allow using types with a
base-10-representation. Rounding errors due to binary stored numbers are
often a problem. Consider a typical bug:

double d = 0;
for( int i=0; i<100; ++i ) d += .01;
if(d==1) { ... }

Conclusion: Make it damn hard for users to use inexact values. Our
solution is (like yours): explicit conversion functions or use strings.

> 2. No overflow detection or +inf etc. Just like with the integer types there
> is no checking for overflow on operations.

Reasonable, IMHO.

> Integers works as both money and decimal so Money*2 and Money+1 is always
> allowed.

money*int is OK, money+int is not. And FWIW, I never saw any of my
colleagues complain about money+int not compiling. If the compiler
happens to catch it, it usually means that it saved them from a having bug!

> typedef money_base<decimal64> money64;

I suggest the following classes/names which I used when designing our
company's decimal/money/currency-framework:

currency

basic_decimal<T> (interface for some T, e.g. decimal64 from above, long
double, ...)

basic_money<T> (consists of a basic_decimal<T> and a currency)

The application can/should then create central typedefs:

typedef basic_decimal<long double> decimal;
typedef basic_money<decimal::value_type> money;

That way, you can switch your complete application for different
underlying types that are used for the real calculations easily.

Regards, Daniel


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk