X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/2ea24d9f47002ce2965b6c782849f2f9b776c3de..0834112f89c4c5da7864e17e6f483ce296798ce6:/src/common/longlong.cpp diff --git a/src/common/longlong.cpp b/src/common/longlong.cpp index bca0d2d1fe..2dd291fb1c 100644 --- a/src/common/longlong.cpp +++ b/src/common/longlong.cpp @@ -26,10 +26,10 @@ #endif #if wxUSE_LONGLONG - #include "wx/longlong.h" #include // for memset() +#include // for fabs() // ============================================================================ // implementation @@ -80,8 +80,28 @@ ostream& operator<< (ostream& o, const wxLongLongNative& ll) #endif // wxUSE_LONGLONG_NATIVE +// ============================================================================ +// wxLongLongWx: emulation of 'long long' using 2 longs +// ============================================================================ + #if wxUSE_LONGLONG_WX +// assignment +wxLongLongWx& wxLongLongWx::Assign(double d) +{ + if ( fabs(d) <= LONG_MAX ) + { + m_hi = d < 0 ? 1 << (8*sizeof(long) - 1) : 0l; + m_lo = (long)d; + } + else + { + wxFAIL_MSG(_T("TODO")); + } + + return *this; +} + wxLongLongWx wxLongLongWx::operator<<(int shift) const { if (shift == 0) @@ -259,7 +279,7 @@ wxLongLongWx& wxLongLongWx::operator-=(const wxLongLongWx& ll) if (previous < ll.m_lo) m_hi--; - return *this;; + return *this; } // pre decrement @@ -391,54 +411,128 @@ wxLongLongWx& wxLongLongWx::operator*=(const wxLongLongWx& ll) // division -void wxLongLongWx::Divide(const wxLongLongWx& divisor, +void wxLongLongWx::Divide(const wxLongLongWx& divisorIn, wxLongLongWx& quotient, 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 // 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; } // 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 + // + // 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. + + // init everything + wxLongLongWx dividend = *this, + divisor = divisorIn; + + quotient = 0l; + remainder = 0l; + + // check for some particular cases + if ( divisor > dividend ) + { + remainder = dividend; - // the algorithm: first find N such that 2^N * divisor is less than us, - // then substract divisor from *this - 2^N * divisor as many times as - // possible + return; + } - wxLongLongWx prev = divisor; - remainder = *this; + if ( divisor == dividend ) + { + quotient = 1l; - quotient = 1l; + return; + } - for ( wxLongLongWx tmp = divisor; tmp < remainder; ) + // 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 ) { - prev = tmp; + 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) ) + { + remainder |= 1; + } - tmp <<= 1; + d = dividend; + dividend <<= 1; - if ( tmp < 0 ) + nBits--; + } + + // undo the last loop iteration + dividend = d; + remainder >>= 1; + nBits++; + + for ( size_t i = 0; i < nBits; i++ ) + { + remainder <<= 1; + if ( IS_MSB_SET(dividend) ) { - // shifted too far - break; + remainder |= 1; } + wxLongLongWx t = remainder - divisor; + dividend <<= 1; quotient <<= 1; + if ( !IS_MSB_SET(t) ) + { + quotient |= 1; + + remainder = t; + } } - while ( remainder >= prev ) + // adjust signs + if ( negRemainder ) { - remainder -= divisor; - quotient++; + remainder = -remainder; } - // remainder should be in this range at the end - wxASSERT_MSG( (0l <= remainder) && (remainder < divisor.Abs()), - _T("logic error in wxLongLong division") ); + if ( negQuotient ) + { + quotient = -quotient; + } } wxLongLongWx wxLongLongWx::operator/(const wxLongLongWx& ll) const @@ -477,14 +571,14 @@ void *wxLongLongWx::asArray(void) const { static unsigned char temp[8]; - temp[0] = (m_hi >> 24) & 0xFF; - temp[1] = (m_hi >> 16) & 0xFF; - temp[2] = (m_hi >> 8) & 0xFF; - temp[3] = (m_hi >> 0) & 0xFF; - temp[4] = (m_lo >> 24) & 0xFF; - temp[5] = (m_lo >> 16) & 0xFF; - temp[6] = (m_lo >> 8) & 0xFF; - temp[7] = (m_lo >> 0) & 0xFF; + temp[0] = (char)((m_hi >> 24) & 0xFF); + temp[1] = (char)((m_hi >> 16) & 0xFF); + temp[2] = (char)((m_hi >> 8) & 0xFF); + temp[3] = (char)((m_hi >> 0) & 0xFF); + temp[4] = (char)((m_lo >> 24) & 0xFF); + temp[5] = (char)((m_lo >> 16) & 0xFF); + temp[6] = (char)((m_lo >> 8) & 0xFF); + temp[7] = (char)((m_lo >> 0) & 0xFF); return temp; }