Date: Thursday, March 9, 2006 @ 10:46:04
  Author: gilles
    Path: /cvsroot/carob/carob

Modified: include/BigDecimal.hpp (1.15 -> 1.16) src/BigDecimal.cpp (1.19
          -> 1.20)

Implemented double and float conversion
Improved toBigInteger()
Fixed wstring conversion for numbers between 0 and 1
Improved conversion to int/long/int64 for numbers between 0 and 1
Added TODOs

Some more testing remains to be done.
Partly fixes CAROB-68


------------------------+
 include/BigDecimal.hpp |   12 +++++++
 src/BigDecimal.cpp     |   76 +++++++++++++++++++++++++++++++++++++++--------
 2 files changed, 76 insertions(+), 12 deletions(-)


Index: carob/include/BigDecimal.hpp
diff -u carob/include/BigDecimal.hpp:1.15 carob/include/BigDecimal.hpp:1.16
--- carob/include/BigDecimal.hpp:1.15   Tue Mar  7 12:29:39 2006
+++ carob/include/BigDecimal.hpp        Thu Mar  9 10:46:04 2006
@@ -92,6 +92,18 @@
    * @throw ConversionException if the value is to big to be converted
    */ 
   operator int64_t() const throw (ConversionException);
+  /**
+   * Convertion to float
+   * TODO: exact behavior description
+   * @throw ConversionException if the value is to big to be converted
+   */ 
+  operator float() const throw (ConversionException);
+  /**
+   * Convertion to double
+   * TODO: exact behavior description
+   * @throw ConversionException if the value is to big to be converted
+   */ 
+  operator double() const throw (ConversionException);
 protected:
   /**
    * Converts this BigDecimal's absolute value to a GMP integer by scaling
Index: carob/src/BigDecimal.cpp
diff -u carob/src/BigDecimal.cpp:1.19 carob/src/BigDecimal.cpp:1.20
--- carob/src/BigDecimal.cpp:1.19       Tue Mar  7 12:48:25 2006
+++ carob/src/BigDecimal.cpp    Thu Mar  9 10:46:04 2006
@@ -27,7 +27,6 @@
 #include "Common.hpp"
 
 #include <locale>
-
 #include <sstream> //for wostringstream
 
 using std::wstring;
@@ -99,6 +98,9 @@
   input>>this->signum;
   
   //2. Read scale
+  // TODO: what if this scale is negative ? from java it should never be, but
+  // should we check ? because afterwards, we do implicit conversions to uint
+  // see toBigInteger() or operator double() 
   input>>this->scale;
 
   //3. Compute gmp value
@@ -113,21 +115,20 @@
     mpz_clear(imported);
   }
   
-  // FIXME TODO: if ODBC/odbsequoia doesn't need the byte array, we should
+  // TODO: if ODBC/odbsequoia doesn't need the byte array, we should
   // delete and throw away the byte array now.
 }
-
 mpz_class BigDecimal::toBigInteger() const
 {
   if (scale == 0)
     return unscaled_value;
 
+  // TODO: optimization = if scale > number of digits in unscaled_value, 
return 0
+
   //we have to apply scale
-  mpz_t scaler; // will be 10^scale
-  mpz_init(scaler);
-  mpz_ui_pow_ui(scaler, 10, scale);
-  mpz_class ret = unscaled_value / mpz_class(scaler);
-  mpz_tdiv_q (ret.get_mpz_t(), unscaled_value.get_mpz_t(), scaler);
+  mpz_t scaler; mpz_init(scaler);                       //int scaler;
+  mpz_ui_pow_ui(scaler, 10, scale);                     //scaler = 10^scale;
+  mpz_class ret = unscaled_value / mpz_class(scaler);   //ret = unscaled_value 
/ scaler;
   mpz_clear(scaler);
   return ret;
 }
@@ -148,6 +149,7 @@
   return mag;
 }
 
+// FIXME: this function can be optimized: lots of front-inserts can be avoided
 BigDecimal::operator wstring() const
 {
   wstring sRet(L"0");
@@ -157,12 +159,19 @@
     std::ostringstream buffer;
     buffer << unscaled_value;
     sRet = fromString(buffer.str());
-    //Add the '.' TODO: get this separator from locale
-    if (sRet.length()-scale > 0 && scale != 0)
+    int sRetLength = static_cast<int>(sRet.length());
+    if (scale != 0)
     {
+      if (sRetLength <= scale)
+      {
+        // add heading zeros as needed
+        sRet.insert(0, scale - sRetLength + 1, L'0');
+      }
+      // insert the decimal point
       wchar_t decimal_point = std::use_facet<std::numpunct<wchar_t> 
>(std::locale()).decimal_point();
       sRet.insert(sRet.length()-scale, 1, decimal_point);
     }
+    // and the optional sign
     if (signum < 0)
       sRet.insert(0, L"-");
 
@@ -175,6 +184,8 @@
   if (signum == 0)
     return 0;
   mpz_class scaled_int = toBigInteger();
+  if (mpz_cmp_d(scaled_int.get_mpz_t(), 0) == 0) // if scaled_int == 0
+    return 0;
   // Check we can convert to int
   if (signum>0)
   {
@@ -210,6 +221,8 @@
   if (signum == 0)
     return 0;
   mpz_class scaled_int = toBigInteger();
+  if (mpz_cmp_d(scaled_int.get_mpz_t(), 0) == 0) // if scaled_int == 0
+    return 0;
   // Check we can convert to int
   if (signum>0)
   {
@@ -234,7 +247,8 @@
   if (signum == 0)
     return 0;
   mpz_class scaled_int = toBigInteger();
-
+  if (mpz_cmp_d(scaled_int.get_mpz_t(), 0) == 0) // if scaled_int == 0
+    return 0;
   // check size
   size_t nbBitsNeeded = mpz_sizeinbase(scaled_int.get_mpz_t(), 2);
   if (signum > 0)
@@ -248,7 +262,7 @@
   if (mag_length <= 0) //should not happen, but safer
   {
     throw (ConversionException(L"BigDecimal " + static_cast<wstring>(*this)
-        + L" could not be converted to int"));
+        + L" could not be converted to int64"));
   }
 
   int64_t result = 0;
@@ -262,3 +276,41 @@
   return result;
 }
 
+BigDecimal::operator float() const throw (ConversionException)
+{
+  // TODO: check that we can represent the big decimal by comparing:
+  // log2(this) < log2(std::numeric_limits<float>::max())
+  // idem with min, -min and max negative values
+    return (static_cast<float>(operator double()));
+}
+
+BigDecimal::operator double() const throw (ConversionException)
+{
+  // TODO: check that we can represent the big decimal by comparing:
+  // log2(this) < log2(std::numeric_limits<double>::max())
+  // idem with min, -min and max negative values
+
+                                                      // understandable 
c-style translation...
+
+  mpf_t res; mpf_init(res);                           // float res;
+  mpf_t unscaled; mpf_init(unscaled);                 // float unscaled;
+  mpf_t scaler; mpf_init(scaler);                     // int scaler;
+
+  // initialize res and scale to double values so the mpf_t will have the 
right precision
+  mpf_set_d(res, static_cast<double>(0));             // res = (double)0;
+  mpf_set_d(scaler, static_cast<double>(10));         // scaler = (double)10;
+  mpf_pow_ui(scaler, scaler, scale);                  // scaler = scaler^scale;
+  mpf_set_z(unscaled, unscaled_value.get_mpz_t());    // unscaled = 
unscaled_value;
+  mpf_div(res, unscaled, scaler);                     // ret = unscaled/scaler;
+  if (signum < 0)
+    mpf_neg(res, res);                                // ret = -ret;
+  double ret = mpf_get_d(res);
+
+  mpf_clear(scaler);
+  mpf_clear(unscaled);
+  mpf_clear(res);
+
+  return ret;
+}
+
+

_______________________________________________
Carob-commits mailing list
[email protected]
https://forge.continuent.org/mailman/listinfo/carob-commits

Reply via email to