|
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