Files
wxWidgets/src/common/longlong.cpp
Vadim Zeitlin 4c24ca50d6 Fix wxULongLongNative::ToDouble() compilation with VC6.
The problem alluded to by the commit message of r40658 arose only in the DLL
build using VC6 so reintroduce the workaround for it removed by r67634 but
make it VC6-specific and, arguably even more importantly, also make it work
correctly for wxULongLongNative values greater than LONGLONG_MAX.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@67643 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
2011-04-28 16:16:16 +00:00

1380 lines
31 KiB
C++

/////////////////////////////////////////////////////////////////////////////
// Name: src/common/longlong.cpp
// Purpose: implementation of wxLongLongNative
// Author: Jeffrey C. Ollie <jeff@ollie.clive.ia.us>, Vadim Zeitlin
// Remarks: this class is not public in wxWidgets 2.0! It is intentionally
// not documented and is for private use only.
// Modified by:
// Created: 10.02.99
// RCS-ID: $Id$
// Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// ============================================================================
// headers
// ============================================================================
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#if wxUSE_LONGLONG
#include "wx/longlong.h"
#ifndef WX_PRECOMP
#include "wx/math.h" // for fabs()
#endif
#if wxUSE_STREAMS
#include "wx/txtstrm.h"
#endif
#include <string.h> // for memset()
#include "wx/ioswrap.h"
// ============================================================================
// implementation
// ============================================================================
#if wxUSE_LONGLONG_NATIVE
// ----------------------------------------------------------------------------
// misc
// ----------------------------------------------------------------------------
void *wxLongLongNative::asArray() const
{
static unsigned char temp[8];
temp[0] = wx_truncate_cast(unsigned char, ((m_ll >> 56) & 0xFF));
temp[1] = wx_truncate_cast(unsigned char, ((m_ll >> 48) & 0xFF));
temp[2] = wx_truncate_cast(unsigned char, ((m_ll >> 40) & 0xFF));
temp[3] = wx_truncate_cast(unsigned char, ((m_ll >> 32) & 0xFF));
temp[4] = wx_truncate_cast(unsigned char, ((m_ll >> 24) & 0xFF));
temp[5] = wx_truncate_cast(unsigned char, ((m_ll >> 16) & 0xFF));
temp[6] = wx_truncate_cast(unsigned char, ((m_ll >> 8) & 0xFF));
temp[7] = wx_truncate_cast(unsigned char, ((m_ll >> 0) & 0xFF));
return temp;
}
void *wxULongLongNative::asArray() const
{
static unsigned char temp[8];
temp[0] = wx_truncate_cast(unsigned char, ((m_ll >> 56) & 0xFF));
temp[1] = wx_truncate_cast(unsigned char, ((m_ll >> 48) & 0xFF));
temp[2] = wx_truncate_cast(unsigned char, ((m_ll >> 40) & 0xFF));
temp[3] = wx_truncate_cast(unsigned char, ((m_ll >> 32) & 0xFF));
temp[4] = wx_truncate_cast(unsigned char, ((m_ll >> 24) & 0xFF));
temp[5] = wx_truncate_cast(unsigned char, ((m_ll >> 16) & 0xFF));
temp[6] = wx_truncate_cast(unsigned char, ((m_ll >> 8) & 0xFF));
temp[7] = wx_truncate_cast(unsigned char, ((m_ll >> 0) & 0xFF));
return temp;
}
#if wxUSE_LONGLONG_WX
wxLongLongNative::wxLongLongNative(wxLongLongWx ll)
{
// assign first to avoid precision loss!
m_ll = ll.GetHi();
m_ll <<= 32;
m_ll |= ll.GetLo();
}
wxLongLongNative& wxLongLongNative::operator=(wxLongLongWx ll)
{
// assign first to avoid precision loss!
m_ll = ll.GetHi();
m_ll <<= 32;
m_ll |= ll.GetLo();
return *this;
}
wxLongLongNative& wxLongLongNative::operator=(const class wxULongLongWx &ll)
{
// assign first to avoid precision loss!
m_ll = ll.GetHi();
m_ll <<= 32;
m_ll |= ll.GetLo();
return *this;
}
wxULongLongNative::wxULongLongNative(const class wxULongLongWx &ll)
{
// assign first to avoid precision loss!
m_ll = ll.GetHi();
m_ll <<= 32;
m_ll |= ((unsigned long) ll.GetLo());
}
wxULongLongNative& wxULongLongNative::operator=(wxLongLongWx ll)
{
// assign first to avoid precision loss!
m_ll = ll.GetHi();
m_ll <<= 32;
m_ll |= ((unsigned long) ll.GetLo());
return *this;
}
wxULongLongNative& wxULongLongNative::operator=(const class wxULongLongWx &ll)
{
// assign first to avoid precision loss!
m_ll = ll.GetHi();
m_ll <<= 32;
m_ll |= ((unsigned long) ll.GetLo());
return *this;
}
#endif
#ifdef __VISUALC6__
double wxULongLongNative::ToDouble() const
{
// Work around the problem of casting unsigned __int64 to double in VC6
// (which for unknown reasons only manifests itself in DLL builds, i.e.
// when using /MD).
static const __int64 int64_t_max = 9223372036854775807i64;
if ( m_ll <= int64_t_max )
return wx_truncate_cast(double, (wxLongLong_t)m_ll);
double d = wx_truncate_cast(double, int64_t_max);
d += (__int64)(m_ll - int64_t_max - 1); // The cast is safe because of -1
return d + 1;
}
#endif // __VISUALC6__
#endif // wxUSE_LONGLONG_NATIVE
// ============================================================================
// wxLongLongWx: emulation of 'long long' using 2 longs
// ============================================================================
#if wxUSE_LONGLONG_WX
// Set value from unsigned wxULongLongWx
wxLongLongWx &wxLongLongWx::operator=(const class wxULongLongWx &ll)
{
m_hi = (unsigned long) ll.GetHi();
m_lo = ll.GetLo();
return *this;
}
// assignment
wxLongLongWx& wxLongLongWx::Assign(double d)
{
bool positive = d >= 0;
d = fabs(d);
if ( d <= ULONG_MAX )
{
m_hi = 0;
m_lo = (long)d;
}
else
{
m_hi = (unsigned long)(d / (1.0 + (double)ULONG_MAX));
m_lo = (unsigned long)(d - ((double)m_hi * (1.0 + (double)ULONG_MAX)));
}
#ifdef wxLONGLONG_TEST_MODE
m_ll = (wxLongLong_t)d;
Check();
#endif // wxLONGLONG_TEST_MODE
if ( !positive )
Negate();
return *this;
}
double wxLongLongWx::ToDouble() const
{
double d = m_hi;
d *= 1.0 + (double)ULONG_MAX;
d += m_lo;
#ifdef wxLONGLONG_TEST_MODE
wxASSERT( d == m_ll );
#endif // wxLONGLONG_TEST_MODE
return d;
}
double wxULongLongWx::ToDouble() const
{
unsigned double d = m_hi;
d *= 1.0 + (double)ULONG_MAX;
d += m_lo;
#ifdef wxLONGLONG_TEST_MODE
wxASSERT( d == m_ll );
#endif // wxLONGLONG_TEST_MODE
return d;
}
wxLongLongWx wxLongLongWx::operator<<(int shift) const
{
wxLongLongWx ll(*this);
ll <<= shift;
return ll;
}
wxULongLongWx wxULongLongWx::operator<<(int shift) const
{
wxULongLongWx ll(*this);
ll <<= shift;
return ll;
}
wxLongLongWx& wxLongLongWx::operator<<=(int shift)
{
if (shift != 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;
}
wxULongLongWx& wxULongLongWx::operator<<=(int shift)
{
if (shift != 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
{
wxLongLongWx ll(*this);
ll >>= shift;
return ll;
}
wxULongLongWx wxULongLongWx::operator>>(int shift) const
{
wxULongLongWx ll(*this);
ll >>= shift;
return ll;
}
wxLongLongWx& wxLongLongWx::operator>>=(int shift)
{
if (shift != 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;
}
wxULongLongWx& wxULongLongWx::operator>>=(int shift)
{
if (shift != 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 = 0;
}
}
#ifdef wxLONGLONG_TEST_MODE
m_ll >>= shift;
Check();
#endif // wxLONGLONG_TEST_MODE
return *this;
}
wxLongLongWx wxLongLongWx::operator+(const wxLongLongWx& ll) const
{
wxLongLongWx res(*this);
res += ll;
return res;
}
wxULongLongWx wxULongLongWx::operator+(const wxULongLongWx& ll) const
{
wxULongLongWx res(*this);
res += ll;
return res;
}
wxLongLongWx wxLongLongWx::operator+(long l) const
{
wxLongLongWx res(*this);
res += l;
return res;
}
wxULongLongWx wxULongLongWx::operator+(unsigned long l) const
{
wxULongLongWx res(*this);
res += l;
return res;
}
wxLongLongWx& wxLongLongWx::operator+=(const wxLongLongWx& ll)
{
unsigned long previous = m_lo;
m_lo += ll.m_lo;
m_hi += ll.m_hi;
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;
}
wxULongLongWx& wxULongLongWx::operator+=(const wxULongLongWx& ll)
{
unsigned long previous = m_lo;
m_lo += ll.m_lo;
m_hi += ll.m_hi;
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;
}
wxLongLongWx& wxLongLongWx::operator+=(long l)
{
unsigned long previous = m_lo;
m_lo += l;
if (l < 0)
m_hi += -1l;
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;
}
wxULongLongWx& wxULongLongWx::operator+=(unsigned long l)
{
unsigned long previous = m_lo;
m_lo += l;
if ((m_lo < previous) || (m_lo < l))
m_hi++;
#ifdef wxLONGLONG_TEST_MODE
m_ll += l;
Check();
#endif // wxLONGLONG_TEST_MODE
return *this;
}
// pre increment
wxLongLongWx& wxLongLongWx::operator++()
{
m_lo++;
if (m_lo == 0)
m_hi++;
#ifdef wxLONGLONG_TEST_MODE
m_ll++;
Check();
#endif // wxLONGLONG_TEST_MODE
return *this;
}
wxULongLongWx& wxULongLongWx::operator++()
{
m_lo++;
if (m_lo == 0)
m_hi++;
#ifdef wxLONGLONG_TEST_MODE
m_ll++;
Check();
#endif // wxLONGLONG_TEST_MODE
return *this;
}
// negation
wxLongLongWx wxLongLongWx::operator-() const
{
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++;
#ifdef wxLONGLONG_TEST_MODE
m_ll = -m_ll;
Check();
#endif // wxLONGLONG_TEST_MODE
return *this;
}
// subtraction
wxLongLongWx wxLongLongWx::operator-(const wxLongLongWx& ll) const
{
wxLongLongWx res(*this);
res -= ll;
return res;
}
wxLongLongWx wxULongLongWx::operator-(const wxULongLongWx& ll) const
{
wxASSERT(m_hi <= LONG_MAX );
wxASSERT(ll.m_hi <= LONG_MAX );
wxLongLongWx res( (long)m_hi , m_lo );
wxLongLongWx op( (long)ll.m_hi , ll.m_lo );
res -= op;
return res;
}
wxLongLongWx& wxLongLongWx::operator-=(const wxLongLongWx& ll)
{
unsigned long previous = m_lo;
m_lo -= ll.m_lo;
m_hi -= ll.m_hi;
if (previous < ll.m_lo)
m_hi--;
#ifdef wxLONGLONG_TEST_MODE
m_ll -= ll.m_ll;
Check();
#endif // wxLONGLONG_TEST_MODE
return *this;
}
wxULongLongWx& wxULongLongWx::operator-=(const wxULongLongWx& ll)
{
unsigned long previous = m_lo;
m_lo -= ll.m_lo;
m_hi -= ll.m_hi;
if (previous < ll.m_lo)
m_hi--;
#ifdef wxLONGLONG_TEST_MODE
m_ll -= ll.m_ll;
Check();
#endif // wxLONGLONG_TEST_MODE
return *this;
}
// pre decrement
wxLongLongWx& wxLongLongWx::operator--()
{
m_lo--;
if (m_lo == 0xFFFFFFFF)
m_hi--;
#ifdef wxLONGLONG_TEST_MODE
m_ll--;
Check();
#endif // wxLONGLONG_TEST_MODE
return *this;
}
wxULongLongWx& wxULongLongWx::operator--()
{
m_lo--;
if (m_lo == 0xFFFFFFFF)
m_hi--;
#ifdef wxLONGLONG_TEST_MODE
m_ll--;
Check();
#endif // wxLONGLONG_TEST_MODE
return *this;
}
// comparison operators
bool wxLongLongWx::operator<(const wxLongLongWx& ll) const
{
if ( m_hi < ll.m_hi )
return true;
else if ( m_hi == ll.m_hi )
return m_lo < ll.m_lo;
else
return false;
}
bool wxULongLongWx::operator<(const wxULongLongWx& ll) const
{
if ( m_hi < ll.m_hi )
return true;
else if ( m_hi == ll.m_hi )
return m_lo < ll.m_lo;
else
return false;
}
bool wxLongLongWx::operator>(const wxLongLongWx& ll) const
{
if ( m_hi > ll.m_hi )
return true;
else if ( m_hi == ll.m_hi )
return m_lo > ll.m_lo;
else
return false;
}
bool wxULongLongWx::operator>(const wxULongLongWx& ll) const
{
if ( m_hi > ll.m_hi )
return true;
else if ( m_hi == ll.m_hi )
return m_lo > ll.m_lo;
else
return false;
}
// bitwise operators
wxLongLongWx wxLongLongWx::operator&(const wxLongLongWx& ll) const
{
return wxLongLongWx(m_hi & ll.m_hi, m_lo & ll.m_lo);
}
wxULongLongWx wxULongLongWx::operator&(const wxULongLongWx& ll) const
{
return wxULongLongWx(m_hi & ll.m_hi, m_lo & ll.m_lo);
}
wxLongLongWx wxLongLongWx::operator|(const wxLongLongWx& ll) const
{
return wxLongLongWx(m_hi | ll.m_hi, m_lo | ll.m_lo);
}
wxULongLongWx wxULongLongWx::operator|(const wxULongLongWx& ll) const
{
return wxULongLongWx(m_hi | ll.m_hi, m_lo | ll.m_lo);
}
wxLongLongWx wxLongLongWx::operator^(const wxLongLongWx& ll) const
{
return wxLongLongWx(m_hi ^ ll.m_hi, m_lo ^ ll.m_lo);
}
wxULongLongWx wxULongLongWx::operator^(const wxULongLongWx& ll) const
{
return wxULongLongWx(m_hi ^ ll.m_hi, m_lo ^ ll.m_lo);
}
wxLongLongWx& wxLongLongWx::operator&=(const wxLongLongWx& ll)
{
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;
}
wxULongLongWx& wxULongLongWx::operator&=(const wxULongLongWx& ll)
{
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)
{
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;
}
wxULongLongWx& wxULongLongWx::operator|=(const wxULongLongWx& ll)
{
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)
{
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;
}
wxULongLongWx& wxULongLongWx::operator^=(const wxULongLongWx& ll)
{
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
{
return wxLongLongWx(~m_hi, ~m_lo);
}
wxULongLongWx wxULongLongWx::operator~() const
{
return wxULongLongWx(~m_hi, ~m_lo);
}
// multiplication
wxLongLongWx wxLongLongWx::operator*(const wxLongLongWx& ll) const
{
wxLongLongWx res(*this);
res *= ll;
return res;
}
wxULongLongWx wxULongLongWx::operator*(const wxULongLongWx& ll) const
{
wxULongLongWx res(*this);
res *= ll;
return res;
}
wxLongLongWx& wxLongLongWx::operator*=(const wxLongLongWx& ll)
{
wxLongLongWx t(m_hi, m_lo);
wxLongLongWx q(ll.m_hi, ll.m_lo);
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;
q >>= 1;
t <<= 1;
counter++;
}
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;
}
wxULongLongWx& wxULongLongWx::operator*=(const wxULongLongWx& ll)
{
wxULongLongWx t(m_hi, m_lo);
wxULongLongWx q(ll.m_hi, ll.m_lo);
m_hi = m_lo = 0;
#ifdef wxLONGLONG_TEST_MODE
wxULongLong_t llOld = m_ll;
m_ll = 0;
#endif // wxLONGLONG_TEST_MODE
int counter = 0;
do
{
if ((q.m_lo & 1) != 0)
*this += t;
q >>= 1;
t <<= 1;
counter++;
}
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;
}
// division
#define IS_MSB_SET(ll) ((ll.GetHi()) & (1 << (8*sizeof(long) - 1)))
void wxLongLongWx::Divide(const wxLongLongWx& divisorIn,
wxLongLongWx& quotient,
wxLongLongWx& remainderIO) const
{
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 = 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
wxULongLongWx dividend, divisor, remainder;
quotient = 0l;
remainder = 0l;
// 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 = GetHi() < 0;
bool negQuotient = false; // assume positive
if ( GetHi() < 0 )
{
negQuotient = !negQuotient;
dividend = -*this;
} else {
dividend = *this;
}
if ( divisorIn.GetHi() < 0 )
{
negQuotient = !negQuotient;
divisor = -divisorIn;
} else {
divisor = divisorIn;
}
// check for some particular cases
if ( divisor > dividend )
{
remainder = dividend;
}
else if ( divisor == dividend )
{
quotient = 1l;
}
else
{
// here: dividend > divisor and both are positive: do unsigned division
size_t nBits = 64u;
wxLongLongWx d;
while ( remainder < divisor )
{
remainder <<= 1;
if ( IS_MSB_SET(dividend) )
{
remainder |= 1;
}
d = dividend;
dividend <<= 1;
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) )
{
remainder |= 1;
}
wxLongLongWx t = remainder - divisor;
dividend <<= 1;
quotient <<= 1;
if ( !IS_MSB_SET(t) )
{
quotient |= 1;
remainder = t;
}
}
}
remainderIO = remainder;
// adjust signs
if ( negRemainder )
{
remainderIO = -remainderIO;
}
if ( negQuotient )
{
quotient = -quotient;
}
}
void wxULongLongWx::Divide(const wxULongLongWx& divisorIn,
wxULongLongWx& quotient,
wxULongLongWx& remainder) const
{
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
unsigned 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
wxULongLongWx dividend = *this,
divisor = divisorIn;
quotient = 0l;
remainder = 0l;
// check for some particular cases
if ( divisor > dividend )
{
remainder = dividend;
}
else if ( divisor == dividend )
{
quotient = 1l;
}
else
{
// here: dividend > divisor
size_t nBits = 64u;
wxULongLongWx d;
while ( remainder < divisor )
{
remainder <<= 1;
if ( IS_MSB_SET(dividend) )
{
remainder |= 1;
}
d = dividend;
dividend <<= 1;
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) )
{
remainder |= 1;
}
wxULongLongWx t = remainder - divisor;
dividend <<= 1;
quotient <<= 1;
if ( !IS_MSB_SET(t) )
{
quotient |= 1;
remainder = t;
}
}
}
}
wxLongLongWx wxLongLongWx::operator/(const wxLongLongWx& ll) const
{
wxLongLongWx quotient, remainder;
Divide(ll, quotient, remainder);
return quotient;
}
wxULongLongWx wxULongLongWx::operator/(const wxULongLongWx& ll) const
{
wxULongLongWx quotient, remainder;
Divide(ll, quotient, remainder);
return quotient;
}
wxLongLongWx& wxLongLongWx::operator/=(const wxLongLongWx& ll)
{
wxLongLongWx quotient, remainder;
Divide(ll, quotient, remainder);
*this = quotient;
return *this;
}
wxULongLongWx& wxULongLongWx::operator/=(const wxULongLongWx& ll)
{
wxULongLongWx quotient, remainder;
Divide(ll, quotient, remainder);
*this = quotient;
return *this;
}
wxLongLongWx wxLongLongWx::operator%(const wxLongLongWx& ll) const
{
wxLongLongWx quotient, remainder;
Divide(ll, quotient, remainder);
return remainder;
}
wxULongLongWx wxULongLongWx::operator%(const wxULongLongWx& ll) const
{
wxULongLongWx quotient, remainder;
Divide(ll, quotient, remainder);
return remainder;
}
// ----------------------------------------------------------------------------
// misc
// ----------------------------------------------------------------------------
// temporary - just for testing
void *wxLongLongWx::asArray(void) const
{
static unsigned char temp[8];
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;
}
void *wxULongLongWx::asArray(void) const
{
static unsigned char temp[8];
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;
}
#endif // wxUSE_LONGLONG_WX
#define LL_TO_STRING(name) \
wxString name::ToString() const \
{ \
/* TODO: this is awfully inefficient, anything better? */ \
wxString result; \
\
name ll = *this; \
\
bool neg = ll < 0; \
if ( neg ) \
{ \
while ( ll != 0 ) \
{ \
long digit = (ll % 10).ToLong(); \
result.Prepend((wxChar)(wxT('0') - digit)); \
ll /= 10; \
} \
} \
else \
{ \
while ( ll != 0 ) \
{ \
long digit = (ll % 10).ToLong(); \
result.Prepend((wxChar)(wxT('0') + digit)); \
ll /= 10; \
} \
} \
\
if ( result.empty() ) \
result = wxT('0'); \
else if ( neg ) \
result.Prepend(wxT('-')); \
\
return result; \
}
#define ULL_TO_STRING(name) \
wxString name::ToString() const \
{ \
/* TODO: this is awfully inefficient, anything better? */ \
wxString result; \
\
name ll = *this; \
\
while ( ll != 0 ) \
{ \
result.Prepend((wxChar)(wxT('0') + (ll % 10).ToULong())); \
ll /= 10; \
} \
\
if ( result.empty() ) \
result = wxT('0'); \
\
return result; \
}
#if wxUSE_LONGLONG_NATIVE
LL_TO_STRING(wxLongLongNative)
ULL_TO_STRING(wxULongLongNative)
#endif
#if wxUSE_LONGLONG_WX
LL_TO_STRING(wxLongLongWx)
ULL_TO_STRING(wxULongLongWx)
#endif
#if wxUSE_STD_IOSTREAM
// input/output
WXDLLIMPEXP_BASE
wxSTD ostream& operator<< (wxSTD ostream& o, const wxLongLong& ll)
{
return o << ll.ToString();
}
WXDLLIMPEXP_BASE
wxSTD ostream& operator<< (wxSTD ostream& o, const wxULongLong& ll)
{
return o << ll.ToString();
}
#endif // wxUSE_STD_IOSTREAM
WXDLLIMPEXP_BASE wxString& operator<< (wxString& s, const wxLongLong& ll)
{
return s << ll.ToString();
}
WXDLLIMPEXP_BASE wxString& operator<< (wxString& s, const wxULongLong& ll)
{
return s << ll.ToString();
}
#if wxUSE_STREAMS
WXDLLIMPEXP_BASE wxTextOutputStream& operator<< (wxTextOutputStream& o, const wxULongLong& ll)
{
return o << ll.ToString();
}
WXDLLIMPEXP_BASE wxTextOutputStream& operator<< (wxTextOutputStream& o, const wxLongLong& ll)
{
return o << ll.ToString();
}
#define READ_STRING_CHAR(s, idx, len) ((idx!=len) ? (wxChar)s[idx++] : wxT('\0'))
WXDLLIMPEXP_BASE class wxTextInputStream &operator>>(class wxTextInputStream &o, wxULongLong &ll)
{
wxString s = o.ReadWord();
ll = wxULongLong(0l, 0l);
size_t length = s.length();
size_t idx = 0;
wxChar ch = READ_STRING_CHAR(s, idx, length);
// Skip WS
while (ch==wxT(' ') || ch==wxT('\t'))
ch = READ_STRING_CHAR(s, idx, length);
// Read number
wxULongLong multiplier(0l, 10l);
while (ch>=wxT('0') && ch<=wxT('9')) {
long lValue = (unsigned) (ch - wxT('0'));
ll = ll * multiplier + wxULongLong(0l, lValue);
ch = READ_STRING_CHAR(s, idx, length);
}
return o;
}
WXDLLIMPEXP_BASE class wxTextInputStream &operator>>(class wxTextInputStream &o, wxLongLong &ll)
{
wxString s = o.ReadWord();
ll = wxLongLong(0l, 0l);
size_t length = s.length();
size_t idx = 0;
wxChar ch = READ_STRING_CHAR(s, idx, length);
// Skip WS
while (ch==wxT(' ') || ch==wxT('\t'))
ch = READ_STRING_CHAR(s, idx, length);
// Ask for sign
int iSign = 1;
if (ch==wxT('-') || ch==wxT('+')) {
iSign = ((ch==wxT('-')) ? -1 : 1);
ch = READ_STRING_CHAR(s, idx, length);
}
// Read number
wxLongLong multiplier(0l, 10l);
while (ch>=wxT('0') && ch<=wxT('9')) {
long lValue = (unsigned) (ch - wxT('0'));
ll = ll * multiplier + wxLongLong(0l, lValue);
ch = READ_STRING_CHAR(s, idx, length);
}
#if wxUSE_LONGLONG_NATIVE
ll = ll * wxLongLong((wxLongLong_t) iSign);
#else
ll = ll * wxLongLong((long) iSign);
#endif
return o;
}
#if wxUSE_LONGLONG_NATIVE
WXDLLIMPEXP_BASE class wxTextOutputStream &operator<<(class wxTextOutputStream &o, wxULongLong_t value)
{
return o << wxULongLong(value).ToString();
}
WXDLLIMPEXP_BASE class wxTextOutputStream &operator<<(class wxTextOutputStream &o, wxLongLong_t value)
{
return o << wxLongLong(value).ToString();
}
WXDLLIMPEXP_BASE class wxTextInputStream &operator>>(class wxTextInputStream &o, wxULongLong_t &value)
{
wxULongLong ll;
o >> ll;
value = ll.GetValue();
return o;
}
WXDLLIMPEXP_BASE class wxTextInputStream &operator>>(class wxTextInputStream &o, wxLongLong_t &value)
{
wxLongLong ll;
o >> ll;
value = ll.GetValue();
return o;
}
#endif // wxUSE_LONGLONG_NATIVE
#endif // wxUSE_STREAMS
#endif // wxUSE_LONGLONG