Rounding Errors in RWDecimal<T>

Article ID: 1136
Last updated: 31 Jan, 2008
Article ID: 1136
Last updated: 31 Jan, 2008
Revision: 1
Views: 3262
Posted: 08 Jun, 2001
by Dean J.
Updated: 31 Jan, 2008
by Dean J.
Problem


Under certain circumstances, RWDecimal<T> objects fail to round properly. This problem affects all versions of Money.h++ and the Currency Module in SourcePro C++ Edition 1-2001 only.

Specifically, very small decimal numbers, such as 123x10^-42, round improperly when the number of decimal places eliminated by rounding is greater than the template parameter, T, can hold.  Consequently, if you have templatized an RWDecimal<T> such that maxDigits() is M decimal digits, and you have a very small decimal whose exponent is greater than M+1, attempts to round off more than M+1 digits yield incorrect results.

This bug becomes evident when:

  • An RWDecimal<T> object has an exponent E greater than M+1, the maximum number of digits the template parameter T supports; for example, when an RWDecimal<RWMP2Int>, which can hold at most 19 digits, has an exponent of 42.

and:

  • An attempt is made to eliminate M+1 or more digits in the rounding process.

While this is probably not a common set of circumstances, it is more common than at first imagined.  Since internally class RWDecimal<T> represents numbers as a mantissa/exponent pair, it's quite possible to have very small numbers that are entirely valid.  Even though the template parameter T limits the mantissa to M significant digits, the value of the exponent can easily exceed M, as in the example above.

The following code would trigger the bug:

#include <iostream.h>
#include <rw/money/decimal.h>
#include <rw/money/mp2int.h>

int main()
{
  RWDecimal<RWMP2Int> k1( "0.000000000001" ); // 10^-12
  RWDecimal<RWMP2Int> k2( "1000000000000" );  // 10^+12
  RWDecimal<RWMP2Int> k3 = k1 / k2;           // 10^-24, so exponent = 24
  RWDecimal<RWMP2Int> r1 = round( k3, 3 );    // 24-3 = 21 digits eliminated by rounding

  cout << "r1 = " << r1 << endl; // Output varies with version:
                                 //    version 2.0.3: "NaN"
                                 //    version 2.1.1: "BadValue"
                                 //    Currency Module, SourcePro Analysis 7.0: "0.001"
}




Cause


There is a bug in the file rw/money/decimal.cc, in the function roundDecimal().  During the rounding process, the function creates a temporary object of type T.  If the number of digits eliminated by rounding exceeds maxDigits()+1, this temporary object is corrupted and the rounding algorithm fails.




Action


Corrected versions of the affected file .../rw/money/decimal.cc are available from Rogue Wave Support Services for Money.h++ 2.03 and 2.11, and the Currency Module in SourcePro C++ Edition 1-2001.  Different release versions require different versions of the corrected file, so it's vital that you tell the Support Engineer which release version you are using.  To verify the version of your product:

  • For SPM installations, check the parts directory structure within your spm directory; that is, spm/parts/mny02xxx.  The directory should be named either mny0211u, mny0211w, mny0203u, or mny0203w, where the u/w character stands for Unix or Windows.
  • For RCB installations, check the heading of the Currency Module readme file. It should be in <RW_BUILDSPACE>/docs/readmes/sourcepro-analysis/currency.

Note: if you received a patch to decimal.cc before July 27, 2001, it doesn't contain the latest corrections and can still yield incorrect results under some circumstances. Please contact Support Services to determine an appropriate solution for your specific situation.

This article was:   Helpful | Not helpful
Report an issue
Article ID: 1136
Last updated: 31 Jan, 2008
Revision: 1
Views: 3262
Posted: 08 Jun, 2001 by Dean J.
Updated: 31 Jan, 2008 by Dean J.
Also listed in


Others in this category