## Introduction

This is a simple utility class which encapsulates the OLE Automation type `DECIMAL`

. It's intended purpose is to rid the user of `::VarDecXXX()`

calls and make the `DECIMAL`

s "behave just like `int`

s".

## Interoperability

My class, `Decimal`

, inherits publically from `DECIMAL`

. The benefit of this is that anywhere you can put a `DECIMAL`

, you can also put a `Decimal`

. This makes the class fully interoperable with raw COM interfaces.

Unlike ATL, I do not overload the *address of* operator (`operator&`

), so there is no need to adapt this class with `CAdapt<>`

in order to contain it in STL containers.

## Interface

All methods and constructors share the property `throw()`

- i.e., no method will ever throw an exception. However, in debug builds, `assert`

s may be triggered. Division by zero comes to mind. But you already know you shouldn't be dividing with zero, right?

All methods which return a `Decimal&`

value, returns a reference to `*this`

. Hence it is possible to stack such methods/operations.

### Constructors

There are ten constructors. They are:

`Decimal()`

Initializes the object with value 0.

`Decimal(const DECIMAL& decValue)`

Initializes the object with the value which is contained in parameter `decValue`

.

`Decimal(char nValue) `

`Decimal(short nValue) `

`Decimal(long nValue) `

`Decimal(unsigned char nValue) `

`Decimal(unsigned short nValue) `

`Decimal(unsigned long nValue) `

Initializes the object with the integer value contained in parameter `nValue`

.

`Decimal(float fValue) `

`Decimal(double fValue) `

Initializes the object with the real value contained in parameter `nValue`

.

### Mutating operators

The following operators are defined, and behaves just like `int`

s (hence I will not explain their usage and function!):

`Decimal& operator = (char nValue) `

`Decimal& operator = (short nValue) `

`Decimal& operator = (long nValue) `

`Decimal& operator = (unsigned char nValue) `

`Decimal& operator = (unsigned short nValue) `

`Decimal& operator = (unsigned long nValue) `

`Decimal& operator = (float fValue) `

`Decimal& operator = (double dValue) `

`Decimal& operator += (const DECIMAL& decRHS) `

`Decimal& operator -= (const DECIMAL& decRHS) `

`Decimal& operator *= (const DECIMAL& decRHS) `

`Decimal& operator /= (const DECIMAL& decRHS) `

`Decimal operator++(int) `

`Decimal operator--(int) `

`Decimal& operator++() `

`Decimal& operator--()`

Each operator operates just as if they had been defined for `int`

s.

### Mutating methods

`bool FromString(LPCOLESTR lpszNum, LCID lcid = 0)`

Parses a string pointed to by `lpszNum`

using the locale identifier `lcid`

. The parsed value is then assigned to `this`

object before returning.

Should this function fail because of a badly formatted string, the return value is `false`

.

If the locale identifier, `lcid`

, is `0`

, then the default system locale will be used to parse the string.

`Decimal& MakeAbsolute()`

Makes this value an absolute value.

`Decimal& MakeNegative() `

Makes this value a negative value.

`Decimal& MakeInteger() `

Makes this value an integer by removing its fractional part. The semantics of this function is as follows: *If the value is negative, then the first negative integer less than or equal to this value is returned.* (Semantic description was copied and adapted from the MSDN documentation. Please see manual page for `VarDecInt`

for the original text.)

`Decimal& MakeFixed()`

Makes this value an integer by removing its fractional part. The semantics of this function is as follows: *If the value is negative, then the first negative integer greater than or equal to this value is returned.* (Semantic description was copied and adapted from the MSDN documentation. Please see manual page for `VarDecFix`

for the original text.)

`Decimal& MakeRound(int n)`

Rounds this value up to the `n`

th decimal.

Note that `n`

must be greater or equal to zero.

### Non-Mutating methods

The following functions are non-mutating. They are related to their mutating cousins described above, therefore I will just mention them here. For example, if a method mentioned below is named `Absolute`

, then please see the documentation above for `MakeAbsolute`

. These methods all share the common property that they do not modify the current value. Instead they create a temporary value which is modified and returned.

