Date: Friday, March 3, 2006 @ 18:18:15
Author: gilles
Path: /cvsroot/carob/carob
Modified: Makefile (1.33 -> 1.34) include/BigDecimal.hpp (1.13 -> 1.14)
src/BigDecimal.cpp (1.16 -> 1.17)
Implemented BigDecimal::operator wstring() using GMP
Lots of temporary code for remaining or non-working other operators
------------------------+
Makefile | 3
include/BigDecimal.hpp | 52 ++++----
src/BigDecimal.cpp | 280 ++++++++++++++++-------------------------------
3 files changed, 126 insertions(+), 209 deletions(-)
Index: carob/Makefile
diff -u carob/Makefile:1.33 carob/Makefile:1.34
--- carob/Makefile:1.33 Tue Feb 14 18:35:47 2006
+++ carob/Makefile Fri Mar 3 18:18:15 2006
@@ -66,6 +66,9 @@
#CXXFLAGS += -DCAROB_USE_LOG4CXX
#LDFLAGS += -llog4cxx
+# for GMP
+LDFLAGS += -lgmpxx -lgmp
+
#Doc
# DOC_DIR is duplicated in Doxyfile
DOC_DIR = doxygen
Index: carob/include/BigDecimal.hpp
diff -u carob/include/BigDecimal.hpp:1.13 carob/include/BigDecimal.hpp:1.14
--- carob/include/BigDecimal.hpp:1.13 Thu Jan 26 12:12:53 2006
+++ carob/include/BigDecimal.hpp Fri Mar 3 18:18:15 2006
@@ -25,6 +25,7 @@
#include "CarobException.hpp"
#include "Common.hpp" //for java_byte and ResultSetDataType
+#include <gmpxx.h>
#include <string>
namespace CarobNS {
@@ -65,10 +66,29 @@
BigDecimal::BigDecimal(const DriverSocket& input)
throw (SocketIOException, UnexpectedException);
/**
- * Convertion to string. Handy for displaying the number
- * FIXME: This is dummy code for now (testing state), correct it
+ * Converts this BigDecimal to a GMP integer
+ */
+ mpz_class toBigInteger() const;
+ /**
+ * Convertion to string.
+ * A leading minus sign is used to indicate sign, and the number of digits to
+ * the right of the decimal point is used to indicate scale.
*/
operator std::wstring() const;
+ /**
+ * Convertion to int.
+ * Any fractional part of this BigDecimal will be discarded, and if the
+ * resulting "BigInteger" is too big to fit in an int, only the low-order 32
+ * bits are returned
+ */
+ operator int() const;
+ /**
+ * Convertion to long.
+ * Any fractional part of this BigDecimal will be discarded, and if the
+ * resulting "BigInteger" is too big to fit in a long, only the low-order
+ * 64 bits are returned
+ */
+ operator long() const;
private:
/** Length of the unscaled value java_byte-array */
@@ -81,34 +101,12 @@
java_byte* byteArray;
/** Scale of this BigDecimal. */
- int32_t scale;
+ int scale;
/** Sign (+ or - or 0) */
int signum;
- /**
- * Converts internal 2's complement java_byte array to an array of ints
- * @param intArrayLength (out) size of the generated int array
- * @return converted int array
- */
- int* toIntArray(int& intArrayLength) const;
-
- /**
- * Returns a copy of the member java_byte array stripped of any leading zero
- * bytes.
- * @param intArrayLength (out) size of the generated int array
- * @return stripped java_byte array as an int array
- */
- int* stripByteArrayLeadingZeroBytes(int& intArrayLength) const;
- /**
- * From the member array representing a negative 2's-complement number,
- * returns the minimal (no leading zero bytes) unsigned whose value is -a
into
- * an array of int
- * @param intArrayLength (out) size of the generated int array
- * @return positive int array corresponding to the java_byte array
- */
- int* makeByteArrayPositive(int& intArrayLength) const;
-
-
+ /** Unscaled value as a GMP integer */
+ mpz_class unscaled_value;
};
} //namespace CarobNS
Index: carob/src/BigDecimal.cpp
diff -u carob/src/BigDecimal.cpp:1.16 carob/src/BigDecimal.cpp:1.17
--- carob/src/BigDecimal.cpp:1.16 Wed Feb 15 11:03:42 2006
+++ carob/src/BigDecimal.cpp Fri Mar 3 18:18:15 2006
@@ -23,11 +23,14 @@
#include "DriverSocket.hpp"
#include "Common.hpp"
+#include <iostream> // REMOVE ME !
+#include <sstream> //for wostringstream
+
using std::wstring;
using namespace CarobNS;
-BigDecimal::BigDecimal()
+BigDecimal::BigDecimal() : unscaled_value(0)
{
byteArrayLength = 0;
byteArray = NULL;
@@ -44,7 +47,7 @@
}
BigDecimal::BigDecimal(const DriverSocket& input)
- throw (SocketIOException, UnexpectedException)
+ throw (SocketIOException, UnexpectedException) : unscaled_value(0)
{
//1. Read intVal:
//1.1 Read intValLength
@@ -56,7 +59,7 @@
if (this->byteArrayLength == 0)
{
//This is a zero, no byte array
- // FIXME: for safety, create an empty byte array instead
+ // FIXME: for safety, create an empty byte array instead ?
;
}
else
@@ -87,204 +90,117 @@
this->byteArray[idx+3] = static_cast<java_byte> (wordRead &0xFF);
}
}
-
- // UNTESTED
+
// 1.4 read sign
input>>this->signum;
//2. Read scale
input>>this->scale;
-}
-int* BigDecimal::toIntArray(int& intArrayLength) const
-{
- if (byteArrayLength == 0)
- return NULL;
-
- int* intArray;
- int signum = 0;
- if (byteArray[0] < 0)
- {
- intArray = makeByteArrayPositive(intArrayLength);
- signum = -1;
- }
- else
+ //3. Compute gmp value
+ if (signum != 0)// 0 signum means 0 value => no useless computations !
{
- intArray = stripByteArrayLeadingZeroBytes(intArrayLength);
- signum = (intArrayLength == 0 ? 0 : 1);
+ // convert byte array into and unscaled int
+ mpz_t imported;
+ mpz_init(imported);
+ mpz_import(imported, byteArrayLength, 1 /*MSB 1st*/,
+ sizeof(java_byte), 1 /*MSB 1st*/, 0, byteArray);
+ unscaled_value = static_cast<mpz_class>(imported);
+ mpz_clear(imported);
+#if 0
+ mpz_t unscaledVal;
+ mpz_init(unscaledVal);
+ // convert byte array into and unscaled int
+ mpz_import(unscaledVal, byteArrayLength, 1 /*MSB 1st*/,
+ sizeof(java_byte), 1 /*MSB 1st*/, 0, byteArray);
+ // apply scale
+ mpz_t scaler; // will be 10^scale
+ mpz_init(scaler);
+ mpq_t rat_scaler;
+ mpq_init(rat_scaler);
+ mpz_ui_pow_ui(scaler, 10, scale);
+ mpf_init2(gmp_value, mpz_sizeinbase(unscaledVal, 2/*binary*/) + 2); // + 1
for '.'
+ mpq_t rat_uv;
+ mpq_init(rat_uv);
+ mpq_set_z(rat_uv, unscaledVal);
+ mpq_set_z(rat_scaler, scaler);
+ mpq_div(rat_uv, rat_uv, rat_scaler);
+ mpf_set_q(gmp_value, rat_uv);
+ // free tmp data
+ mpq_clear(rat_uv);
+ mpq_clear(rat_scaler);
+ mpz_clear(scaler);
+ mpz_clear(unscaledVal);
+ if (signum < 0)
+ {
+ mpf_neg(gmp_value, gmp_value);
+ }
+#endif
}
- return intArray;
}
-
-int* BigDecimal::stripByteArrayLeadingZeroBytes(int& intArrayLength) const
-{
- unsigned int keep;
- // Find first nonzero byte
- for (keep=0; keep<byteArrayLength && byteArray[keep]==0; keep++);
-
- // Allocate new array and copy relevant part of input array
- intArrayLength = ((byteArrayLength - keep) + 3)/4;
- int* result = new int[intArrayLength];
- int b = byteArrayLength - 1;
- for (int i = intArrayLength-1; i >= 0; i--)
- {
- result[i] = byteArray[b--] & 0xff;
- int bytesRemaining = b - keep + 1;
- int bytesToTransfer = std::min(3, bytesRemaining);
- for (int j=8; j <= 8*bytesToTransfer; j += 8)
- result[i] |= ((byteArray[b--] & 0xff) << j);
- }
- return result;
-}
-
-int* BigDecimal::makeByteArrayPositive(int& intArrayLength) const
-{
- unsigned int keep, k;
-
- // Find first non-sign (0xff) byte of input
- for (keep=0; keep<byteArrayLength && byteArray[keep]==-1; keep++)
- ;
-
- /* Allocate output array. If all non-sign bytes are 0x00, we must
- * allocate space for one extra output byte. */
- for (k=keep; k<byteArrayLength && byteArray[k]==0; k++)
- ;
-
- int extraByte = (k==byteArrayLength) ? 1 : 0;
- intArrayLength = ((byteArrayLength - keep + extraByte) + 3)/4;
- int* result = new int[intArrayLength];
-
- /* Copy one's complement of input into into output, leaving extra
- * byte (if it exists) == 0x00 */
- int b = byteArrayLength - 1;
- for (int i = intArrayLength-1; i >= 0; i--)
- {
- result[i] = byteArray[b--] & 0xff;
- unsigned int numBytesToTransfer = std::min(3, static_cast<int>(b-keep+1));
- if (numBytesToTransfer < 0)
- numBytesToTransfer = 0;
- for (unsigned int j=8; j <= 8*numBytesToTransfer; j += 8)
- result[i] |= ((byteArray[b--] & 0xff) << j);
-
- // Mask indicates which bits must be complemented
- int mask = ((uint32_t)-1 >> 8*(3-numBytesToTransfer));
- result[i] = ~result[i] & mask;
- }
-
- // Add one to one's complement to generate two's complement
- for (int i=intArrayLength-1; i>=0; i--)
- {
- result[i] = (result[i] & 0xffffffffL) + 1;
- if (result[i] != 0)
- break;
- }
- return result;
+/**
+ * Converts this BigDecimal to a GMP integer
+ */
+mpz_class BigDecimal::toBigInteger() const
+{
+ if (scale == 0)
+ return unscaled_value;
+ 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_clear(scaler);
+ return ret;
}
BigDecimal::operator wstring() const
{
- // !!!!!!! THAT IS JUST A DUMMY FUNCTION FOR TESTING !!!!!!
-/* wstring sRet;
- int idx = 0, word = 0;
- int padding = byteArrayLength%4;
- if (padding > 0)
+ wstring sRet(L"0");
+ if (signum != 0) // 0 signum means 0 value => no useless computations !
{
- for (idx=0; idx<padding; idx++)
+ //convert to string, then to wstring (no direct mpz->wstring converter)
+ 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)
{
- word |= ((int)byteArray[idx] & 0xFF) << (8*(padding-idx-1));
+ sRet.insert(sRet.length()-scale, L".");
}
- sRet+=toWString(word);
- }
- for (; idx<byteArrayLength; idx+=4)
- {
- word = ((int)byteArray[idx] & 0xFF) << 24
- | ((int)byteArray[idx+1] & 0xFF) << 16
- | ((int)byteArray[idx+2] & 0xFF) << 8
- | (int)byteArray[idx+3] & 0xFF;
- sRet+=toWString(word);
- }
- for (int i=0; i<byteArrayLength; i++)
- {
- if (i==0 && (int)byteArray[i] == 0)
- continue;
- sRet+=toWString((int)byteArray[i]);
+ if (signum < 0)
+ sRet.insert(0, L"-");
}
-*/
- wstring sRet;
- if (signum == 0)
- sRet = L'0';
- else if (signum < 0)
- sRet = L'-';
- // else this is a +, we don't put it
-
- int l = 0;
- int* test = toIntArray(l);
- for (int i=0; i<l; i++)
- {
- sRet+=toWString(test[i]);
- }
- //Add the '.'
- if (sRet.length()-scale > 0 && scale != 0)
- {
- sRet.insert(sRet.length()-scale,L".");
- }
-
- delete []test;
-
return sRet;
+}
-/* wstring sRet;
+BigDecimal::operator int() const
+{
+ //TODO
+#if 1
+ return 0;
+#else
if (signum == 0)
- sRet = "0";
+ return 0;
+ mpz_class bi(toBigInteger());
+//BYTES_PER_MP_LIMB
+// int bytesPerInt = sizeof(int)/8;
+//mpz_export (void *rop, size_t *countp, int order, int size, int endian,
size_t nails, mpz_t op)
+// mpz_import(imported, byteArrayLength, 1 /*MSB 1st*/,
+ int ret = bi.get_si();
+ return (signum > 0 ? ret : -ret);
+#endif
+}
+
+BigDecimal::operator long() const
+{
+ //TODO
+#if 1
+ return 0;
+#else
if (signum == 0)
- sRet = L'0';
- else if (signum < 0)
- sRet = L'-';
- // else this is a +, we don't put it
-
- int intArrayLength = 0;
- int* intArray = toIntArray(l);
-
- // Compute upper bound on number of digit groups and allocate space
- int maxNumDigitGroups = (4*intArrayLength + 6)/7;
- wstring* digitGroup = new wstring[maxNumDigitGroups];
-
- // Translate number to string, a digit group at a time
- BigDecimal tmp = new BigDecimal();
- tmp.byteArrayLength = byteArrayLength;
- memcpy(tmp.byteArray, byteArray, byteArrayLength);
- int numGroups = 0;
- while (tmp.signum != 0) {
- BigInteger d = longRadix[radix];
-
- MutableBigInteger q = new MutableBigInteger(),
- r = new MutableBigInteger(),
- a = new MutableBigInteger(tmp.mag),
- b = new MutableBigInteger(d.mag);
- a.divide(b, q, r);
- BigInteger q2 = new BigInteger(q, tmp.signum * d.signum);
- BigInteger r2 = new BigInteger(r, tmp.signum * d.signum);
-
- digitGroup[numGroups++] = Long.toString(r2.longValue(), radix);
- tmp = q2;
- }
-
- // Put sign (if any) and first digit group into result buffer
- StringBuffer buf = new StringBuffer(numGroups*digitsPerLong[radix]+1);
- if (signum<0)
- buf.append('-');
- buf.append(digitGroup[numGroups-1]);
-
- // Append remaining digit groups padded with leading zeros
- for (int i=numGroups-2; i>=0; i--) {
- // Prepend (any) leading zeros for this digit group
- int numLeadingZeros = digitsPerLong[radix]-digitGroup[i].length();
- if (numLeadingZeros != 0)
- buf.append(zeros[numLeadingZeros]);
- buf.append(digitGroup[i]);
- }
- return buf.toString();
-*/
-
+ return 0;
+ mpz_class bi(toBigInteger());
+ return (signum > 0 ? bi.get_si() : -bi.get_si());
+#endif
}
-
_______________________________________________
Carob-commits mailing list
[email protected]
https://forge.continuent.org/mailman/listinfo/carob-commits