#include <limits.h> // for LONG_MAX
-// #define wxUSE_LONGLONG_WX 1 // for testing (VZ)
+// define this to compile wxLongLongWx in "test" mode: the results of all
+// calculations will be compared with the real results taken from
+// wxLongLongNative
+#define wxLONGLONG_TEST_MODE
+
+#ifdef wxLONGLONG_TEST_MODE
+ #define wxUSE_LONGLONG_WX 1
+ #define wxUSE_LONGLONG_NATIVE 1
+#endif // wxLONGLONG_TEST_MODE
// ----------------------------------------------------------------------------
// decide upon which class we will use
// to disable automatic testing (useful for the test program which defines
// both classes) but by default we only use one class
#if (defined(wxUSE_LONGLONG_WX) && wxUSE_LONGLONG_WX) || !defined(wxLongLong_t)
- #undef wxUSE_LONGLONG_NATIVE
- #define wxUSE_LONGLONG_NATIVE 0
+ // don't use both classes unless wxUSE_LONGLONG_NATIVE was explicitly set:
+ // this is useful in test programs nad only there
+ #ifndef wxUSE_LONGLONG_NATIVE
+ #define wxUSE_LONGLONG_NATIVE 0
+ #endif
+
class WXDLLEXPORT wxLongLongWx;
typedef wxLongLongWx wxLongLong;
#else
public:
// ctors
// default ctor initializes to 0
- wxLongLongWx() { m_lo = m_hi = 0; }
+ wxLongLongWx()
+ {
+ m_lo = m_hi = 0;
+
+#ifdef wxLONGLONG_TEST_MODE
+ m_ll = 0;
+
+ Check();
+#endif // wxLONGLONG_TEST_MODE
+ }
// from long
- wxLongLongWx(long l)
- { m_lo = l; m_hi = (l < 0 ? -1l : 0l); }
+ wxLongLongWx(long l) { *this = l; }
// from 2 longs
wxLongLongWx(long hi, unsigned long lo)
- { m_hi = hi; m_lo = lo; }
+ {
+ m_hi = hi;
+ m_lo = lo;
+
+#ifdef wxLONGLONG_TEST_MODE
+ m_ll = hi;
+ m_ll <<= 32;
+ m_ll |= lo;
+
+ Check();
+#endif // wxLONGLONG_TEST_MODE
+ }
// default copy ctor is ok in both cases
// assignment operators
// from long
wxLongLongWx& operator=(long l)
- { m_lo = l; m_hi = (l < 0 ? -1l : 0l); return *this; }
+ {
+ m_lo = l;
+ m_hi = (l < 0 ? -1l : 0l);
+
+#ifdef wxLONGLONG_TEST_MODE
+ m_ll = l;
+
+ Check();
+#endif // wxLONGLONG_TEST_MODE
+
+ return *this;
+ }
// from double
wxLongLongWx& Assign(double d);
// can't have assignment operator from 2 longs
// get absolute value
wxLongLongWx Abs() const { return wxLongLongWx(*this).Abs(); }
- wxLongLongWx& Abs() { if ( m_hi < 0 ) m_hi = -m_hi; return *this; }
+ wxLongLongWx& Abs()
+ {
+ if ( m_hi < 0 )
+ m_hi = -m_hi;
+
+#ifdef wxLONGLONG_TEST_MODE
+ if ( m_ll < 0 )
+ m_ll = -m_ll;
+
+ Check();
+#endif // wxLONGLONG_TEST_MODE
+
+ return *this;
+ }
// convert to long with range checking in the debug mode (only!)
long ToLong() const
{
- wxASSERT_MSG( m_hi == 0l,
+ wxASSERT_MSG( (m_hi == 0l) || (m_hi == -1l),
_T("wxLongLong to long conversion loss of precision") );
return (long)m_lo;
wxLongLongWx& operator++();
// post increment operator
- wxLongLongWx& operator++(int);
+ wxLongLongWx& operator++(int) { return ++(*this); }
// negation operator
wxLongLongWx operator-() const;
+ wxLongLongWx& Negate();
// subraction
wxLongLongWx operator-(const wxLongLongWx& ll) const;
wxLongLongWx& operator--();
// post decrement operator
- wxLongLongWx& operator--(int);
+ wxLongLongWx& operator--(int) { return --(*this); }
// shifts
// left shift
friend ostream& operator<<(ostream&, const wxLongLongWx&);
#endif // wxUSE_STD_IOSTREAM
- void *asArray(void) const;
+ void *asArray() const;
private:
// long is at least 32 bits, so represent our 64bit number as 2 longs
long m_hi; // signed bit is in the high part
unsigned long m_lo;
+
+#ifdef wxLONGLONG_TEST_MODE
+ void Check()
+ {
+ wxASSERT( (m_ll >> 32) == m_hi && (unsigned long)m_ll == m_lo );
+ }
+
+ wxLongLong_t m_ll;
+#endif // wxLONGLONG_TEST_MODE
};
#endif // wxUSE_LONGLONG_WX
// what to test?
//#define TEST_ARRAYS
-#define TEST_CMDLINE
+//#define TEST_CMDLINE
//#define TEST_DIR
//#define TEST_LOG
//#define TEST_LONGLONG
//#define TEST_MIME
//#define TEST_STRINGS
//#define TEST_THREADS
-//#define TEST_TIME
+#define TEST_TIME
// ============================================================================
// implementation
#include <wx/longlong.h>
#include <wx/timer.h>
+// make a 64 bit number from 4 16 bit ones
+#define MAKE_LL(x1, x2, x3, x4) wxLongLong((x1 << 16) | x2, (x3 << 16) | x3)
+
+// get a random 64 bit number
+#define RAND_LL() MAKE_LL(rand(), rand(), rand(), rand())
+
+#if wxUSE_LONGLONG_NATIVE
+inline bool operator==(const wxLongLongWx& a, const wxLongLongNative& b)
+ { return a.GetHi() == b.GetHi() && a.GetLo() == b.GetLo(); }
+inline bool operator==(const wxLongLongNative& a, const wxLongLongWx& b)
+ { return a.GetHi() == b.GetHi() && a.GetLo() == b.GetLo(); }
+#endif // wxUSE_LONGLONG_NATIVE
+
static void TestSpeed()
{
static const long max = 100000000;
}
}
-static void TestDivision()
+static void TestLongLongConversion()
{
- puts("*** Testing wxLongLong division ***\n");
+ puts("*** Testing wxLongLong conversions ***\n");
+
+ wxLongLong a;
+ size_t nTested = 0;
+ for ( size_t n = 0; n < 100000; n++ )
+ {
+ a = RAND_LL();
+
+#if wxUSE_LONGLONG_NATIVE
+ wxLongLongNative b(a.GetHi(), a.GetLo());
- #define MAKE_LL(x1, x2, x3, x4) wxLongLong((x1 << 16) | x2, (x3 << 16) | x3)
+ wxASSERT_MSG( a == b, "conversions failure" );
+#else
+ puts("Can't do it without native long long type, test skipped.");
- // seed pseudo random generator
- srand((unsigned)time(NULL));
+ return;
+#endif // wxUSE_LONGLONG_NATIVE
+
+ if ( !(nTested % 1000) )
+ {
+ putchar('.');
+ fflush(stdout);
+ }
+
+ nTested++;
+ }
+
+ puts(" done!");
+}
+
+static void TestMultiplication()
+{
+ puts("*** Testing wxLongLong multiplication ***\n");
+
+ wxLongLong a, b;
+ size_t nTested = 0;
+ for ( size_t n = 0; n < 100000; n++ )
+ {
+ a = RAND_LL();
+ b = RAND_LL();
+
+#if wxUSE_LONGLONG_NATIVE
+ wxLongLongNative aa(a.GetHi(), a.GetLo());
+ wxLongLongNative bb(b.GetHi(), b.GetLo());
+
+ wxASSERT_MSG( a*b == aa*bb, "multiplication failure" );
+#else // !wxUSE_LONGLONG_NATIVE
+ puts("Can't do it without native long long type, test skipped.");
+
+ return;
+#endif // wxUSE_LONGLONG_NATIVE
+
+ if ( !(nTested % 1000) )
+ {
+ putchar('.');
+ fflush(stdout);
+ }
+
+ nTested++;
+ }
+
+ puts(" done!");
+}
+
+static void TestDivision()
+{
+ puts("*** Testing wxLongLong division ***\n");
wxLongLong q, r;
size_t nTested = 0;
q = ll / l;
r = ll % l;
+#if wxUSE_LONGLONG_NATIVE
+ wxLongLongNative m(ll.GetHi(), ll.GetLo());
+
+ wxLongLongNative p = m / l, s = m % l;
+ wxASSERT_MSG( q == p && r == s, "division failure" );
+#else // !wxUSE_LONGLONG_NATIVE
// verify the result
wxASSERT_MSG( ll == q*l + r, "division failure" );
+#endif // wxUSE_LONGLONG_NATIVE
if ( !(nTested % 1000) )
{
}
puts(" done!");
+}
- #undef MAKE_LL
+static void TestAddition()
+{
+ puts("*** Testing wxLongLong addition ***\n");
+
+ wxLongLong a, b, c;
+ size_t nTested = 0;
+ for ( size_t n = 0; n < 100000; n++ )
+ {
+ a = RAND_LL();
+ b = RAND_LL();
+ c = a + b;
+
+#if wxUSE_LONGLONG_NATIVE
+ wxASSERT_MSG( c == wxLongLongNative(a.GetHi(), a.GetLo()) +
+ wxLongLongNative(b.GetHi(), b.GetLo()),
+ "addition failure" );
+#else // !wxUSE_LONGLONG_NATIVE
+ wxASSERT_MSG( c - b == a, "addition failure" );
+#endif // wxUSE_LONGLONG_NATIVE
+
+ if ( !(nTested % 1000) )
+ {
+ putchar('.');
+ fflush(stdout);
+ }
+
+ nTested++;
+ }
+
+ puts(" done!");
}
+static void TestBitOperations()
+{
+ puts("*** Testing wxLongLong bit operation ***\n");
+
+ wxLongLong a, c;
+ size_t nTested = 0;
+ for ( size_t n = 0; n < 100000; n++ )
+ {
+ a = RAND_LL();
+
+#if wxUSE_LONGLONG_NATIVE
+ for ( size_t n = 0; n < 33; n++ )
+ {
+ wxLongLongNative b(a.GetHi(), a.GetLo());
+
+ b >>= n;
+ c = a >> n;
+
+ wxASSERT_MSG( b == c, "bit shift failure" );
+
+ b = wxLongLongNative(a.GetHi(), a.GetLo()) << n;
+ c = a << n;
+
+ wxASSERT_MSG( b == c, "bit shift failure" );
+ }
+
+#else // !wxUSE_LONGLONG_NATIVE
+ puts("Can't do it without native long long type, test skipped.");
+
+ return;
+#endif // wxUSE_LONGLONG_NATIVE
+
+ if ( !(nTested % 1000) )
+ {
+ putchar('.');
+ fflush(stdout);
+ }
+
+ nTested++;
+ }
+
+ puts(" done!");
+}
+
+#undef MAKE_LL
+#undef RAND_LL
+
#endif // TEST_LONGLONG
// ----------------------------------------------------------------------------
#endif // TEST_THREADS
#ifdef TEST_LONGLONG
+ // seed pseudo random generator
+ srand((unsigned)time(NULL));
+
if ( 0 )
+ {
TestSpeed();
- if ( 1 )
+ }
+ TestMultiplication();
+ if ( 0 )
+ {
TestDivision();
+ TestAddition();
+ TestLongLongConversion();
+ TestBitOperations();
+ }
#endif // TEST_LONGLONG
#ifdef TEST_MIME
#endif // TEST_MIME
#ifdef TEST_TIME
- if ( 0 )
+ if ( 1 )
{
TestTimeSet();
TestTimeStatic();
// misc
// ----------------------------------------------------------------------------
-void *wxLongLongNative::asArray(void) const
+void *wxLongLongNative::asArray() const
{
static unsigned char temp[8];
// assignment
wxLongLongWx& wxLongLongWx::Assign(double d)
{
- if ( fabs(d) <= LONG_MAX )
+ bool positive = d >= 0;
+ d = fabs(d);
+ if ( d <= LONG_MAX )
{
- m_hi = d < 0 ? 1 << (8*sizeof(long) - 1) : 0l;
+ m_hi = 0;
m_lo = (long)d;
}
else
{
- wxFAIL_MSG(_T("TODO"));
+#if 0
+ m_lo = (long)d;
+ d -= m_lo;
+ d /= 0x1000;
+ d /= 0x1000;
+ d /= 0x100;
+ m_hi = (long)d;
+#else
+ wxFAIL_MSG(_T("TODO"));
+#endif
}
+ if ( !positive )
+ m_hi = -m_hi;
+
+#ifdef wxLONGLONG_TEST_MODE
+ m_ll = (wxLongLong_t)d;
+
+ Check();
+#endif // wxLONGLONG_TEST_MODE
+
return *this;
}
wxLongLongWx wxLongLongWx::operator<<(int shift) const
{
- if (shift == 0)
- return *this;
+ wxLongLongWx ll(*this);
+ ll <<= shift;
- if (shift < 32)
- return wxLongLongWx((m_hi << shift) | (m_lo >> (32 - shift)),
- m_lo << shift);
- else
- return wxLongLongWx(m_lo << (shift - 32),
- 0);
+ return ll;
}
wxLongLongWx& wxLongLongWx::operator<<=(int shift)
{
- if (shift == 0)
- return *this;
-
- if (shift < 32)
+ if (shift != 0)
{
- m_hi <<= shift;
- m_hi |= m_lo >> (32 - shift);
- m_lo <<= shift;
- }
- else
- {
- m_hi = m_lo << (shift - 32);
- m_lo = 0;
+ if (shift < 32)
+ {
+ m_hi <<= shift;
+ m_hi |= m_lo >> (32 - shift);
+ m_lo <<= shift;
+ }
+ else
+ {
+ m_hi = m_lo << (shift - 32);
+ m_lo = 0;
+ }
}
+#ifdef wxLONGLONG_TEST_MODE
+ m_ll <<= shift;
+
+ Check();
+#endif // wxLONGLONG_TEST_MODE
+
return *this;
}
wxLongLongWx wxLongLongWx::operator>>(int shift) const
{
- if (shift == 0)
- return *this;
+ wxLongLongWx ll(*this);
+ ll >>= shift;
- if (shift < 32)
- return wxLongLongWx(m_hi >> shift,
- (m_lo >> shift) | (m_hi << (32 - shift)));
- else
- return wxLongLongWx((m_hi < 0 ? -1l : 0),
- m_hi >> (shift - 32));
+ return ll;
}
wxLongLongWx& wxLongLongWx::operator>>=(int shift)
{
- if (shift == 0)
- return *this;
-
- if (shift < 32)
- {
- m_lo >>= shift;
- m_lo |= m_hi << (32 - shift);
- m_hi >>= shift;
- }
- else
+ if (shift != 0)
{
- m_lo = m_hi >> (shift - 32);
- m_hi = (m_hi < 0 ? -1L : 0);
+ if (shift < 32)
+ {
+ m_lo >>= shift;
+ m_lo |= m_hi << (32 - shift);
+ m_hi >>= shift;
+ }
+ else
+ {
+ m_lo = m_hi >> (shift - 32);
+ m_hi = (m_hi < 0 ? -1L : 0);
+ }
}
+#ifdef wxLONGLONG_TEST_MODE
+ m_ll >>= shift;
+
+ Check();
+#endif // wxLONGLONG_TEST_MODE
+
return *this;
}
wxLongLongWx wxLongLongWx::operator+(const wxLongLongWx& ll) const
{
- wxLongLongWx temp;
+ wxLongLongWx res(*this);
+ res += ll;
- temp.m_lo = m_lo + ll.m_lo;
- temp.m_hi = m_hi + ll.m_hi;
- if ((temp.m_lo < m_lo) || (temp.m_lo < ll.m_lo))
- temp.m_hi++;
-
- return temp;
+ return res;
}
wxLongLongWx wxLongLongWx::operator+(long l) const
{
- wxLongLongWx temp;
-
- temp.m_lo = m_lo + l;
+ wxLongLongWx res(*this);
+ res += l;
- if (l < 0)
- temp.m_hi += -1l;
-
- if ((temp.m_lo < m_lo) || (temp.m_lo < (unsigned long)l))
- temp.m_hi++;
-
- return temp;
+ return res;
}
wxLongLongWx& wxLongLongWx::operator+=(const wxLongLongWx& ll)
if ((m_lo < previous) || (m_lo < ll.m_lo))
m_hi++;
+#ifdef wxLONGLONG_TEST_MODE
+ m_ll += ll.m_ll;
+
+ Check();
+#endif // wxLONGLONG_TEST_MODE
+
return *this;
}
if ((m_lo < previous) || (m_lo < (unsigned long)l))
m_hi++;
+#ifdef wxLONGLONG_TEST_MODE
+ m_ll += l;
+
+ Check();
+#endif // wxLONGLONG_TEST_MODE
+
return *this;
}
if (m_lo == 0)
m_hi++;
- return *this;
-}
+#ifdef wxLONGLONG_TEST_MODE
+ m_ll++;
-// post increment
-wxLongLongWx& wxLongLongWx::operator++(int)
-{
- m_lo++;
- if (m_lo == 0)
- m_hi++;
+ Check();
+#endif // wxLONGLONG_TEST_MODE
return *this;
}
// negation
wxLongLongWx wxLongLongWx::operator-() const
{
- wxLongLongWx temp(~m_hi, ~m_lo);
+ wxLongLongWx res(*this);
+ res.Negate();
+
+ return res;
+}
+
+wxLongLongWx& wxLongLongWx::Negate()
+{
+ m_hi = ~m_hi;
+ m_lo = ~m_lo;
+
+ m_lo++;
+ if ( m_lo == 0 )
+ m_hi++;
- temp.m_lo++;
- if (temp.m_lo == 0)
- temp.m_hi++;
+#ifdef wxLONGLONG_TEST_MODE
+ m_ll = -m_ll;
- return temp;
+ Check();
+#endif // wxLONGLONG_TEST_MODE
+
+ return *this;
}
// subtraction
wxLongLongWx wxLongLongWx::operator-(const wxLongLongWx& ll) const
{
- wxLongLongWx temp;
-
- temp.m_lo = m_lo - ll.m_lo;
- temp.m_hi = m_hi - ll.m_hi;
+ wxLongLongWx res(*this);
+ res -= ll;
- if (m_lo < ll.m_lo)
- temp.m_hi--;
-
- return temp;
+ return res;
}
wxLongLongWx& wxLongLongWx::operator-=(const wxLongLongWx& ll)
if (previous < ll.m_lo)
m_hi--;
+#ifdef wxLONGLONG_TEST_MODE
+ m_ll -= ll.m_ll;
+
+ Check();
+#endif // wxLONGLONG_TEST_MODE
+
return *this;
}
if (m_lo == 0xFFFFFFFF)
m_hi--;
- return *this;
-}
+#ifdef wxLONGLONG_TEST_MODE
+ m_ll--;
-// post decrement
-wxLongLongWx& wxLongLongWx::operator--(int)
-{
- m_lo--;
- if (m_lo == 0xFFFFFFFF)
- m_hi--;
+ Check();
+#endif // wxLONGLONG_TEST_MODE
return *this;
}
m_lo &= ll.m_lo;
m_hi &= ll.m_hi;
+#ifdef wxLONGLONG_TEST_MODE
+ m_ll &= ll.m_ll;
+
+ Check();
+#endif // wxLONGLONG_TEST_MODE
+
return *this;
}
m_lo |= ll.m_lo;
m_hi |= ll.m_hi;
+#ifdef wxLONGLONG_TEST_MODE
+ m_ll |= ll.m_ll;
+
+ Check();
+#endif // wxLONGLONG_TEST_MODE
+
return *this;
}
m_lo ^= ll.m_lo;
m_hi ^= ll.m_hi;
+#ifdef wxLONGLONG_TEST_MODE
+ m_ll ^= ll.m_ll;
+
+ Check();
+#endif // wxLONGLONG_TEST_MODE
+
return *this;
}
wxLongLongWx wxLongLongWx::operator*(const wxLongLongWx& ll) const
{
- wxLongLongWx t(m_hi, m_lo);
- wxLongLongWx q(ll.m_hi, ll.m_lo);
- wxLongLongWx p;
- int counter = 0;
+ wxLongLongWx res(*this);
+ res *= ll;
- do
- {
- if ((q.m_lo & 1) != 0)
- p += t;
- q >>= 1;
- t <<= 1;
- counter++;
- }
- while ((counter < 64) && ((q.m_hi != 0) || (q.m_lo != 0)));
- return p;
+ return res;
}
wxLongLongWx& wxLongLongWx::operator*=(const wxLongLongWx& ll)
{
wxLongLongWx t(m_hi, m_lo);
wxLongLongWx q(ll.m_hi, ll.m_lo);
- int counter = 0;
+ m_hi = m_lo = 0;
+
+#ifdef wxLONGLONG_TEST_MODE
+ wxLongLong_t llOld = m_ll;
+ m_ll = 0;
+#endif // wxLONGLONG_TEST_MODE
+
+ int counter = 0;
do
{
if ((q.m_lo & 1) != 0)
- *this += t;
+ *this += t;
q >>= 1;
t <<= 1;
counter++;
- }
- while ((counter < 64) && ((q.m_hi != 0) || (q.m_lo != 0)));
+ }
+ while ((counter < 64) && ((q.m_hi != 0) || (q.m_lo != 0)));
+
+#ifdef wxLONGLONG_TEST_MODE
+ m_ll = llOld * ll.m_ll;
+
+ Check();
+#endif // wxLONGLONG_TEST_MODE
+
return *this;
}
quotient = 0l;
remainder = 0l;
- // check for some particular cases
- if ( divisor > dividend )
- {
- remainder = dividend;
-
- return;
- }
-
- if ( divisor == dividend )
- {
- quotient = 1l;
-
- return;
- }
-
// always do unsigned division and adjust the signs later: in C integer
// division, the sign of the remainder is the same as the sign of the
// dividend, while the sign of the quotient is the product of the signs of
divisor = -divisor;
}
- // here: dividend > divisor and both are positibe: do unsigned division
- size_t nBits = 64u;
- wxLongLongWx d;
-
- #define IS_MSB_SET(ll) ((ll.m_hi) & (1 << (8*sizeof(long) - 1)))
-
- while ( remainder < divisor )
+ // check for some particular cases
+ if ( divisor > dividend )
{
- remainder <<= 1;
- if ( IS_MSB_SET(dividend) )
- {
- remainder |= 1;
- }
-
- d = dividend;
- dividend <<= 1;
-
- nBits--;
+ remainder = dividend;
+ }
+ else if ( divisor == dividend )
+ {
+ quotient = 1l;
}
+ else
+ {
+ // here: dividend > divisor and both are positibe: do unsigned division
+ size_t nBits = 64u;
+ wxLongLongWx d;
- // undo the last loop iteration
- dividend = d;
- remainder >>= 1;
- nBits++;
+ #define IS_MSB_SET(ll) ((ll.m_hi) & (1 << (8*sizeof(long) - 1)))
- for ( size_t i = 0; i < nBits; i++ )
- {
- remainder <<= 1;
- if ( IS_MSB_SET(dividend) )
+ while ( remainder < divisor )
{
- remainder |= 1;
+ remainder <<= 1;
+ if ( IS_MSB_SET(dividend) )
+ {
+ remainder |= 1;
+ }
+
+ d = dividend;
+ dividend <<= 1;
+
+ nBits--;
}
- wxLongLongWx t = remainder - divisor;
- dividend <<= 1;
- quotient <<= 1;
- if ( !IS_MSB_SET(t) )
- {
- quotient |= 1;
+ // undo the last loop iteration
+ dividend = d;
+ remainder >>= 1;
+ nBits++;
- remainder = t;
+ for ( size_t i = 0; i < nBits; i++ )
+ {
+ remainder <<= 1;
+ if ( IS_MSB_SET(dividend) )
+ {
+ remainder |= 1;
+ }
+
+ wxLongLongWx t = remainder - divisor;
+ dividend <<= 1;
+ quotient <<= 1;
+ if ( !IS_MSB_SET(t) )
+ {
+ quotient |= 1;
+
+ remainder = t;
+ }
}
}