`Decimal Absolute() const `

`Decimal Negative() const `

`Decimal Integer() const `

`Decimal Fixed() const `

`Decimal Round() const`

### Inspectors

`bool IsNegative() const`

Predicate which returns `true`

if this value is negative.

`bool IsZero() const`

Predicate which returns `true`

if this value is negative. This is the fastest way to test whether a `Decimal`

is zero or not.

`BSTR ToString(LCID lcid = 0) const`

Converts this value into a `BSTR`

string using the specified locale. If the locale identifier, `lcid`

, is zero, then the systems default locale will be used.

### Free functions

The following free functions, although logically members of `Decimal`

, works as if they had been designed for `int`

s.

`Decimal operator + (const DECIMAL& decRHS, const DECIMAL& decLHS) `

`Decimal operator - (const DECIMAL& decRHS, const DECIMAL& decLHS) `

`Decimal operator * (const DECIMAL& decRHS, const DECIMAL& decLHS) `

`Decimal operator / (const DECIMAL& decRHS, const DECIMAL& decLHS) `

`bool operator < (const DECIMAL& decRHS, const DECIMAL& decLHS) `

`bool operator > (const DECIMAL& decRHS, const DECIMAL& decLHS) `

`bool operator <= (const DECIMAL& decRHS, const DECIMAL& decLHS) `

`bool operator >= (const DECIMAL& decRHS, const DECIMAL& decLHS) `

`bool operator == (const DECIMAL& decRHS, const DECIMAL& decLHS) `

`bool operator != (const DECIMAL& decRHS, const DECIMAL& decLHS)`

## Implementation details

I do not do any arithmetic calculations in my code. I merely use the OLE automation functions for manipulating `DECIMAL`

s. All I have done is moulded it all together into a thin C++ wrapper class which makes `DECIMAL`

s a bit more enjoyable to work with. Syntactic sugar makes software sweet.

If you take a quick look at the source file you will see that it is a very thin wrapper and adds, to my knowledge, a very small running time overhead. But please, correct me if I am wrong.

## Caveat emptor

There are a couple of things which you may be interested in knowing before you use this code.

### verify/assert

This code currently uses the C library versions of `assert`

(and my own `assert`

dependent macro `verify`

). You may want to change this before you use this in an ATL or MFC environment. A simple *Search and Replace All* should do the trick.

### Variants

I have not included any method for dealing with `VARIANT`

s. I want a simple and clean interface. If I ever need any interoperability with `VARIANT`

s, I'll add the method. Until then, tough luck - or write it yourself.

### Strings

As you may have noticed, I only support `BSTR`

strings in the interface. The reason is quite simple; I intend to use this code in the shadow lands near VB[Script] (and possibly other weird environments) where `BSTR`

is the string of choice. I don't believe in bloating interfaces, so I'll refrain from adding support for any other type of string unless I really need it. If I do, I'll update this source code. If you need it before I do, well, you've got the source!

### VC6

I've included VC6 as a keyword for this article. But I admit that I have not tested against that compiler. But since I'm not using any fancy templates or other new and exotic features, I believe this code will work just fine in VC6. In fact, I had an older version of this class in another project, which compiled just fine for VC6. Considering that I've removed a lot of bloat, this class should still compile. This is QA at its peak.

### Rounding coins

There's a free function called `RoundToSmallestCoin`

in the header file. It's a function I use in POS-software I write at work. I keep it in this file because I'm lazy. If you feel that it's bloating your code, just select it and hit the delete button.

## References

Marc Clifton wrote a similar article about a decimal class. His implementation is perfect if you do not intend to work with COM/OLE automation environments. You can find his article here.

## Disclaimer and License grant

### Disclaimer

No warranties of any kind comes with this article and source code. I cannot be held liable for damages to data, damages to hardware or injuries. In fact, you cannot hold me liable for anything if you use this source code.

### License grant

However, should you find this code useful, and should we ever meet, I will not say "No thank you" should you offer me a beer (preferably a beer of my choice). However, it's not a requirement. This is beerware if it's ok with you, otherwise it's freeware.