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