Based on earlier dialogs, I want to create the following implementation detail based on the requirements for precision and performance:
All numbers will be represented as one or two longs (depending on precision) for the mantissa and a single int for the base 10 exponent. For example, 12345.678 could be 12345678 mantissa and -3 exponent.
It is possible for the result of a calculation to burst into the maximum internal representation (which is 2 longs for the mantissa and one int for the decimal).
If the calculation involves adding two 4-digit values, with 2 decimal places precision, then internally the calculation will only need to perform one java-long addition.
For all currency arithmetic, calculations are performed according to the full precision of the internal representation.
Then if there is no rounding specified, and if the internal representation can't be expressed due to an overflow, then it will throw a Rounding exception
For example, $100/3=33.33333... will throw a Rounding exception
But if there is a rounding specified, then the calculation will be performed to the precision specified in the rounding.
(Please note that the Rounding associated with a Money instance should not be confused with the Rounding associated with a display instance. The Rounding for the Money instance represents the internal precision of the calculation, so for example 1/8 = .125. But if the Rounding specifies 2 decimal places then the internal representation would be truncated to .13 (using for this example USA rounding rules.)
It should be noted that several options have been considered concerning how to represent the value, without requiring the developer to be concerned with the internal representation.
That can be accomplished by accepting the following API's for the Money class:
Money(Currency c, String value, Rounding r) and
Money(Currency c, double value, Rounding r).
When adding or subtracting two Money instances with different exponents, one of the moneys will need to shift its value to accomodate the other.
So for example 123.45 + 678.912, are represented internally as 12345 -2 and 678912 -3, so the addition will need to shift the lowest precision and perform as follows:
123450 -3 + 678912 -3
To minimize the number of shifts when performing addition and subtraction, we use a convention where by default, 10 decimal places are assumed.
Using that convention, if the value is 123.45, it will internally be represented as 123_4_500_000_000 -10. Since a long has about 19 digits of precision, that leaves 9 digits for the integer part of the value using one long, and 28 digits using 2 longs.
The exponent would be shifted to the right in extreme cases to allow more digits.
(This representation would accomodate the current gross world product (US$80,000,000,000,000) to 14 decimal places. That would even allow an accurate representation in Korean Wons.
If you use the String constructor, there is a performance hit on converting that to an internal representation
If you use the double constructor, there is a smaller performance hit on the conversion, but you are agreeing to the value as supplied, assuming it is precise.
A 3rd constructor that allows the user to specify an internal precision, for example as a long array will also be provided.
Money(Currency c, long mantissa, int exponent, Rounding r)
Which ever constructor is used, the Money class will automatically allocate the internal representation based on the value and Rounding.
This suggests several classes and an internal representation:
1. Money - an immutable value object containing a value and a Currency, as well as an optional Rounding
2. Rounding - an immutable object that is included in a Money object on construction.
3. RoundingAlgorithm - an extendable Enum containing all known rounding algorithms 4. RoundingException (Checked Exception) - thrown when a calculation produces a value that exceeds the internal representation, and when no rounding is specified to handle that overflow.