Explorar el Código

Merge pull request #2892 from rengolin/nbcd

BCD refactoring

Reviewed-by: Gavin Halliday <ghalliday@hpccsystems.com>
Gavin Halliday hace 13 años
padre
commit
3dd75fe67e
Se han modificado 6 ficheros con 341 adiciones y 249 borrados
  1. 1 1
      common/workunit/workunit.cpp
  2. 1 1
      roxie/ccd/ccdserver.cpp
  3. 56 56
      rtl/nbcd/nbcd.cpp
  4. 74 58
      rtl/nbcd/nbcd.hpp
  5. 5 5
      rtl/nbcd/nbcds.cpp
  6. 204 128
      rtl/nbcd/nbcdtest.cpp

+ 1 - 1
common/workunit/workunit.cpp

@@ -7208,7 +7208,7 @@ void CLocalWUResult::getResultDecimal(void * val, unsigned len, unsigned precisi
         const char *xmlVal = p->queryProp("xmlValue");
         if (xmlVal)
         {
-            TempDecimal d;
+            Decimal d;
             d.setString(strlen(xmlVal), xmlVal);
             if (isSigned)
                 d.getDecimal(len, precision, val);

+ 1 - 1
roxie/ccd/ccdserver.cpp

@@ -29441,7 +29441,7 @@ public:
                 CriticalBlock b(contextCrit);
                 useContext(sequence).getProp(stepname, x);
             }
-            TempDecimal d;
+            Decimal d;
             d.setString(x.length(), x.str());
             if (isSigned)
                 d.getDecimal(tlen, precision, tgt);

+ 56 - 56
rtl/nbcd/nbcd.cpp

@@ -27,24 +27,24 @@
 #endif
 
 static double Pow10[] = { 1, 10, 100, 1000, 10000, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10,1e11,1e12,1e13,1e14,1e15,1e16 };
-int signMap[16] = { 0,0,0,0,0,0,0,0,0,0,+1,-1,+1,-1,+1,+1 };
+static int signMap[16] = { 0,0,0,0,0,0,0,0,0,0,+1,-1,+1,-1,+1,+1 };
 
 
 
 
-TempDecimal::TempDecimal(const TempDecimal & other)
+Decimal::Decimal(const Decimal & other)
 {
     memcpy(this, &other, sizeof(*this));
 }
 
-TempDecimal & TempDecimal::abs()
+Decimal & Decimal::abs()
 {
     negative = false;
     return *this;
 }
 
 
-TempDecimal & TempDecimal::add(const TempDecimal & other)
+Decimal & Decimal::add(const Decimal & other)
 {
     if (negative == other.negative)
         return addDigits(other);
@@ -54,7 +54,7 @@ TempDecimal & TempDecimal::add(const TempDecimal & other)
 
 
 
-TempDecimal & TempDecimal::addDigits(const TempDecimal & other)
+Decimal & Decimal::addDigits(const Decimal & other)
 {
     extendRange(other);
     byte oLo = other.lsb;
@@ -93,7 +93,7 @@ TempDecimal & TempDecimal::addDigits(const TempDecimal & other)
     return *this;
 }
 
-int TempDecimal::compareNull() const
+int Decimal::compareNull() const
 {
     byte idx;
     for (idx = lsb; idx <= msb; idx++)
@@ -104,7 +104,7 @@ int TempDecimal::compareNull() const
 }
 
 
-int TempDecimal::compare(const TempDecimal & other) const
+int Decimal::compare(const Decimal & other) const
 {
     int lo1, hi1, lo2, hi2;
     clip(lo1, hi1);
@@ -142,7 +142,7 @@ int TempDecimal::compare(const TempDecimal & other) const
 }
 
 
-TempDecimal & TempDecimal::divide(const TempDecimal & other)
+Decimal & Decimal::divide(const Decimal & other)
 {
     //NB: Round towards zero
     int lo1, hi1, lo2, hi2;
@@ -233,7 +233,7 @@ TempDecimal & TempDecimal::divide(const TempDecimal & other)
 }
 
 
-void TempDecimal::extendRange(byte oLsb, byte oMsb)
+void Decimal::extendRange(byte oLsb, byte oMsb)
 {
     byte index;
     if (lsb > oLsb)
@@ -251,15 +251,15 @@ void TempDecimal::extendRange(byte oLsb, byte oMsb)
 }
 
 
-TempDecimal & TempDecimal::modulus(const TempDecimal & other)
+Decimal & Decimal::modulus(const Decimal & other)
 {
-    TempDecimal left(*this);
+    Decimal left(*this);
     left.divide(other).truncate(0).multiply(other);
     return subtract(left);
 }
 
 
-TempDecimal & TempDecimal::multiply(const TempDecimal & other)
+Decimal & Decimal::multiply(const Decimal & other)
 {
     int low1, high1, low2, high2, lowt, hight;
 
@@ -318,13 +318,13 @@ TempDecimal & TempDecimal::multiply(const TempDecimal & other)
 }
 
 
-TempDecimal & TempDecimal::negate()
+Decimal & Decimal::negate()
 {
     negative = !negative;
     return *this;
 }
 
-TempDecimal & TempDecimal::power(unsigned value)
+Decimal & Decimal::power(unsigned value)
 {
     if (value == 0)
         setInt(1);
@@ -334,14 +334,14 @@ TempDecimal & TempDecimal::power(unsigned value)
 }
 
 
-TempDecimal & TempDecimal::power(int value)
+Decimal & Decimal::power(int value)
 {
     if ( value >= 0)
         return power((unsigned)value);
 
 #if 1
     //This probably gives slightly more expected results, but both suffer from rounding errors.
-    TempDecimal reciprocal;
+    Decimal reciprocal;
     reciprocal.setInt(1);
     reciprocal.divide(*this);
     set(reciprocal);
@@ -349,7 +349,7 @@ TempDecimal & TempDecimal::power(int value)
     return *this;
 #else
     doPower((unsigned)-value);
-    TempDecimal reciprocal;
+    Decimal reciprocal;
     reciprocal.setInt(1);
     reciprocal.divide(*this);
     set(reciprocal);
@@ -358,7 +358,7 @@ TempDecimal & TempDecimal::power(int value)
 }
 
 
-TempDecimal & TempDecimal::incLSD()
+Decimal & Decimal::incLSD()
 {
     unsigned index = lsb;
     while (index <= msb)
@@ -376,7 +376,7 @@ TempDecimal & TempDecimal::incLSD()
 }
 
 
-TempDecimal & TempDecimal::round(int places)
+Decimal & Decimal::round(int places)
 {
     //out of range - either 0 or overflow
     if (places < -maxPrecision)
@@ -403,7 +403,7 @@ TempDecimal & TempDecimal::round(int places)
 }
 
 
-TempDecimal & TempDecimal::roundup(int places)
+Decimal & Decimal::roundup(int places)
 {
     if ((places >= maxPrecision) || (zeroDigit - places <= lsb))
         return *this;
@@ -419,7 +419,7 @@ TempDecimal & TempDecimal::roundup(int places)
 }
 
 
-void TempDecimal::getPrecision(unsigned & digits, unsigned & precision)
+void Decimal::getPrecision(unsigned & digits, unsigned & precision)
 {
     //Ensures digits>=precision && precision >= 0
     unsigned top = msb >= zeroDigit ? msb+1 : zeroDigit;
@@ -428,7 +428,7 @@ void TempDecimal::getPrecision(unsigned & digits, unsigned & precision)
     precision = zeroDigit-low;
 }
 
-void TempDecimal::getClipPrecision(unsigned & digits, unsigned & precision)
+void Decimal::getClipPrecision(unsigned & digits, unsigned & precision)
 {
     int lo, hi;
     clip(lo, hi);
@@ -448,7 +448,7 @@ void TempDecimal::getClipPrecision(unsigned & digits, unsigned & precision)
     }
 }
 
-TempDecimal & TempDecimal::setPrecision(byte numDigits, byte precision)
+Decimal & Decimal::setPrecision(byte numDigits, byte precision)
 {
     unsigned char newhigh = zeroDigit + numDigits - precision - 1;
     unsigned char newlow = zeroDigit - precision;
@@ -465,7 +465,7 @@ TempDecimal & TempDecimal::setPrecision(byte numDigits, byte precision)
 }
 
 
-TempDecimal & TempDecimal::subtract(const TempDecimal & other)
+Decimal & Decimal::subtract(const Decimal & other)
 {
     if (negative != other.negative)
         return addDigits(other);
@@ -474,7 +474,7 @@ TempDecimal & TempDecimal::subtract(const TempDecimal & other)
 }
 
 
-TempDecimal & TempDecimal::subtractDigits(const TempDecimal & other)
+Decimal & Decimal::subtractDigits(const Decimal & other)
 {
     extendRange(other);
     byte oLo = other.lsb;
@@ -527,7 +527,7 @@ TempDecimal & TempDecimal::subtractDigits(const TempDecimal & other)
     return *this;
 }
 
-TempDecimal & TempDecimal::truncate(int places)
+Decimal & Decimal::truncate(int places)
 {
     //out of range - either 0 or overflow
     if (places <= -maxIntegerDigits)
@@ -549,7 +549,7 @@ TempDecimal & TempDecimal::truncate(int places)
 }
 
 
-size32_t TempDecimal::getStringLength() const
+size32_t Decimal::getStringLength() const
 {
     int lo, hi;
     clip(lo, hi);
@@ -567,7 +567,7 @@ size32_t TempDecimal::getStringLength() const
 }
 
 
-void TempDecimal::getCString(size32_t length, char * buffer) const
+void Decimal::getCString(size32_t length, char * buffer) const
 {
     unsigned len = getStringLength();
     if (len >= length)
@@ -582,7 +582,7 @@ void TempDecimal::getCString(size32_t length, char * buffer) const
     buffer[len] = 0;
 }
 
-char * TempDecimal::getCString() const
+char * Decimal::getCString() const
 {
     unsigned len = getStringLength();
     char * buffer = (char *)malloc(len+1);
@@ -593,7 +593,7 @@ char * TempDecimal::getCString() const
 }
 
 
-void TempDecimal::getDecimal(byte length, byte precision, void * buffer, byte signs) const
+void Decimal::getDecimal(byte length, byte precision, void * buffer, byte signs) const
 {
     doGetDecimal(length, 2*length-1, precision, buffer);
     byte sign = negative ? (signs & 0x0f) : (signs >> 4);
@@ -601,7 +601,7 @@ void TempDecimal::getDecimal(byte length, byte precision, void * buffer, byte si
 }
 
 
-__int64 TempDecimal::getInt64() const
+__int64 Decimal::getInt64() const
 {
     unsigned __int64 value = getUInt64();
     if (negative)
@@ -610,7 +610,7 @@ __int64 TempDecimal::getInt64() const
 }
 
 
-int TempDecimal::getInt() const
+int Decimal::getInt() const
 {
     unsigned int value = getUInt();
     if (negative)
@@ -619,7 +619,7 @@ int TempDecimal::getInt() const
 }
 
 
-double TempDecimal::getReal() const
+double Decimal::getReal() const
 {
     int lo, hi;
     clip(lo, hi);
@@ -659,7 +659,7 @@ double TempDecimal::getReal() const
 }
 
 
-void TempDecimal::getString(size32_t length, char * buffer) const
+void Decimal::getString(size32_t length, char * buffer) const
 {
     unsigned len = getStringLength();
     if (len > length)
@@ -674,7 +674,7 @@ void TempDecimal::getString(size32_t length, char * buffer) const
 }
 
 
-void TempDecimal::getStringX(size32_t & length, char * & buffer) const
+void Decimal::getStringX(size32_t & length, char * & buffer) const
 {
     unsigned len = getStringLength();
     buffer = (char *)malloc(len);
@@ -684,13 +684,13 @@ void TempDecimal::getStringX(size32_t & length, char * & buffer) const
 }
 
 
-void TempDecimal::getUDecimal(byte length, byte precision, void * buffer) const
+void Decimal::getUDecimal(byte length, byte precision, void * buffer) const
 {
     doGetDecimal(length, 2*length, precision, buffer);
 }
 
 
-unsigned int TempDecimal::getUInt() const
+unsigned int Decimal::getUInt() const
 {
     const unsigned hi = msb;
     unsigned int value = 0;
@@ -716,7 +716,7 @@ unsigned int TempDecimal::getUInt() const
 }
 
 
-unsigned __int64 TempDecimal::getUInt64() const
+unsigned __int64 Decimal::getUInt64() const
 {
     //MORE: This isn't the most efficient way of doing it - see num2str in jutil for some hints.
     const unsigned hi = msb;
@@ -743,17 +743,17 @@ unsigned __int64 TempDecimal::getUInt64() const
 }
 
 
-void TempDecimal::overflow()
+void Decimal::overflow()
 {
 }
 
 
-void TempDecimal::set(const TempDecimal & value)
+void Decimal::set(const Decimal & value)
 {
     memcpy(this, &value, sizeof(*this));
 }
 
-void TempDecimal::setCString(const char * buffer)
+void Decimal::setCString(const char * buffer)
 {
     const char * cur = buffer;
     while (*cur == ' ')
@@ -798,7 +798,7 @@ void TempDecimal::setCString(const char * buffer)
 }
 
 
-void TempDecimal::setDecimal(byte length, byte precision, const void * _buffer)
+void Decimal::setDecimal(byte length, byte precision, const void * _buffer)
 {
     const byte * buffer = (const byte *)_buffer;
     lsb = zeroDigit - precision;
@@ -829,7 +829,7 @@ void TempDecimal::setDecimal(byte length, byte precision, const void * _buffer)
 }
 
 
-void TempDecimal::setInt64(__int64 value)
+void Decimal::setInt64(__int64 value)
 {
     if (value >= 0)
         setUInt64((unsigned __int64)value);
@@ -841,7 +841,7 @@ void TempDecimal::setInt64(__int64 value)
 }
 
 
-void TempDecimal::setInt(int value)
+void Decimal::setInt(int value)
 {
     if (value >= 0)
         setUInt((unsigned int)value);
@@ -852,7 +852,7 @@ void TempDecimal::setInt(int value)
     }
 }
 
-void TempDecimal::setReal(double value)
+void Decimal::setReal(double value)
 {
     setZero();
 
@@ -906,7 +906,7 @@ void TempDecimal::setReal(double value)
 }
 
 
-void TempDecimal::setString(size32_t length, const char * buffer)
+void Decimal::setString(size32_t length, const char * buffer)
 {
     const char * limit = buffer+length;
     const char * cur = buffer;
@@ -953,7 +953,7 @@ void TempDecimal::setString(size32_t length, const char * buffer)
 }
 
 
-void TempDecimal::setUInt(unsigned int value)
+void Decimal::setUInt(unsigned int value)
 {
     negative = false;
     lsb = zeroDigit;
@@ -969,7 +969,7 @@ void TempDecimal::setUInt(unsigned int value)
 }
 
 
-void TempDecimal::setUInt64(unsigned __int64 value)
+void Decimal::setUInt64(unsigned __int64 value)
 {
     negative = false;
     //MORE: This isn't the most efficient way of doing it - see num2str in jutil for some hints.
@@ -986,7 +986,7 @@ void TempDecimal::setUInt64(unsigned __int64 value)
 }
 
 
-void TempDecimal::setUDecimal(byte length, byte precision, const void * _buffer)
+void Decimal::setUDecimal(byte length, byte precision, const void * _buffer)
 {
     const byte * buffer = (const byte *)_buffer;
     lsb = zeroDigit - precision;
@@ -1003,7 +1003,7 @@ void TempDecimal::setUDecimal(byte length, byte precision, const void * _buffer)
 
 //-- helper functions:
 
-void TempDecimal::clip(int & newLsb, int & newMsb) const
+void Decimal::clip(int & newLsb, int & newMsb) const
 {
     int lo = lsb;
     int hi = msb;
@@ -1015,7 +1015,7 @@ void TempDecimal::clip(int & newLsb, int & newMsb) const
     newMsb = hi;
 }
 
-void TempDecimal::clip(int & newLsb, int & newMsb, unsigned minLsb, unsigned maxMsb) const
+void Decimal::clip(int & newLsb, int & newMsb, unsigned minLsb, unsigned maxMsb) const
 {
     clip(newLsb, newMsb);
     if (newLsb < (int)minLsb)
@@ -1026,7 +1026,7 @@ void TempDecimal::clip(int & newLsb, int & newMsb, unsigned minLsb, unsigned max
         newMsb = newLsb-1;
 }
 
-unsigned TempDecimal::doGetString(char * buffer) const
+unsigned Decimal::doGetString(char * buffer) const
 {
     char * cur = buffer;
     int lo, hi;
@@ -1076,7 +1076,7 @@ unsigned TempDecimal::doGetString(char * buffer) const
 }
 
 
-void TempDecimal::doGetDecimal(byte length, byte maxDigits, byte precision, void * buffer) const
+void Decimal::doGetDecimal(byte length, byte maxDigits, byte precision, void * buffer) const
 {
     int tgtHighPos = zeroDigit+maxDigits-precision-1;
     int tgtLowPos = tgtHighPos - length*2 + 1;
@@ -1132,14 +1132,14 @@ void TempDecimal::doGetDecimal(byte length, byte maxDigits, byte precision, void
     }
 }
 
-void TempDecimal::doPower(unsigned value)
+void Decimal::doPower(unsigned value)
 {
     if (value == 1)
         return;
 
     if (value & 1)
     {
-        TempDecimal saved(*this);
+        Decimal saved(*this);
         doPower(value >> 1);
         multiply(*this);
         multiply(saved);
@@ -1151,7 +1151,7 @@ void TempDecimal::doPower(unsigned value)
     }
 }
 
-void TempDecimal::setZero()
+void Decimal::setZero()
 {
     negative = false;
     lsb = msb = zeroDigit;

+ 74 - 58
rtl/nbcd/nbcd.hpp

@@ -31,27 +31,43 @@
 
 template <byte length, byte precision> class decimal;
 
-class nbcd_decl TempDecimal
+/*
+ * Decimal implements Binary Coded Decimal (BCD) arithmetic.
+ *
+ * The internal representation is an array of digits, with size
+ * equals maxDigits, divided in two sections:
+ *  * 0~max/2: integer part
+ *  * max/2+1~max: decimal part
+ *
+ * The decimal point is always in the middle and msb and lsb
+ * point to the beginning of the integer part and the end
+ * of the decimal part. Sign is a boolean flag, but represented
+ * with standard C/D/F flags (+/-/unsigned) in BCD format.
+ *
+ * This class is notably used in the Decimal run-time library
+ * (nbcds.cpp), providing decimal arithmetic to ECL programs.
+ */
+class nbcd_decl Decimal
 {
 public:
-    TempDecimal() {} // does no initialization...
-    TempDecimal(const TempDecimal & other);
+    Decimal() { setZero(); }
+    Decimal(const Decimal & other);
 
-    TempDecimal & abs();
-    TempDecimal & add(const TempDecimal & other);
+    Decimal & abs();
+    Decimal & add(const Decimal & other);
     int compareNull() const;
-    int compare(const TempDecimal & other) const;
-    TempDecimal & divide(const TempDecimal & other);
-    TempDecimal & modulus(const TempDecimal & other);
-    TempDecimal & multiply(const TempDecimal & other);
-    TempDecimal & negate();
-    TempDecimal & power(int value);
-    TempDecimal & power(unsigned value);
-    TempDecimal & round(int places=0);      // -ve means left of decimal point e.g., -3 = to nearest 1000.
-    TempDecimal & roundup(int places=0);        // -ve means left of decimal point e.g., -3 = to nearest 1000.
-    TempDecimal & setPrecision(byte numDigits, byte precision);
-    TempDecimal & subtract(const TempDecimal & other);
-    TempDecimal & truncate(int places=0);
+    int compare(const Decimal & other) const;
+    Decimal & divide(const Decimal & other);
+    Decimal & modulus(const Decimal & other);
+    Decimal & multiply(const Decimal & other);
+    Decimal & negate();
+    Decimal & power(int value);
+    Decimal & power(unsigned value);
+    Decimal & round(int places=0);      // -ve means left of decimal point e.g., -3 = to nearest 1000.
+    Decimal & roundup(int places=0);        // -ve means left of decimal point e.g., -3 = to nearest 1000.
+    Decimal & setPrecision(byte numDigits, byte precision);
+    Decimal & subtract(const Decimal & other);
+    Decimal & truncate(int places=0);
 
     size32_t getStringLength() const;
     void getCString(size32_t length, char * buffer) const;
@@ -69,7 +85,7 @@ public:
     void getClipPrecision(unsigned & digits, unsigned & precision);
     void getPrecision(unsigned & digits, unsigned & precison);
 
-    void set(const TempDecimal & value);
+    void set(const Decimal & value);
     void setCString(const char * buffer);
     void setDecimal(byte length, byte precision, const void * buffer);
     void setInt64(__int64 value);
@@ -83,25 +99,25 @@ public:
 
 #ifdef DECIMAL_OVERLOAD
     template <byte length, byte precision> 
-    TempDecimal(const decimal<length, precision> & x)   { setDecimal(length, precision, &x); }
-    inline TempDecimal(int value)                               { setInt(value); }
-    inline TempDecimal(unsigned value)                          { setUInt(value); }
-    inline TempDecimal(__int64 value)                           { setInt64(value); }
-    inline TempDecimal(unsigned __int64 value)                  { setUInt64(value); }
-    inline TempDecimal(double value)                            { setReal(value); }
-    inline TempDecimal(const char * value)                      { setCString(value); }
-
-    inline TempDecimal & operator = (int value)                 { setInt(value); return *this; }
-    inline TempDecimal & operator = (unsigned value)            { setUInt(value); return *this; }
-    inline TempDecimal & operator = (__int64 value)             { setInt64(value); return *this; }
-    inline TempDecimal & operator = (unsigned __int64 value)    { setUInt64(value); return *this; }
-    inline TempDecimal & operator = (double value)              { setReal(value); return *this; }
-    inline TempDecimal & operator = (const char * value)        { setCString(value); return *this; }
+    Decimal(const decimal<length, precision> & x)   { setDecimal(length, precision, &x); }
+    inline Decimal(int value)                               { setInt(value); }
+    inline Decimal(unsigned value)                          { setUInt(value); }
+    inline Decimal(__int64 value)                           { setInt64(value); }
+    inline Decimal(unsigned __int64 value)                  { setUInt64(value); }
+    inline Decimal(double value)                            { setReal(value); }
+    inline Decimal(const char * value)                      { setCString(value); }
+
+    inline Decimal & operator = (int value)                 { setInt(value); return *this; }
+    inline Decimal & operator = (unsigned value)            { setUInt(value); return *this; }
+    inline Decimal & operator = (__int64 value)             { setInt64(value); return *this; }
+    inline Decimal & operator = (unsigned __int64 value)    { setUInt64(value); return *this; }
+    inline Decimal & operator = (double value)              { setReal(value); return *this; }
+    inline Decimal & operator = (const char * value)        { setCString(value); return *this; }
 #endif
 
 protected:
-    TempDecimal & addDigits(const TempDecimal & other);
-    TempDecimal & subtractDigits(const TempDecimal & other);
+    Decimal & addDigits(const Decimal & other);
+    Decimal & subtractDigits(const Decimal & other);
     void clip(int & newLsb, int & newMsb) const;
     void clip(int & newLsb, int & newMsb, unsigned minLsb, unsigned maxMsb) const;
     void doGetDecimal(byte length, byte maxDigits, byte precision, void * buffer) const;
@@ -109,24 +125,24 @@ protected:
 
     unsigned doGetString(char * target) const;
     void extendRange(byte oLsb, byte oMsb);
-    void extendRange(const TempDecimal & other)     { extendRange(other.lsb, other.msb); }
+    void extendRange(const Decimal & other)     { extendRange(other.lsb, other.msb); }
     void overflow();
 
 private:
-    TempDecimal & incLSD();
+    Decimal & incLSD();
 
 protected:
     enum { 
-        maxDigits=MAX_DECIMAL_DIGITS,
-        maxPrecision=MAX_DECIMAL_PRECISION,
-        maxIntegerDigits=MAX_DECIMAL_LEADING,
-        lastDigit = maxDigits-1, 
-        zeroDigit = (maxDigits-maxIntegerDigits), 
+        maxDigits=MAX_DECIMAL_DIGITS,             // Total buffer size (integer+decimal)
+        maxPrecision=MAX_DECIMAL_PRECISION,       // Size of decimal part
+        maxIntegerDigits=MAX_DECIMAL_LEADING,     // Size of integer part
+        lastDigit = maxDigits-1,                  // Last decimal digit
+        zeroDigit = (maxDigits-maxIntegerDigits), // Unity digit (decimal point)
     };
-    byte digits[maxDigits];                 // stored little endian.
-    byte msb;
-    byte lsb;
-    byte negative;                          // byte to allow ^ operation
+    byte digits[maxDigits];                       // stored little endian.
+    byte msb;                                     // Most significant integer digit
+    byte lsb;                                     // Least significant decimal digit
+    byte negative;                                // byte to allow ^ operation
 };
 
 
@@ -135,7 +151,7 @@ class decimal
 {
 public:
     decimal()                               { memset(buffer, 0, length); }
-    decimal(const TempDecimal & other)      { other.getDecimal(length, precision, buffer); }
+    decimal(const Decimal & other)      { other.getDecimal(length, precision, buffer); }
 
 protected:
     byte buffer[length];
@@ -146,24 +162,24 @@ class udecimal
 {
 public:
     udecimal()                              { memset(buffer, 0, length); }
-    udecimal(const TempDecimal & other)     { other.getUDecimal(length, precision, buffer); }
+    udecimal(const Decimal & other)     { other.getUDecimal(length, precision, buffer); }
 
 protected:
     byte buffer[length];
 };
 
 #ifdef DECIMAL_OVERLOAD
-inline TempDecimal operator + (const TempDecimal & left, const TempDecimal & right) { return TempDecimal(left).add(right); }
-inline TempDecimal operator - (const TempDecimal & left, const TempDecimal & right) { return TempDecimal(left).subtract(right); }
-inline TempDecimal operator * (const TempDecimal & left, const TempDecimal & right) { return TempDecimal(left).multiply(right); }
-inline TempDecimal operator / (const TempDecimal & left, const TempDecimal & right) { return TempDecimal(left).divide(right); }
-inline TempDecimal operator % (const TempDecimal & left, const TempDecimal & right) { return TempDecimal(left).modulus(right); }
-inline bool operator == (const TempDecimal & left, const TempDecimal & right) { return left.compare(right) == 0; }
-inline bool operator != (const TempDecimal & left, const TempDecimal & right) { return left.compare(right) != 0; }
-inline bool operator >= (const TempDecimal & left, const TempDecimal & right) { return left.compare(right) >= 0; }
-inline bool operator <= (const TempDecimal & left, const TempDecimal & right) { return left.compare(right) <= 0; }
-inline bool operator > (const TempDecimal & left, const TempDecimal & right) { return left.compare(right) > 0; }
-inline bool operator < (const TempDecimal & left, const TempDecimal & right) { return left.compare(right) < 0; }
+inline Decimal operator + (const Decimal & left, const Decimal & right) { return Decimal(left).add(right); }
+inline Decimal operator - (const Decimal & left, const Decimal & right) { return Decimal(left).subtract(right); }
+inline Decimal operator * (const Decimal & left, const Decimal & right) { return Decimal(left).multiply(right); }
+inline Decimal operator / (const Decimal & left, const Decimal & right) { return Decimal(left).divide(right); }
+inline Decimal operator % (const Decimal & left, const Decimal & right) { return Decimal(left).modulus(right); }
+inline bool operator == (const Decimal & left, const Decimal & right) { return left.compare(right) == 0; }
+inline bool operator != (const Decimal & left, const Decimal & right) { return left.compare(right) != 0; }
+inline bool operator >= (const Decimal & left, const Decimal & right) { return left.compare(right) >= 0; }
+inline bool operator <= (const Decimal & left, const Decimal & right) { return left.compare(right) <= 0; }
+inline bool operator > (const Decimal & left, const Decimal & right) { return left.compare(right) > 0; }
+inline bool operator < (const Decimal & left, const Decimal & right) { return left.compare(right) < 0; }
 #endif
 
 bool dec2Bool(size32_t bytes, const void * data);

+ 5 - 5
rtl/nbcd/nbcds.cpp

@@ -35,7 +35,7 @@ nbcd_decl void _fastcall  DecUnlock()
     bcdCriticalSection.leave();
 }
 
-static TempDecimal stack[32];
+static Decimal stack[32];
 unsigned  curStack;
 
 
@@ -253,10 +253,10 @@ nbcd_decl void _fastcall  DecRoundTo(unsigned places)
 
 nbcd_decl void _fastcall  DecSwap()
 {
-    char temp[sizeof(TempDecimal)];
-    memcpy(&temp, &stack[curStack-1], sizeof(TempDecimal));
-    memcpy(&stack[curStack-1], &stack[curStack-2], sizeof(TempDecimal));
-    memcpy(&stack[curStack-2], &temp, sizeof(TempDecimal));
+    char temp[sizeof(Decimal)];
+    memcpy(&temp, &stack[curStack-1], sizeof(Decimal));
+    memcpy(&stack[curStack-1], &stack[curStack-2], sizeof(Decimal));
+    memcpy(&stack[curStack-2], &temp, sizeof(Decimal));
 }
 
 

+ 204 - 128
rtl/nbcd/nbcdtest.cpp

@@ -28,12 +28,51 @@ const char * hex = "0123456789ABCDEF";
 
 #ifdef _USE_CPPUNIT
 #include <cppunit/extensions/HelperMacros.h>
-#define ASSERT(a) { if (!(a)) CPPUNIT_ASSERT(a); }
+
+// Usage: success &= check(statement, "error: foo bar %d", variable);
+static bool check(bool condition, const char *fmt, ...) __attribute__((format(printf, 2, 3)));
+static bool check(bool condition, const char *fmt, ...)
+{
+    if (!condition)
+    {
+        va_list args;
+        va_start(args, fmt);
+        VALOG(MCdebugInfo, unknownJob, fmt, args);
+        va_end(args);
+    }
+    return condition;
+}
+
+// Usage: cppunit_assert(statement, "error: foo bar %d", variable));
+static void cppunit_assert(bool condition, const char *fmt, ...) __attribute__((format(printf, 2, 3)));
+static void cppunit_assert(bool condition, const char *fmt, ...)
+{
+    if (!condition)
+    {
+        va_list args;
+        va_start(args, fmt);
+        VALOG(MCdebugInfo, unknownJob, fmt, args);
+        va_end(args);
+        CPPUNIT_ASSERT(!"Please refer to the errors above");
+    }
+}
+// Do not use: cppunit_cppunit_assert(condition, "string")), as that will print the string twice
 
 class NBcdTest : public CppUnit::TestFixture  
 {
     CPPUNIT_TEST_SUITE(NBcdTest);
-        CPPUNIT_TEST(testBcd);
+        CPPUNIT_TEST(testBcdUninitialized);
+        CPPUNIT_TEST(testBcdCString);
+        CPPUNIT_TEST(testBcdRoundTruncate);
+        CPPUNIT_TEST(testBcdDecimal);
+        CPPUNIT_TEST(testBcdInt);
+        CPPUNIT_TEST(testBcdMultiply);
+        CPPUNIT_TEST(testBcdDivideModulus);
+        CPPUNIT_TEST(testBcdCompare);
+        // Failing tests (due to precision)
+        CPPUNIT_TEST(testBcdRandom);
+        CPPUNIT_TEST(testBcdPower);
+        CPPUNIT_TEST(testBcdPrecision);
     CPPUNIT_TEST_SUITE_END();
 protected:
 
@@ -53,134 +92,155 @@ protected:
     {
         if (!right) right = left;
         char temp[80];
-        TempDecimal a = left;
-        TempDecimal b = right;
+        Decimal a = left;
+        Decimal b = right;
         a.multiply(b);
         a.getCString(sizeof(temp), temp);
-        ASSERT(strcmp(expected, temp) == 0);
+        cppunit_assert(strcmp(expected, temp) == 0, "ERROR: testMultiply/getCString: expected '%s', got '%s'", expected, temp);
         DecPushCString(left);
         DecPushCString(right);
         DecMul();
         DecPopCString(sizeof(temp),temp);
-        ASSERT(strcmp(expected, temp) == 0);
+        cppunit_assert(strcmp(expected, temp) == 0, "ERROR: testMultiply/DecMul: expected '%s', got '%s'", expected, temp);
     }
 
     void testDivide(const char * left, const char * right, const char * expected)
     {
         char temp[80];
-        TempDecimal a = left;
-        TempDecimal b = right;
+        Decimal a = left;
+        Decimal b = right;
         a.divide(b);
         a.getCString(sizeof(temp), temp);
-        ASSERT(strcmp(expected, temp) == 0);
+        cppunit_assert(strcmp(expected, temp) == 0, "ERROR: testDivide/getCString: expected '%s', got '%s'", expected, temp);
         DecPushCString(left);
         DecPushCString(right);
         DecDivide();
         DecPopCString(sizeof(temp),temp);
-        ASSERT(strcmp(expected, temp) == 0);
+        cppunit_assert(strcmp(expected, temp) == 0, "ERROR: testDivide/DecDivide: expected '%s', got '%s'", expected, temp);
     }
 
     void testCompare(const char * left, const char * right, int expected)
     {
-        TempDecimal a = left;
-        TempDecimal b = right;
+        Decimal a = left;
+        Decimal b = right;
         int temp = a.compare(b);
-        ASSERT(temp == expected);
+        cppunit_assert(temp == expected, "ERROR: testCompare/positive: expected '%d', got '%d'", expected, temp);
         temp = b.compare(a);
-        ASSERT(temp == -expected);
+        cppunit_assert(temp == -expected, "ERROR: testCompare/negative: expected '%d', got '%d'", expected, temp);
 
         DecPushCString(left);
         DecPushCString(right);
         temp = DecDistinct();
-        ASSERT(expected == temp);
+        cppunit_assert(expected == temp, "ERROR: testCompare/DecDistinct: expected '%d', got '%d'", expected, temp);
     }
 
     void testModulus(const char * left, const char * right, const char * expected)
     {
         char temp[80];
-        TempDecimal a = left;
-        TempDecimal b = right;
+        Decimal a = left;
+        Decimal b = right;
         a.modulus(b);
         a.getCString(sizeof(temp), temp);
-        ASSERT(strcmp(expected, temp) == 0);
+        cppunit_assert(strcmp(expected, temp) == 0, "ERROR: testModulus: expected '%s', got '%s'", expected, temp);
     }
 
-    void checkDecimal(const TempDecimal & value, const char * expected)
+    void checkDecimal(const Decimal & value, const char * expected)
     {
         char temp[80];
         value.getCString(sizeof(temp), temp);
-        ASSERT(strcmp(expected, temp) == 0);
+        cppunit_assert(strcmp(expected, temp) == 0, "ERROR: checkDecimal/char: expected '%s', got '%s'", expected, temp);
     }
 
-    void checkDecimal(const TempDecimal & value, unsigned __int64 expected)
+    void checkDecimal(const Decimal & value, unsigned __int64 expected)
     {
         unsigned __int64 temp = value.getUInt64();
-        ASSERT(expected == temp)
+        cppunit_assert(expected == temp, "ERROR: checkDecimal/uint64: expected '%" I64F "d', got '%" I64F "d'", expected, temp);
     }
 
-    void checkDecimal(const TempDecimal & value, __int64 expected)
+    void checkDecimal(const Decimal & value, __int64 expected)
     {
         __int64 temp = value.getInt64();
-        ASSERT(expected == temp);
+        cppunit_assert(expected == temp, "ERROR: checkDecimal/int64: expected '%" I64F "d', got '%" I64F "d'", expected, temp);
     }
 
     void checkBuffer(const void * buffer, const char * expected)
     {
         char temp[40];
         expandHex(buffer, strlen(expected)/2, temp);
-        ASSERT(strcmp(expected, temp) == 0);
+        cppunit_assert(strcmp(expected, temp) == 0, "ERROR: checkBuffer: expected '%s', got '%s'", expected, temp);
     }
 
-
-    void testRandom()
+    // ========================================================= UNIT TESTS BELOW
+    void testBcdRandom()
     {
-        unsigned __int64 val1 = (rand() << 16) | rand();
-        unsigned __int64 val2 = (rand() << 16) | rand();
-        unsigned __int64 val3 = (rand() << 16) | rand();
-        unsigned __int64 val4 = (rand() << 16) | rand();
-
-        for (int i = 0; i < 2; i++)
+        for (int i = 0; i < 1000; i++)
         {
-            TempDecimal d1 = val1;
-            TempDecimal d2 = val2;
-            TempDecimal d3 = val3;
-            TempDecimal d4 = val4;
-
-            d1.multiply(d2);
-            d3.multiply(d4);
-            checkDecimal(d1, val1*val2);
-            checkDecimal(d3, val3*val4);
-            d2.set(d1);
-            d1.subtract(d3);
-            d2.add(d3);
-            checkDecimal(d1, (__int64)(val1*val2-val3*val4));
-            checkDecimal(d2, (val1*val2+val3*val4));
+            // 14-digit numbers, multiplications can't pass 28 digits (32 max)
+            unsigned __int64 val1 = ((__int64) rand() << 16) | rand();
+            unsigned __int64 val2 = ((__int64) rand() << 16) | rand();
+            unsigned __int64 val3 = ((__int64) rand() << 16) | rand();
+            unsigned __int64 val4 = ((__int64) rand() << 16) | rand();
+
+            for (int i = 0; i < 2; i++)
+            {
+                Decimal d1 = val1;
+                Decimal d2 = val2;
+                Decimal d3 = val3;
+                Decimal d4 = val4;
+
+                d1.multiply(d2);
+                d3.multiply(d4);
+                checkDecimal(d1, val1*val2);
+                checkDecimal(d3, val3*val4);
+                d2.set(d1);
+                d1.subtract(d3);
+                d2.add(d3);
+                checkDecimal(d1, (__int64)(val1*val2-val3*val4));
+                checkDecimal(d2, (val1*val2+val3*val4));
+            }
         }
     }
     
-    void testBcd()
+    void testBcdUninitialized()
+    {
+        // Test uninitialised
+        Decimal zero, one=1, two(2);
+        checkDecimal(zero, 0ULL);
+        checkDecimal(one, 1ULL);
+        checkDecimal(two, 2ULL);
+        zero.add(one);
+        checkDecimal(zero, 1ULL);
+        zero.multiply(two);
+        checkDecimal(zero, 2ULL);
+    }
+
+    void testBcdCString()
     {
-        TempDecimal a,b,c;
+        Decimal a,b,c;
         a.setString(10,"1234.56789");   // 1234.56789
         b.setString(8,"  123456.88");   // 123456
         c.setString(6," 0.123 ");
 
         char temp[80];
         a.getCString(sizeof(temp), temp);
-        DBGLOG("a = %s", temp);
+        check(strcmp("1234.56789", temp) == 0, "ERROR: testBcdCString/a: expected '1234.56789', got '%s'", temp);
         b.getCString(sizeof(temp), temp);
-        DBGLOG("b = %s", temp);
+        check(strcmp("123456", temp) == 0, "ERROR: testBcdCString/b: expected '123456', got '%s'", temp);
         c.getCString(sizeof(temp), temp);
-        DBGLOG("c = %s", temp);
+        check(strcmp("0.123", temp) == 0, "ERROR: testBcdCString/c: expected '0.123', got '%s'", temp);
 
         a.add(b);
         a.getCString(sizeof(temp), temp);
-        DBGLOG("a+b = %s", temp);
+        check(strcmp("124690.56789", temp) == 0, "ERROR: testBcdCString/a+b: expected '124690.56789', got '%s'", temp);
         b.subtract(a);
         b.getCString(sizeof(temp), temp);
-        DBGLOG("-a = %s", temp);
+        check(strcmp("-1234.56789", temp) == 0, "ERROR: testBcdCString/-a: expected '-1234.56789', got '%s'", temp);
+    }
 
-        c = "9.53456";
+    void testBcdRoundTruncate()
+    {
+        char temp[80];
+        Decimal c = "9.53456";
         checkDecimal(c, "9.53456");
         c.round(4);
         checkDecimal(c,"9.5346");
@@ -196,11 +256,6 @@ protected:
         c.round(-3);
         checkDecimal(c, "1235000");
 
-        c = 1234567.8901234567;
-        c.getCString(sizeof(temp), temp);
-        DBGLOG("1234567.89012346 = %s (cstr)", temp);
-        DBGLOG("1234567.89012346 = %.8f (real)", c.getReal());
-
         c = "9.53456";
         c.truncate(4);
         checkDecimal(c, "9.5345");
@@ -211,7 +266,49 @@ protected:
         c.truncate();
         checkDecimal(c, "9");
 
-        a = "123.2345";
+        Decimal x1 = 1;
+        x1.round(-3);
+        checkDecimal(x1, (__int64)0);
+        Decimal x2 = 100;
+        x2.round(-3);
+        checkDecimal(x2, (__int64)0);
+        Decimal x3 = 499;
+        x3.round(-3);
+        checkDecimal(x3, (__int64)0);
+        Decimal x4 = 500;
+        x4.round(-3);
+        checkDecimal(x4, (__int64)1000);
+        Decimal x5 = 1000;
+        x5.round(-3);
+        checkDecimal(x5, (__int64)1000);
+        Decimal x6 = 1499;
+        x6.round(-3);
+        checkDecimal(x6, (__int64)1000);
+        Decimal x7 = 1500;
+        x7.round(-3);
+        checkDecimal(x7, (__int64)2000);
+        Decimal x8 = 10000;
+        x8.round(-3);
+        checkDecimal(x8, (__int64)10000);
+        Decimal x9 = 10499;
+        x9.round(-3);
+        checkDecimal(x9, (__int64)10000);
+        Decimal x10 = 10500;
+        x10.round(-3);
+        checkDecimal(x10, (__int64)11000);
+        Decimal x11 = -10500;
+        x11.round(-3);
+        checkDecimal(x11, (__int64)-11000);
+
+        c = 1234567.8901234567; // Expect rounding of the last digit
+        c.getCString(sizeof(temp), temp);
+        cppunit_assert(strcmp("1234567.890123457", temp) == 0, "ERROR: testBcdRoundTruncate/cstr: expected '1234567.890123457', got '%s'", temp);
+        cppunit_assert(c.getReal() == 1234567.890123457, "ERROR: testBcdRoundTruncate/real: expected '1234567.890123457', got '%.8f'", c.getReal());
+    }
+
+    void testBcdDecimal()
+    {
+        Decimal a = "123.2345";
         unsigned decBufferSize=5;
         char decBuffer[7];
         char * decBufferPtr = decBuffer+1;
@@ -294,30 +391,37 @@ protected:
         checkDecimal(a, "1234567");
         a.setDecimal(5, 8, decBufferPtr);
         checkDecimal(a, "0.01234567");
+    }
 
+    void testBcdInt()
+    {
+        Decimal a, b;
         for (unsigned i1 = 0; i1 <= 1000; i1++)
         {
             a = i1;
-            ASSERT(a.getUInt() == i1);
+            cppunit_assert(a.getUInt() == i1, "ERROR: testBcdInt/getUInt: expected '%d', got '%d'", i1, a.getUInt());
         }
         for (unsigned i3 = 0; i3 <= 100; i3++)
         {
             a = i3;
             b = 10;
             a.multiply(b);
-            ASSERT(a.getUInt() == i3*10);
+            cppunit_assert(a.getUInt() == i3*10, "ERROR: testBcdInt/getUInt*3: expected '%d', got '%d'", i3*10, a.getUInt());
         }
 
         for (unsigned i2 = 0; i2 <= 100; i2++)
         {
-            TempDecimal x = i2;
-            TempDecimal y = 100;
+            Decimal x = i2;
+            Decimal y = 100;
             y.multiply(x);
-            ASSERT(100*i2 == (unsigned)y.getInt());
+            cppunit_assert(100*i2 == (unsigned)y.getInt(), "ERROR: testBcdInt/getInt*100: expected '%d', got '%d'", 100*i2, y.getInt());
             x.multiply(x);
-            ASSERT(i2*i2 == (unsigned)x.getInt());
+            cppunit_assert(i2*i2 == (unsigned)x.getInt(), "ERROR: testBcdInt/getInt*getInt: expected '%d', got '%d'", i2*i2, x.getInt());
         }
+    }
 
+    void testBcdMultiply()
+    {
         testMultiply("-1","0","0");
         testMultiply("-1","2","-2");
         testMultiply("-1","-2","2");
@@ -336,13 +440,18 @@ protected:
         testMultiply("101","99009901","10000000001");
         testMultiply("0.000000000000000101","0.0000000000000000099009901","0");
         testMultiply("0.000000000000000101","0.000000000000000099009901","0.00000000000000000000000000000001");
+        testMultiply("109", "9174311926605504587155963302.75229357798165137614678899082568", "999999999999999999999999999999.99999999999999999999999999999912");
 
-        a = "9999999999999999";
-        b = "10000000000000002";
+        Decimal a = "9999999999999999";
+        Decimal b = "10000000000000002";
+        char temp[80];
         a.multiply(b);
         a.getCString(sizeof(temp), temp);
-        DBGLOG("9999999999999999*10000000000000002=%s (overflow)",temp);
+        cppunit_assert(strcmp("9999999999999998", temp) == 0, "ERROR: testBcdMultiply/overflow: expected '9999999999999998', got '%s'", temp);
+    }
 
+    void testBcdDivideModulus()
+    {
         //Divide
         testDivide("1","1","1");
         testDivide("125","5","25");
@@ -351,8 +460,6 @@ protected:
         testDivide("0.1234","20000000000000000000000000000000","0");
         testDivide("1","0.00000000000000000000000000000002", "50000000000000000000000000000000");
         testDivide("1","3", "0.33333333333333333333333333333333");
-
-        testMultiply("109", "9174311926605504587155963302.75229357798165137614678899082568", "999999999999999999999999999999.99999999999999999999999999999912");
         testDivide("1000000000000000000000000000000","109", "9174311926605504587155963302.75229357798165137614678899082568");
         testModulus("1000000000000000000000000000000","109", "82");
         testModulus("10","5","0");
@@ -360,7 +467,10 @@ protected:
         testModulus("10","-6","4");
         testModulus("-10","6","-4");
         testModulus("-10","-6","-4");
+    }
 
+    void testBcdCompare()
+    {
         testCompare("1","1.0000",0);
         testCompare("-1","1.0000",-1);
         testCompare("1","-1.0000",+1);
@@ -386,43 +496,45 @@ protected:
         testCompare("-1234.999","-1234.99",-1);
         testCompare("-1234.989","-1234.99",+1);
 
+    }
+
+    void testBcdPower()
+    {
         //MORE: Test power functions...
         const char * values[] = { "0.00001", "10000", "-1", "-10", "1.0001", "9.99" };
-        TempDecimal one(1);
+        Decimal one(1);
         for (unsigned idx = 0; idx < _elements_in(values); idx++)
         {
-            TempDecimal value = values[idx];
-            TempDecimal sofar1 = 1;
-            TempDecimal sofar2 = 1;
+            Decimal value = values[idx];
+            Decimal sofar1 = 1;
+            Decimal sofar2 = 1;
 
+            bool success=true;
             for (int power = 0; power < 10; power++)
             {
-                TempDecimal powerValue1 = values[idx];
-                TempDecimal powerValue2 = values[idx];
+                Decimal powerValue1 = values[idx];
+                Decimal powerValue2 = values[idx];
                 powerValue1.power(power);
                 powerValue2.power(-power);
 
                 char temp1[80], temp2[80], temp3[80];
                 if (sofar1.compare(powerValue1) != 0)
                 {
-                    TempDecimal diff = powerValue1;
+                    Decimal diff = powerValue1;
                     diff.subtract(sofar1);
                     sofar1.getCString(sizeof(temp1), temp1);
                     powerValue1.getCString(sizeof(temp2), temp2);
                     diff.getCString(sizeof(temp3), temp3);
-                    DBGLOG("ERROR: %s^%d=%s (expected %s) diff %s", values[idx], power, temp2, temp1, temp3);
-                    ASSERT(!"nbcd power operation failed");
+                    success &= check(false, "ERROR: %s^%d=%s (expected %s) diff %s", values[idx], power, temp2, temp1, temp3);
                 }
                 if (sofar2.compare(powerValue2) != 0)
                 {
-                    TempDecimal diff = powerValue2;
+                    Decimal diff = powerValue2;
                     diff.subtract(sofar2);
                     sofar2.getCString(sizeof(temp1), temp1);
                     powerValue2.getCString(sizeof(temp2), temp2);
                     diff.getCString(sizeof(temp3), temp3);
-                    DBGLOG("ERROR: %s^%d=%s (expected %s) diff %s", values[idx], -power, temp2, temp1, temp3);
-                    //Report a message, but not an error, because rounding errors are fairly unavoidable.
-                    //ASSERT(!"nbcd power operation failed");
+                    success &= check(false, "ERROR: %s^%d=%s (expected %s) diff %s", values[idx], -power, temp2, temp1, temp3);
                 }
 
                 //internal consistency test, but liable to rounding errors....
@@ -431,56 +543,24 @@ protected:
                     powerValue1.multiply(powerValue2);
                     if (power && (powerValue1.compareNull() != 0) && (powerValue1.compare(one) != 0))
                     {
-                        TempDecimal diff = powerValue1;
+                        Decimal diff = powerValue1;
                         diff.subtract(one);
                         one.getCString(sizeof(temp1), temp1);
                         powerValue1.getCString(sizeof(temp2), temp2);
                         diff.getCString(sizeof(temp3), temp3);
-                        DBGLOG("ERROR: %s^%d^-%d=%s (expected %s) diff %s", values[idx], power, power, temp2, temp1, temp3);
-                        //Report a message, but not an error, because rounding errors are fairly unavoidable.
-                        //ASSERT(!"nbcd power operation failed");
+                        success &= check(false, "ERROR: %s^%d^-%d=%s (expected %s) diff %s", values[idx], power, power, temp2, temp1, temp3);
                     }
                 }
 
                 sofar1.multiply(value);
                 sofar2.divide(value);
             }
+            cppunit_assert(success, "ERROR: testBcdPower: one or more errors detected above.");
         }
+    }
 
-        TempDecimal x1 = 1;
-        x1.round(-3);
-        checkDecimal(x1, (__int64)0);
-        TempDecimal x2 = 100;
-        x2.round(-3);
-        checkDecimal(x2, (__int64)0);
-        TempDecimal x3 = 499;
-        x3.round(-3);
-        checkDecimal(x3, (__int64)0);
-        TempDecimal x4 = 500;
-        x4.round(-3);
-        checkDecimal(x4, (__int64)1000);
-        TempDecimal x5 = 1000;
-        x5.round(-3);
-        checkDecimal(x5, (__int64)1000);
-        TempDecimal x6 = 1499;
-        x6.round(-3);
-        checkDecimal(x6, (__int64)1000);
-        TempDecimal x7 = 1500;
-        x7.round(-3);
-        checkDecimal(x7, (__int64)2000);
-        TempDecimal x8 = 10000;
-        x8.round(-3);
-        checkDecimal(x8, (__int64)10000);
-        TempDecimal x9 = 10499;
-        x9.round(-3);
-        checkDecimal(x9, (__int64)10000);
-        TempDecimal x10 = 10500;
-        x10.round(-3);
-        checkDecimal(x10, (__int64)11000);
-        TempDecimal x11 = -10500;
-        x11.round(-3);
-        checkDecimal(x11, (__int64)-11000);
-
+    void testBcdPrecision()
+    {
         //check rounding is done correctly to number of significant digits
         checkDecimal(9999999.12, "9999999.12");
         checkDecimal(-9999999.12, "-9999999.12");
@@ -494,15 +574,11 @@ protected:
         checkDecimal(99999991234567890.00, "99999991234567900");
         checkDecimal(-99999991234567890.00, "-99999991234567900");
 
-
-// in vc++ these real constants seem to only have 14 significant digits
+        // in vc++ these real constants seem to only have 14 significant digits
 //      checkDecimal(0.99999991234567800, "0.999999912345678");
 //      checkDecimal(0.99999991234567890, "0.999999912345679");
 //      checkDecimal(0.099999991234567800, "0.0999999912345678");
 //      checkDecimal(0.099999991234567890, "0.0999999912345679");
-
-        for (int i = 0; i < 1000; i++)
-            testRandom();
     }
 };