implemented wxLongLong division - seems to work
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@5101 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
#include <limits.h> // for LONG_MAX
|
#include <limits.h> // for LONG_MAX
|
||||||
|
|
||||||
// #define wxUSE_LONGLONG_WX 1 -- for testing (VZ)
|
//#define wxUSE_LONGLONG_WX 1 // for testing (VZ)
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// decide upon which class we will use
|
// decide upon which class we will use
|
||||||
@@ -59,7 +59,7 @@
|
|||||||
// have any 64 bit integer type
|
// have any 64 bit integer type
|
||||||
#if !defined(__VISAGECPP__) && \
|
#if !defined(__VISAGECPP__) && \
|
||||||
!defined(__VISUALC__) && \
|
!defined(__VISUALC__) && \
|
||||||
!defined(__BORLANDC__
|
!defined(__BORLANDC__)
|
||||||
#warning "Your compiler does not appear to support 64 bit integers, "\
|
#warning "Your compiler does not appear to support 64 bit integers, "\
|
||||||
"using emulation class instead."
|
"using emulation class instead."
|
||||||
#endif // known compilers without long long
|
#endif // known compilers without long long
|
||||||
|
@@ -32,11 +32,11 @@
|
|||||||
//#define TEST_ARRAYS
|
//#define TEST_ARRAYS
|
||||||
//#define TEST_DIR
|
//#define TEST_DIR
|
||||||
//#define TEST_LOG
|
//#define TEST_LOG
|
||||||
#define TEST_LONGLONG
|
//#define TEST_LONGLONG
|
||||||
//#define TEST_MIME
|
//#define TEST_MIME
|
||||||
//#define TEST_STRINGS
|
//#define TEST_STRINGS
|
||||||
//#define TEST_THREADS
|
//#define TEST_THREADS
|
||||||
//#define TEST_TIME
|
#define TEST_TIME
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// implementation
|
// implementation
|
||||||
@@ -224,14 +224,16 @@ static void TestSpeed()
|
|||||||
|
|
||||||
static void TestDivision()
|
static void TestDivision()
|
||||||
{
|
{
|
||||||
|
puts("*** Testing wxLongLong division ***\n");
|
||||||
|
|
||||||
#define MAKE_LL(x1, x2, x3, x4) wxLongLong((x1 << 16) | x2, (x3 << 16) | x3)
|
#define MAKE_LL(x1, x2, x3, x4) wxLongLong((x1 << 16) | x2, (x3 << 16) | x3)
|
||||||
|
|
||||||
// seed pseudo random generator
|
// seed pseudo random generator
|
||||||
//srand((unsigned)time(NULL));
|
srand((unsigned)time(NULL));
|
||||||
|
|
||||||
wxLongLong q, r;
|
wxLongLong q, r;
|
||||||
size_t nTested = 0;
|
size_t nTested = 0;
|
||||||
for ( size_t n = 0; n < 10000; n++ )
|
for ( size_t n = 0; n < 100000; n++ )
|
||||||
{
|
{
|
||||||
// get a random wxLongLong (shifting by 12 the MSB ensures that the
|
// get a random wxLongLong (shifting by 12 the MSB ensures that the
|
||||||
// multiplication will not overflow)
|
// multiplication will not overflow)
|
||||||
@@ -242,12 +244,19 @@ static void TestDivision()
|
|||||||
q = ll / l;
|
q = ll / l;
|
||||||
r = ll % l;
|
r = ll % l;
|
||||||
|
|
||||||
|
// verify the result
|
||||||
wxASSERT_MSG( ll == q*l + r, "division failure" );
|
wxASSERT_MSG( ll == q*l + r, "division failure" );
|
||||||
|
|
||||||
|
if ( !(nTested % 1000) )
|
||||||
|
{
|
||||||
|
putchar('.');
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
|
||||||
nTested++;
|
nTested++;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("\n*** Tested %u divisions/multiplications: ok\n", nTested);
|
puts(" done!");
|
||||||
|
|
||||||
#undef MAKE_LL
|
#undef MAKE_LL
|
||||||
}
|
}
|
||||||
|
@@ -391,54 +391,128 @@ wxLongLongWx& wxLongLongWx::operator*=(const wxLongLongWx& ll)
|
|||||||
|
|
||||||
// division
|
// division
|
||||||
|
|
||||||
void wxLongLongWx::Divide(const wxLongLongWx& divisor,
|
void wxLongLongWx::Divide(const wxLongLongWx& divisorIn,
|
||||||
wxLongLongWx& quotient,
|
wxLongLongWx& quotient,
|
||||||
wxLongLongWx& remainder) const
|
wxLongLongWx& remainder) const
|
||||||
{
|
{
|
||||||
if ((divisor.m_lo == 0) && (divisor.m_hi == 0))
|
if ((divisorIn.m_lo == 0) && (divisorIn.m_hi == 0))
|
||||||
{
|
{
|
||||||
// provoke division by zero error and silence the compilers warnings
|
// provoke division by zero error and silence the compilers warnings
|
||||||
// about an expression without effect and unused variable
|
// about an expression without effect and unused variable
|
||||||
long dummy = divisor.m_lo/divisor.m_hi;
|
long dummy = divisorIn.m_lo/divisorIn.m_hi;
|
||||||
dummy += 0;
|
dummy += 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// VZ: I'm writing this in a hurry and it's surely not the fastest way to
|
// VZ: I'm writing this in a hurry and it's surely not the fastest way to
|
||||||
// do this - any improvements are more than welcome
|
// do this - any improvements are more than welcome
|
||||||
|
//
|
||||||
|
// code inspired by the snippet at
|
||||||
|
// http://www.bearcave.com/software/divide.htm
|
||||||
|
//
|
||||||
|
// Copyright notice:
|
||||||
|
//
|
||||||
|
// Use of this program, for any purpose, is granted the author, Ian
|
||||||
|
// Kaplan, as long as this copyright notice is included in the source
|
||||||
|
// code or any source code derived from this program. The user assumes
|
||||||
|
// all responsibility for using this code.
|
||||||
|
|
||||||
// the algorithm: first find N such that 2^N * divisor is less than us,
|
// init everything
|
||||||
// then substract divisor from *this - 2^N * divisor as many times as
|
wxLongLongWx dividend = *this,
|
||||||
// possible
|
divisor = divisorIn;
|
||||||
|
|
||||||
wxLongLongWx prev = divisor;
|
quotient = 0l;
|
||||||
remainder = *this;
|
remainder = 0l;
|
||||||
|
|
||||||
quotient = 1l;
|
// check for some particular cases
|
||||||
|
if ( divisor > dividend )
|
||||||
for ( wxLongLongWx tmp = divisor; tmp < remainder; )
|
|
||||||
{
|
{
|
||||||
prev = tmp;
|
remainder = dividend;
|
||||||
|
|
||||||
tmp <<= 1;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if ( tmp < 0 )
|
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
|
||||||
|
// the dividend and divisor. Of course, we also always have
|
||||||
|
//
|
||||||
|
// dividend = quotient*divisor + remainder
|
||||||
|
//
|
||||||
|
// with 0 <= abs(remainder) < abs(divisor)
|
||||||
|
bool negRemainder = dividend.m_hi < 0;
|
||||||
|
bool negQuotient = FALSE; // assume positive
|
||||||
|
if ( dividend.m_hi < 0 )
|
||||||
|
{
|
||||||
|
negQuotient = !negQuotient;
|
||||||
|
dividend = -dividend;
|
||||||
|
}
|
||||||
|
if ( divisor.m_hi < 0 )
|
||||||
|
{
|
||||||
|
negQuotient = !negQuotient;
|
||||||
|
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 )
|
||||||
|
{
|
||||||
|
remainder <<= 1;
|
||||||
|
if ( IS_MSB_SET(dividend) )
|
||||||
{
|
{
|
||||||
// shifted too far
|
remainder |= 1;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
quotient <<= 1;
|
d = dividend;
|
||||||
|
dividend <<= 1;
|
||||||
|
|
||||||
|
nBits--;
|
||||||
}
|
}
|
||||||
|
|
||||||
while ( remainder >= prev )
|
// undo the last loop iteration
|
||||||
|
dividend = d;
|
||||||
|
remainder >>= 1;
|
||||||
|
nBits++;
|
||||||
|
|
||||||
|
for ( size_t i = 0; i < nBits; i++ )
|
||||||
{
|
{
|
||||||
remainder -= divisor;
|
remainder <<= 1;
|
||||||
quotient++;
|
if ( IS_MSB_SET(dividend) )
|
||||||
|
{
|
||||||
|
remainder |= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
wxLongLongWx t = remainder - divisor;
|
||||||
|
dividend <<= 1;
|
||||||
|
quotient <<= 1;
|
||||||
|
if ( !IS_MSB_SET(t) )
|
||||||
|
{
|
||||||
|
quotient |= 1;
|
||||||
|
|
||||||
|
remainder = t;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// remainder should be in this range at the end
|
// adjust signs
|
||||||
wxASSERT_MSG( (0l <= remainder) && (remainder < divisor.Abs()),
|
if ( negRemainder )
|
||||||
_T("logic error in wxLongLong division") );
|
{
|
||||||
|
remainder = -remainder;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( negQuotient )
|
||||||
|
{
|
||||||
|
quotient = -quotient;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wxLongLongWx wxLongLongWx::operator/(const wxLongLongWx& ll) const
|
wxLongLongWx wxLongLongWx::operator/(const wxLongLongWx& ll) const
|
||||||
|
Reference in New Issue
Block a user