First date of publication: 05 october 2006
Last date of modification: 05 october 2006
very tiny correction: 18 july 2007
One of the Microsoft Foundation Classes is the class Decimal. This class supplies decimal numbers and the relating arithmetics. All decimal values are stored in the same way as binary floats, i.e. as a set of two binary integer values. The mantissa is written in signed mantissa notation. It has not a hidden bit. Since it is an integer it also has not a fractional part. The base of the exponent is 10, not 2, so the value of the whole float is: sign * |mantissa| * 10 ^ exponent. Consequently there must be both a +0 and a -0 value. Microsoft does not mention this fact.
The mantissa is an enormously long binary integer, 96 data bits plus the sign bit. Its maximum value is exactly 79,228,162,514,264,337,593,543,950,335 (= 2^96 - 1, not 2^96 like Microsoft states). Since this mantissa is a binary integer a decimal shift results in a multiplication or division of this long word by ten. (This is similar to what happens in the Burroughs 6700 machine.)
The exponent is always zero or negative, never positive. Its value is in the range from 0 to -28. Since the length of this range does not exceed the decimal accuracy of the mantissa the total number is not really a float. Perhaps its behaviour is somewhat between a floating point and a fixed point number with less accuracy. This may give an unexpected loss of accuracy.
The value of the whole number is: sign * |96bitsInteger| * 10^-|exponent|. In this formula |QQ| means the absolute value of QQ. The maximum value of the whole number equals the maximum value of the mantissa, approximately 7.93E28. The minimum non-zero value equals exactly 1.E-28.
A decimal number occupies 14 bytes. The absolute value of the mantissa is stored as a large unsigned integer in 12 bytes = 96 bits, perhaps in 3 consecutive computer words of 32 bits each. The two remaining bytes contain the sign of the mantissa, the value of the exponent and the data for internal administration.
The Intel-based computers do not have hardware dedicated especially to support the decimal calculations. The class Decimal is supported only by the hardware for the ordinary binary calculations. In contrast with the binary numbers all numbers of the class Decimal are stored in the bulky format, even when the required accuracy is very low.
Microsoft states in its website about this class:
- This type provides methods that convert Decimal values to and from type Char, SByte, Int16, Int32, Int64, Byte, UInt16, UInt32, and UInt64. Conversions from other types to Decimal are widening conversions that never lose information or throw exceptions.
- Conversions from Decimal to other types are narrowing conversions that round the Decimal value to the nearest integer value toward zero. If the result of the conversion is not representable in the destination type, an OverflowException is thrown.
My comments on these statements are:
- SByte = signed byte; UInt = unsigned integer.
- How can the conversion from an ordinary binary float keep all information? Since both types have incompatible exponent bases certainly often a rounding will occur. Every rounding is a (small) loss of information.
- The maximum value of a binary float is greater than the maximum value of the decimal (although it is less accurate). How can an exception be thrown never?
- In the conversion to other types the rounding is performed to zero. The 4/5-rounding off would give more accurate results.
Both the Decimal Class and the Currency Class seem to be a mediocre attempt by Microsoft to enter the realm of the calculations with decimals. They may not be better than the one of the Burrough's 6700. A much better decimal system is required. It has been invented already, the Packed Decimal floats of IEEE-754-2008.
Microsoft library: Decimals