Boost logo

Boost :

From: Martin (adrianm_at_[hidden])
Date: 2005-01-08 09:36:48


(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.

decimal64 type
-------------
The type stores a decimal value with specified numberof decimals exactly and
also performs all arithmetic operations (+,-,*,/) using decimal math.

(Internally the type stores the value as an int64 value which gives 18 DECIMAL
digits precision. Multiply and divide uses a 128 bit temporay to avoid
rounding errors)

- All std rounding modes are available plus a few extra such as round_to_even.

- Construction of a decimal64 can be made from int, double, string literal
(e.g. "1.234") and other decimal64 values.

- Operations can be made on decimal64 objects with different number of
decimals and/or different rounding policy. Result of a binary operation on two
decimal64 values will have the number of decimals and rounding policy of the
left operand.

- Streaming works the same way as floating point values but the scientific
format is ignored.

There are 2 decimal64 types defined:

- decimal64 - all constructors requires specification of number of decimals
and optionally rounding mode.

decimal64(3.1415, 4, round_to_nearest);

- decimal64_spec - a template version of decimal64 where number of decimals
and rounding mode are specified as template parameters which allows a default
constructor.

typedef decimal64_spec<3, round_to_even> decimal3;
decimal3 x(3.14), y;

The decimal value can be converted into another at any time if a calculation
needs to be performed at a higher precision or with another rounding policy.

decimal64 x(1.2, 1, round_to_nearest);

// calculate x*PI/2 using 5 decimals
// result is stored in x with 1 decimal,
// rounded with round_to_nearest policy

x = x.as_decimal(5) * decimal64(3.14159, 5) / 2;

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?

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

Money type
-----------
The money type uses a decimal type to store a monetary value. The
functionality is the same as for the decimal64 type with the following
exception:

1. Operations are more limited to detect errors. The limitations are:
- Money * Money is not allowed. (Money * Decimal is allowed)
- Money / Money is allowed but the result is a Decimal (not money)
- Money + Decimal is not allowed (Money + Money is allowed).
  (The same applies to - and all comparison operators)

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

2. Streaming uses locale moneypunct for formatting and parsing.

As with the decimal type two money classes are defined

- money_base - construction always requires number of decimals and optionally
rounding policy

typedef money_base<decimal64> money64;
money64 x(100,2,round_toward_infinity);

- money_spec - number of decimals and rounding policy are template parameters.

typedef money_spec<decimal64, 4, round_toward_neg_infinity> money4;
money4 x("9.99"), y;

locale library
--------------
Some time ago implemented helper classes for locale but I never got around
submitting it to boost. I needed it for testing the decimal64/money streaming
so I cleaned it up and it is included in the package.

Building
--------
A jam file for building decimal library is included. I have compiled all files
and testcases with VS2002 (VC70) and "g++ (GCC) 3.4.2 (mingw-special)".
Couldn't get the boost test jam file to work but command line g++ works fine.
g++ libs/decimal/test/decimal64_test.cpp libs/decimal/src/decimal64.cpp
g++ libs/decimal/test/money_test.cpp libs/decimal/src/decimal64.cpp
libs/decimal/src/money.cpp
g++ libs/locale/test/locale_test.cpp libs/decimal/src/decimal64.cpp
libs/decimal/src/money.cpp

There are some differences in streaming which causes a few test errors for
money:
- VC70 only inserts spaces in the money format if the "internal" adjustment
flag and width is set. g++ always inserts 1 space when specifed in the format.
I assumed g++ was right so VC70 fails this test.
- The default locale with g++ seem to miss a '-' sign for the money format so
it fails tests with negative numbers.

Library is available here http://web.telia.com/~u84606172/Boost/
Documentation is available in the download as well.


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