Date: Tuesday, May 2, 2006 @ 12:34:59
Author: gilles
Path: /cvsroot/carob/carob
Modified: Makefile (1.38 -> 1.39) include/BigDecimal.hpp (1.22 -> 1.23)
src/BigDecimal.cpp (1.26 -> 1.27)
Removed dependency to libgmpxx: use of the C++ wrapper was minimal, having one
less dependency is much better
------------------------+
Makefile | 2
include/BigDecimal.hpp | 9 +-
src/BigDecimal.cpp | 158 +++++++++++++++++++++++++++++++----------------
3 files changed, 113 insertions(+), 56 deletions(-)
Index: carob/Makefile
diff -u carob/Makefile:1.38 carob/Makefile:1.39
--- carob/Makefile:1.38 Mon Apr 24 12:11:16 2006
+++ carob/Makefile Tue May 2 12:34:59 2006
@@ -68,7 +68,7 @@
# mandatory LDFLAGS
override LDFLAGS += -fPIC -shared
# for GMP
-override LDFLAGS += -lgmpxx -lgmp
+override LDFLAGS += -lgmp
ARFLAGS = rcs
LIB_CAROB = carob
Index: carob/include/BigDecimal.hpp
diff -u carob/include/BigDecimal.hpp:1.22 carob/include/BigDecimal.hpp:1.23
--- carob/include/BigDecimal.hpp:1.22 Thu Apr 20 12:26:00 2006
+++ carob/include/BigDecimal.hpp Tue May 2 12:34:59 2006
@@ -36,7 +36,7 @@
// - "Incompatibilities Between ISO C and ISO C++" - David R. Tribble
// - C++ Technical Report 1 (TR1)
-#include <gmpxx.h>
+#include <gmp.h>
#include <string>
#include <sstream>
@@ -204,8 +204,9 @@
/**
* Converts this BigDecimal's absolute value to a GMP integer by scaling
* its unscaled_value (thus discarding fractional part)
+ * @param result the scaled value. Note: result must be initialized !
*/
- mpz_class toBigInteger() const;
+ void toBigInteger(mpz_t result) const;
/**
* Converts the given gmp integer to an array of integers.
* The integer array will be allocated by this function, and must be deleted
@@ -214,7 +215,7 @@
* toBigInteger)
* @param intArrayLength size of the returned array
*/
- int* toIntArray(mpz_class scaled_val, int* intArrayLength) const;
+ int* toIntArray(mpz_t scaled_val, int* intArrayLength) const;
/**
* Convertion to string with the given decimal point
* A leading minus sign is used to indicate sign, and the number of digits to
@@ -237,7 +238,7 @@
/** Sign (+ or - or 0) */
int signum;
/** Unscaled value as a GMP integer */
- mpz_class unscaled_value;
+ mpz_t unscaled_value;
};
} //namespace CarobNS
Index: carob/src/BigDecimal.cpp
diff -u carob/src/BigDecimal.cpp:1.26 carob/src/BigDecimal.cpp:1.27
--- carob/src/BigDecimal.cpp:1.26 Thu Mar 30 14:19:07 2006
+++ carob/src/BigDecimal.cpp Tue May 2 12:34:59 2006
@@ -36,7 +36,6 @@
void BigDecimal::initToZero()
{
- unscaled_value = 0;
byteArrayLength = 0;
byteArray = NULL;
scale = 0;
@@ -45,16 +44,21 @@
BigDecimal::BigDecimal()
{
+ // mpz_init must be called in every constructor and only there. If mpz_init
is
+ // called multiple times, a memory leak will appear !
+ mpz_init(unscaled_value);
initToZero();
}
BigDecimal::BigDecimal(const std::wstring& wstr) throw (ConversionException,
UnexpectedException)
{
+ mpz_init(unscaled_value);
createFromString(StaticCodecs::toString(wstr));
}
BigDecimal::BigDecimal(const std::string& str) throw (ConversionException,
UnexpectedException)
{
+ mpz_init(unscaled_value);
createFromString(str);
}
@@ -91,16 +95,17 @@
scale++;
}
}
- if (mpz_set_str(unscaled_value.get_mpz_t(), unscaledStr.c_str(), 10) != 0)
+ if (mpz_set_str(unscaled_value, unscaledStr.c_str(), 10) != 0)
{
throw ConversionException(fromString(str) + L"does not represent a valid
BigDecimal value", L"FIXME");
}
- if (unscaled_value < 0)
+ int uv_sign = mpz_sgn(unscaled_value);
+ if (uv_sign < 0)
{
- unscaled_value = -unscaled_value;
+ mpz_neg(unscaled_value, unscaled_value);
signum = -1;
}
- else if (unscaled_value == 0)
+ else if (uv_sign == 0)
signum = 0;
else
signum = 1;
@@ -108,6 +113,7 @@
BigDecimal::BigDecimal(const int arg)
{
+ mpz_init(unscaled_value);
initToZero();
if (arg > 0)
signum = 1;
@@ -115,13 +121,14 @@
signum = -1;
else
return;
- mpz_set_si(unscaled_value.get_mpz_t(), arg);
+ mpz_set_si(unscaled_value, arg);
if (signum<0) //take the abs()
- mpz_neg(unscaled_value.get_mpz_t(), unscaled_value.get_mpz_t());
+ mpz_neg(unscaled_value, unscaled_value);
}
BigDecimal::BigDecimal(const long arg)
{
+ mpz_init(unscaled_value);
initToZero();
if (arg > 0L)
signum = 1;
@@ -129,13 +136,14 @@
signum = -1;
else
return;
- mpz_set_si(unscaled_value.get_mpz_t(), arg);
+ mpz_set_si(unscaled_value, arg);
if (signum<0) //take the abs()
- mpz_neg(unscaled_value.get_mpz_t(), unscaled_value.get_mpz_t());
+ mpz_neg(unscaled_value, unscaled_value);
}
BigDecimal::BigDecimal(const int64_t arg)
{
+ mpz_init(unscaled_value);
initToZero();
if (arg > 0)
signum = 1;
@@ -157,7 +165,7 @@
handleMinLL = true;
}
}
- mpz_import (unscaled_value.get_mpz_t(),
+ mpz_import (unscaled_value,
1,
0, // only one "64bits word" to import => order doesn't matter
sizeof(int64_t),
@@ -165,29 +173,33 @@
0, // sign bit has been removed by the previous mask
&import);
if (handleMinLL) // special case, see above min int64 handling
- mpz_add_ui(unscaled_value.get_mpz_t(), unscaled_value.get_mpz_t(), 1);
+ mpz_add_ui(unscaled_value, unscaled_value, 1);
}
#if 0
BigDecimal::BigDecimal(const float arg)
{
+ mpz_init(unscaled_value);
//TODO
}
BigDecimal::BigDecimal(const double)
{
+ mpz_init(unscaled_value);
//TODO
}
#endif
BigDecimal::BigDecimal(const BigDecimal& ref)
{
+ mpz_init(unscaled_value);
*this = ref; //make use of = operator
}
BigDecimal::BigDecimal(const DriverSocket& input)
- throw (SocketIOException, UnexpectedException) : unscaled_value(0)
+ throw (SocketIOException, UnexpectedException)
{
+ mpz_init(unscaled_value);
initToZero();
//1. Read intVal:
//1.1 Read intValLength
@@ -238,12 +250,8 @@
if (signum != 0)// 0 signum means 0 value => no useless computations !
{
// convert byte array into and unscaled int
- mpz_t imported;
- mpz_init(imported);
- mpz_import(imported, byteArrayLength, 1 /*MSB 1st*/,
+ mpz_import(unscaled_value, byteArrayLength, 1 /*MSB 1st*/,
sizeof(java_byte), 1 /*MSB 1st*/, 0, byteArray);
- unscaled_value = static_cast<mpz_class>(imported);
- mpz_clear(imported);
}
// TODO: if ODBC/odbsequoia doesn't need the byte array, we should
@@ -252,6 +260,7 @@
BigDecimal::~BigDecimal()
{
+ mpz_clear(unscaled_value);
if (byteArrayLength > 0 && byteArray != NULL)
{
delete[] byteArray;
@@ -262,7 +271,7 @@
{
signum = ref.signum;
scale = ref.scale;
- unscaled_value = ref.unscaled_value;
+ mpz_set(unscaled_value, ref.unscaled_value);
byteArrayLength = ref.byteArrayLength;
if (byteArrayLength != 0)
{
@@ -280,29 +289,30 @@
{
return (signum == ref.signum
&& scale == ref.scale
- && mpz_cmp(unscaled_value.get_mpz_t(), ref.unscaled_value.get_mpz_t())
== 0);
+ && mpz_cmp(unscaled_value, ref.unscaled_value) == 0);
}
-mpz_class BigDecimal::toBigInteger() const
+void BigDecimal::toBigInteger(mpz_t result) const
{
if (scale == 0)
- return unscaled_value;
-
+ {
+ mpz_set(result, unscaled_value);
+ return;
+ }
// TODO: optimization = if scale > number of digits in unscaled_value,
return 0
// TODO: multiply by 10^(-scale) instead of dividing by 10^(scale)
//we have to apply scale
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_tdiv_q(result, unscaled_value, scaler); //ret =
unscaled_value / scaler;
mpz_clear(scaler);
- return ret;
}
-int* BigDecimal::toIntArray(mpz_class scaled_int, int* mag_length) const
+int* BigDecimal::toIntArray(mpz_t scaled_int, int* mag_length) const
{
- size_t sizeInInts = mpz_size(scaled_int.get_mpz_t()) * sizeof(mp_limb_t)
- / sizeof(int);
+ size_t sizeInInts = mpz_size(scaled_int) * sizeof(mp_limb_t) / sizeof(int);
int* mag = new int[sizeInInts];
size_t exported = 0;
mpz_export(static_cast<void*>(mag), &exported,
@@ -310,7 +320,7 @@
sizeof(int), /*words of integers*/
0, /*native word endianess*/
0, /*full words*/
- scaled_int.get_mpz_t());
+ scaled_int);
*mag_length = static_cast<int>(exported);
return mag;
}
@@ -324,9 +334,27 @@
std::wstring BigDecimal::toString(const wchar_t decimal_point) const
{
//convert to string, then to wstring (no direct mpz->wstring converter)
- std::ostringstream buffer;
- buffer << unscaled_value;
- wstring sRet = fromString(buffer.str());
+ // First compute space needed by the resulting string
+ // number of digits in the unscaled value
+ size_t nbDigits = mpz_sizeinbase(unscaled_value, 10);
+ // the real size needed by the string
+ int size_needed = static_cast<int>(nbDigits);
+ // compute room for heading zeros
+ if (scale > size_needed)
+ size_needed = scale;
+ // add room for the decimal point
+ if (scale != 0)
+ //TODO: rather take decimal point length in case of multi char decimal
point
+ size_needed++;
+ // space for the heading '-' (minus) sign
+ if (signum < 0)
+ size_needed++;
+ char* as_string = new char[size_needed+1]; // +1 for the \0
+
+ gmp_snprintf(as_string, nbDigits+1, "%Zd", unscaled_value);
+
+ wstring sRet = fromString(as_string);
+ delete[] as_string;
int sRetLength = static_cast<int>(sRet.length());
if (scale != 0)
{
@@ -349,25 +377,30 @@
{
if (signum == 0)
return 0;
- mpz_class scaled_int = toBigInteger(); // truncate value
- if (mpz_size(scaled_int.get_mpz_t()) == 0) // ie. if (scaled_int == 0)
+ mpz_t scaled_int; mpz_init(scaled_int);
+ toBigInteger(scaled_int); // truncate value
+ if (mpz_size(scaled_int) == 0) // ie. if (scaled_int == 0)
+ {
+ mpz_clear(scaled_int);
return 0;
+ }
// Check that we can convert to int
// TODO: the same with only one "mpz_fits" and a test on int min
if (signum>0)
{
- if (!mpz_fits_sint_p(scaled_int.get_mpz_t()))
+ if (!mpz_fits_sint_p(scaled_int))
throw (ConversionException(L"BigDecimal " + static_cast<wstring>(*this)
+ L" is to big to be converted into an int", CONV_NUM_RANGE));
}
else
{
// We have to negate the value for the test
- mpz_class tmp;
- mpz_neg(tmp.get_mpz_t(), scaled_int.get_mpz_t());
- if (!mpz_fits_sint_p(tmp.get_mpz_t()))
+ mpz_t tmp; mpz_init(tmp);
+ mpz_neg(tmp, scaled_int);
+ if (!mpz_fits_sint_p(tmp))
throw (ConversionException(L"BigDecimal " + static_cast<wstring>(*this)
+ L" is to big to be converted into an int", CONV_NUM_RANGE));
+ mpz_clear(tmp);
}
int mag_length = -1;
int* mag = toIntArray(scaled_int, &mag_length);
@@ -378,6 +411,8 @@
}
int res = mag[mag_length-1];
delete[] mag;
+ mpz_clear(scaled_int);
+
if (signum < 0)
res = -res;
return res;
@@ -387,37 +422,51 @@
{
if (signum == 0)
return 0;
- mpz_class scaled_int = toBigInteger();
- if (mpz_size(scaled_int.get_mpz_t()) == 0) // ie. if scaled_int == 0
+ mpz_t scaled_int; mpz_init(scaled_int);
+ toBigInteger(scaled_int);
+ if (mpz_size(scaled_int) == 0) // ie. if scaled_int == 0
+ {
+ mpz_clear(scaled_int);
return 0;
+ }
// Check we can convert to int
if (signum>0)
{
- if (!mpz_fits_slong_p(scaled_int.get_mpz_t()))
+ if (!mpz_fits_slong_p(scaled_int))
throw (ConversionException(L"BigDecimal " + static_cast<wstring>(*this)
+ L" is to big to be converted into a long", CONV_NUM_RANGE));
}
else
{
// We have to negate the value for the test
- mpz_class tmp;
- mpz_neg(tmp.get_mpz_t(), scaled_int.get_mpz_t());
- if (!mpz_fits_slong_p(tmp.get_mpz_t()))
+ mpz_t tmp; mpz_init(tmp);
+ mpz_neg(tmp, scaled_int);
+ if (!mpz_fits_slong_p(tmp))
throw (ConversionException(L"BigDecimal " + static_cast<wstring>(*this)
+ L" is to big to be converted into a long", CONV_NUM_RANGE));
+ mpz_clear(tmp);
}
- return (signum > 0 ? scaled_int.get_si() : -scaled_int.get_si());
+ long ret = mpz_get_si(scaled_int);
+ if (signum < 0)
+ ret = -ret;
+ mpz_clear(scaled_int);
+ return ret;
}
+
//TODO: optimize this horribly slow stuff
BigDecimal::operator int64_t() const throw (ConversionException)
{
if (signum == 0)
return 0;
- mpz_class scaled_int = toBigInteger();
- if (mpz_size(scaled_int.get_mpz_t()) == 0) // ie. if scaled_int == 0
+ mpz_t scaled_int; mpz_init(scaled_int);
+ toBigInteger(scaled_int);
+ if (mpz_size(scaled_int) == 0) // ie. if scaled_int == 0
+ {
+ mpz_clear(scaled_int);
return 0;
+ }
// check size
- size_t nbBitsNeeded = mpz_sizeinbase(scaled_int.get_mpz_t(), 2);
+ size_t nbBitsNeeded = mpz_sizeinbase(scaled_int, 2);
if (nbBitsNeeded+1 > sizeof(int64_t)*8) //+1 for the sign bit
{
bool numTooBig = true;
@@ -454,6 +503,8 @@
result = (result<<(8*sizeof(int))) + (mag[i]&0xffffffffLL);
}
delete[] mag;
+ mpz_clear(scaled_int);
+
if (signum < 0)
result = -result;
return result;
@@ -467,11 +518,15 @@
if (signum < 0)
throw (ConversionException(L"BigDecimal " + static_cast<wstring>(*this)
+L" is negative ! it cannot be converted into an int64_t",
CONV_NUM_RANGE));
- mpz_class scaled_int = toBigInteger();
- if (mpz_size(scaled_int.get_mpz_t()) == 0) // ie. if scaled_int == 0
+ mpz_t scaled_int; mpz_init(scaled_int);
+ toBigInteger(scaled_int);
+ if (mpz_size(scaled_int) == 0) // ie. if scaled_int == 0
+ {
+ mpz_clear(scaled_int);
return 0;
+ }
// check size
- size_t nbBitsNeeded = mpz_sizeinbase(scaled_int.get_mpz_t(), 2);
+ size_t nbBitsNeeded = mpz_sizeinbase(scaled_int, 2);
if (nbBitsNeeded > (sizeof(int64_t)*8))
throw (ConversionException(L"BigDecimal " + static_cast<wstring>(*this)
+ L" is too big to be converted into an int64_t", CONV_NUM_RANGE));
@@ -490,6 +545,7 @@
result = (result<<(8*sizeof(int))) + (mag[i]&0xffffffffLL);
}
delete[] mag;
+ mpz_clear(scaled_int);
return result;
}
@@ -517,7 +573,7 @@
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_set_z(unscaled, unscaled_value); // unscaled =
unscaled_value;
mpf_div(res, unscaled, scaler); // ret = unscaled/scaler;
if (signum < 0)
mpf_neg(res, res); // ret = -ret;
_______________________________________________
Carob-commits mailing list
[email protected]
https://forge.continuent.org/mailman/listinfo/carob-commits