Simplify BigInt
Change-Id: I1b88648a84760ea16f32566fe0d88e402c328987 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/160888 Tested-by: Jenkins Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
This commit is contained in:
+51
-76
@@ -23,9 +23,11 @@
|
||||
#include <tools/long.hxx>
|
||||
|
||||
#include <cassert>
|
||||
#include <compare>
|
||||
#include <limits>
|
||||
#include <string_view>
|
||||
|
||||
#define MAX_DIGITS 8
|
||||
#define MAX_DIGITS 4
|
||||
|
||||
class SAL_WARN_UNUSED TOOLS_DLLPUBLIC BigInt
|
||||
{
|
||||
@@ -33,21 +35,20 @@ private:
|
||||
// we only use one of these two fields at a time
|
||||
union {
|
||||
sal_Int32 nVal;
|
||||
sal_uInt16 nNum[MAX_DIGITS];
|
||||
sal_uInt32 nNum[MAX_DIGITS];
|
||||
};
|
||||
sal_uInt8 nLen : 5; // current length, if 0, data is in nVal, otherwise data is in nNum
|
||||
bool bIsNeg : 1; // Is Sign negative?
|
||||
sal_uInt8 nLen; // current length, if 0, data is in nVal, otherwise data is in nNum
|
||||
bool bIsNeg; // Is Sign negative?
|
||||
|
||||
TOOLS_DLLPRIVATE void MakeBigInt(BigInt const &);
|
||||
TOOLS_DLLPRIVATE BigInt MakeBig() const;
|
||||
TOOLS_DLLPRIVATE void Normalize();
|
||||
TOOLS_DLLPRIVATE void Mult(BigInt const &, sal_uInt16);
|
||||
TOOLS_DLLPRIVATE void Div(sal_uInt16, sal_uInt16 &);
|
||||
TOOLS_DLLPRIVATE bool IsLess(BigInt const &) const;
|
||||
TOOLS_DLLPRIVATE static BigInt Mult(BigInt const &, sal_uInt32);
|
||||
TOOLS_DLLPRIVATE void Div(sal_uInt32, sal_uInt32 &);
|
||||
TOOLS_DLLPRIVATE bool ABS_IsLessLong(BigInt const &) const;
|
||||
TOOLS_DLLPRIVATE void AddLong(BigInt &, BigInt &);
|
||||
TOOLS_DLLPRIVATE void SubLong(BigInt &, BigInt &);
|
||||
TOOLS_DLLPRIVATE void MultLong(BigInt const &, BigInt &) const;
|
||||
TOOLS_DLLPRIVATE void DivLong(BigInt const &, BigInt &) const;
|
||||
TOOLS_DLLPRIVATE void ModLong(BigInt const &, BigInt &) const;
|
||||
TOOLS_DLLPRIVATE void DivLong(BigInt const &, BigInt &, BigInt * = nullptr) const;
|
||||
TOOLS_DLLPRIVATE bool ABS_IsLess(BigInt const &) const;
|
||||
|
||||
public:
|
||||
@@ -65,32 +66,42 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
#if SAL_TYPES_SIZEOFLONG == 4
|
||||
BigInt(int nValue)
|
||||
: nVal(nValue)
|
||||
, nLen(0)
|
||||
, bIsNeg(false)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
BigInt( double nVal );
|
||||
BigInt( sal_uInt32 nVal );
|
||||
BigInt( sal_Int64 nVal );
|
||||
BigInt( const BigInt& rBigInt );
|
||||
BigInt( std::u16string_view rString );
|
||||
|
||||
template <typename N>
|
||||
requires(std::is_integral_v<N> && std::is_signed_v<N> && sizeof(N) <= sizeof(sal_Int32))
|
||||
BigInt(N val)
|
||||
: BigInt(sal_Int32(val))
|
||||
{
|
||||
}
|
||||
|
||||
template <typename N>
|
||||
requires(std::is_integral_v<N> && std::is_unsigned_v<N> && sizeof(N) <= sizeof(sal_uInt32))
|
||||
BigInt(N val)
|
||||
: BigInt(sal_uInt32(val))
|
||||
{
|
||||
}
|
||||
|
||||
template <typename N>
|
||||
requires(std::is_integral_v<N> && std::is_signed_v<N> && sizeof(N) == sizeof(sal_Int64))
|
||||
BigInt(N val)
|
||||
: BigInt(sal_Int64(val))
|
||||
{
|
||||
}
|
||||
|
||||
operator sal_Int16() const;
|
||||
operator sal_uInt16() const;
|
||||
operator sal_Int32() const;
|
||||
operator sal_uInt32() const;
|
||||
operator double() const;
|
||||
#if SAL_TYPES_SIZEOFPOINTER == 8
|
||||
operator tools::Long() const;
|
||||
#endif
|
||||
operator sal_Int64() const;
|
||||
|
||||
bool IsNeg() const;
|
||||
bool IsZero() const;
|
||||
bool IsNeg() const { return !IsLong() ? bIsNeg : nVal < 0; }
|
||||
bool IsZero() const { return IsLong() && nVal == 0; }
|
||||
bool IsLong() const { return nLen == 0; }
|
||||
|
||||
void Abs();
|
||||
@@ -107,20 +118,8 @@ public:
|
||||
/* Scale and round value */
|
||||
static tools::Long Scale(tools::Long nVal, tools::Long nMult, tools::Long nDiv);
|
||||
|
||||
friend inline BigInt operator +( const BigInt& rVal1, const BigInt& rVal2 );
|
||||
friend inline BigInt operator -( const BigInt& rVal1, const BigInt& rVal2 );
|
||||
friend inline BigInt operator *( const BigInt& rVal1, const BigInt& rVal2 );
|
||||
friend inline BigInt operator /( const BigInt& rVal1, const BigInt& rVal2 );
|
||||
friend inline BigInt operator %( const BigInt& rVal1, const BigInt& rVal2 );
|
||||
|
||||
TOOLS_DLLPUBLIC friend bool operator==( const BigInt& rVal1, const BigInt& rVal2 );
|
||||
friend inline bool operator!=( const BigInt& rVal1, const BigInt& rVal2 );
|
||||
TOOLS_DLLPUBLIC friend bool operator< ( const BigInt& rVal1, const BigInt& rVal2 );
|
||||
friend inline bool operator> ( const BigInt& rVal1, const BigInt& rVal2 );
|
||||
friend inline bool operator<=( const BigInt& rVal1, const BigInt& rVal2 );
|
||||
friend inline bool operator>=( const BigInt& rVal1, const BigInt& rVal2 );
|
||||
|
||||
friend class Fraction;
|
||||
TOOLS_DLLPUBLIC friend std::strong_ordering operator<=> ( const BigInt& rVal1, const BigInt& rVal2 );
|
||||
};
|
||||
|
||||
inline BigInt::operator sal_Int16() const
|
||||
@@ -155,16 +154,25 @@ inline BigInt::operator sal_uInt32() const
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if SAL_TYPES_SIZEOFPOINTER == 8
|
||||
inline BigInt::operator tools::Long() const
|
||||
inline BigInt::operator sal_Int64() const
|
||||
{
|
||||
// Clamp to int32 since long is int32 on Windows.
|
||||
if (nLen == 0)
|
||||
return nVal;
|
||||
constexpr sal_uInt64 maxForPosInt64 = std::numeric_limits<sal_Int64>::max();
|
||||
constexpr sal_uInt64 maxForNegInt64 = std::numeric_limits<sal_Int64>::min();
|
||||
switch (nLen)
|
||||
{
|
||||
case 0:
|
||||
return nVal;
|
||||
case 1:
|
||||
return bIsNeg ? -sal_Int64(nNum[0]) : nNum[0];
|
||||
case 2:
|
||||
if (sal_uInt64 n = (sal_uInt64(nNum[1]) << 32) + nNum[0]; bIsNeg && n <= maxForNegInt64)
|
||||
return -sal_Int64(n); // maxForNegInt64 will convert correctly
|
||||
else if (!bIsNeg && n <= maxForPosInt64)
|
||||
return n;
|
||||
}
|
||||
assert(false && "out of range");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
inline BigInt& BigInt::operator =( sal_Int32 nValue )
|
||||
{
|
||||
@@ -174,22 +182,6 @@ inline BigInt& BigInt::operator =( sal_Int32 nValue )
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline bool BigInt::IsNeg() const
|
||||
{
|
||||
if ( nLen == 0 )
|
||||
return (nVal < 0);
|
||||
else
|
||||
return bIsNeg;
|
||||
}
|
||||
|
||||
inline bool BigInt::IsZero() const
|
||||
{
|
||||
if ( nLen != 0 )
|
||||
return false;
|
||||
else
|
||||
return (nVal == 0);
|
||||
}
|
||||
|
||||
inline void BigInt::Abs()
|
||||
{
|
||||
if ( nLen != 0 )
|
||||
@@ -233,23 +225,6 @@ inline BigInt operator%( const BigInt &rVal1, const BigInt &rVal2 )
|
||||
return aErg;
|
||||
}
|
||||
|
||||
inline bool operator!=( const BigInt& rVal1, const BigInt& rVal2 )
|
||||
{
|
||||
return !(rVal1 == rVal2);
|
||||
}
|
||||
|
||||
inline bool operator>(const BigInt& rVal1, const BigInt& rVal2) { return rVal2 < rVal1; }
|
||||
|
||||
inline bool operator<=( const BigInt& rVal1, const BigInt& rVal2 )
|
||||
{
|
||||
return !( rVal1 > rVal2);
|
||||
}
|
||||
|
||||
inline bool operator>=( const BigInt& rVal1, const BigInt& rVal2 )
|
||||
{
|
||||
return !(rVal1 < rVal2);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|
||||
|
||||
+187
-313
@@ -38,123 +38,116 @@ const sal_Int32 MY_MINLONG = -MY_MAXLONG;
|
||||
* chapter 4.3.1. The Classical Algorithms.
|
||||
*/
|
||||
|
||||
// TODO: Needs conversion to sal_uInt16/INT16/sal_uInt32/sal_Int32
|
||||
void BigInt::MakeBigInt( const BigInt& rVal )
|
||||
BigInt BigInt::MakeBig() const
|
||||
{
|
||||
if ( rVal.nLen != 0 )
|
||||
if (!IsLong())
|
||||
{
|
||||
memcpy( static_cast<void*>(this), static_cast<const void*>(&rVal), sizeof( BigInt ) );
|
||||
while ( nLen > 1 && nNum[nLen-1] == 0 )
|
||||
nLen--;
|
||||
BigInt ret(*this);
|
||||
while ( ret.nLen > 1 && ret.nNum[ret.nLen-1] == 0 )
|
||||
ret.nLen--;
|
||||
return ret;
|
||||
}
|
||||
|
||||
BigInt ret;
|
||||
if (nVal < 0)
|
||||
{
|
||||
ret.bIsNeg = true;
|
||||
ret.nNum[0] = -static_cast<sal_Int64>(nVal);
|
||||
}
|
||||
else
|
||||
{
|
||||
nVal = rVal.nVal;
|
||||
sal_uInt32 nTmp;
|
||||
if (nVal < 0)
|
||||
{
|
||||
bIsNeg = true;
|
||||
nTmp = -static_cast<sal_Int64>(nVal);
|
||||
}
|
||||
else
|
||||
{
|
||||
bIsNeg = false;
|
||||
nTmp = nVal;
|
||||
}
|
||||
|
||||
nNum[0] = static_cast<sal_uInt16>(nTmp & 0xffffL);
|
||||
nNum[1] = static_cast<sal_uInt16>(nTmp >> 16);
|
||||
if ( nTmp & 0xffff0000L )
|
||||
nLen = 2;
|
||||
else
|
||||
nLen = 1;
|
||||
ret.bIsNeg = false;
|
||||
ret.nNum[0] = nVal;
|
||||
}
|
||||
ret.nLen = 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void BigInt::Normalize()
|
||||
{
|
||||
// nLen == 0 means that the active union member is nVal, otherwise nNum
|
||||
if ( nLen != 0 )
|
||||
{
|
||||
while ( nLen > 1 && nNum[nLen-1] == 0 )
|
||||
nLen--;
|
||||
|
||||
if ( nLen < 3 )
|
||||
if (nLen < 2)
|
||||
{
|
||||
sal_Int32 newVal;
|
||||
if ( nLen < 2 )
|
||||
newVal = nNum[0];
|
||||
else if ( nNum[1] & 0x8000 )
|
||||
return;
|
||||
else
|
||||
newVal = (static_cast<sal_Int32>(nNum[1]) << 16) + nNum[0];
|
||||
|
||||
nLen = 0;
|
||||
nVal = newVal;
|
||||
|
||||
if ( bIsNeg )
|
||||
nVal = -nVal;
|
||||
constexpr sal_uInt32 maxForPosInt32 = std::numeric_limits<sal_Int32>::max();
|
||||
constexpr sal_uInt32 maxForNegInt32 = -sal_Int64(std::numeric_limits<sal_Int32>::min());
|
||||
if (bIsNeg && nNum[0] <= maxForNegInt32)
|
||||
{
|
||||
nVal = -sal_Int64(nNum[0]);
|
||||
nLen = 0;
|
||||
}
|
||||
else if (!bIsNeg && nNum[0] <= maxForPosInt32)
|
||||
{
|
||||
nVal = nNum[0];
|
||||
nLen = 0;
|
||||
}
|
||||
}
|
||||
// else nVal is undefined !!! W.P.
|
||||
}
|
||||
// why? nVal is undefined ??? W.P.
|
||||
else if ( nVal & 0xFFFF0000L )
|
||||
nLen = 2;
|
||||
else
|
||||
nLen = 1;
|
||||
}
|
||||
|
||||
void BigInt::Mult( const BigInt &rVal, sal_uInt16 nMul )
|
||||
BigInt BigInt::Mult( const BigInt &rVal, sal_uInt32 nMul )
|
||||
{
|
||||
sal_uInt16 nK = 0;
|
||||
assert(!rVal.IsLong());
|
||||
BigInt ret;
|
||||
sal_uInt64 nK = 0;
|
||||
for ( int i = 0; i < rVal.nLen; i++ )
|
||||
{
|
||||
sal_uInt32 nTmp = static_cast<sal_uInt32>(rVal.nNum[i]) * static_cast<sal_uInt32>(nMul) + nK;
|
||||
nK = static_cast<sal_uInt16>(nTmp >> 16);
|
||||
nNum[i] = static_cast<sal_uInt16>(nTmp);
|
||||
sal_uInt64 nTmp = static_cast<sal_uInt64>(rVal.nNum[i]) * nMul + nK;
|
||||
nK = nTmp >> 32;
|
||||
ret.nNum[i] = static_cast<sal_uInt32>(nTmp);
|
||||
}
|
||||
|
||||
if ( nK )
|
||||
{
|
||||
nNum[rVal.nLen] = nK;
|
||||
nLen = rVal.nLen + 1;
|
||||
assert(rVal.nLen < MAX_DIGITS);
|
||||
ret.nNum[rVal.nLen] = nK;
|
||||
ret.nLen = rVal.nLen + 1;
|
||||
}
|
||||
else
|
||||
nLen = rVal.nLen;
|
||||
ret.nLen = rVal.nLen;
|
||||
|
||||
bIsNeg = rVal.bIsNeg;
|
||||
ret.bIsNeg = rVal.bIsNeg;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void BigInt::Div( sal_uInt16 nDiv, sal_uInt16& rRem )
|
||||
void BigInt::Div( sal_uInt32 nDiv, sal_uInt32& rRem )
|
||||
{
|
||||
sal_uInt32 nK = 0;
|
||||
assert(!IsLong());
|
||||
sal_uInt64 nK = 0;
|
||||
for ( int i = nLen - 1; i >= 0; i-- )
|
||||
{
|
||||
sal_uInt32 nTmp = static_cast<sal_uInt32>(nNum[i]) + (nK << 16);
|
||||
nNum[i] = static_cast<sal_uInt16>(nTmp / nDiv);
|
||||
sal_uInt64 nTmp = nNum[i] + (nK << 32);
|
||||
nNum[i] = nTmp / nDiv;
|
||||
nK = nTmp % nDiv;
|
||||
}
|
||||
rRem = static_cast<sal_uInt16>(nK);
|
||||
rRem = nK;
|
||||
|
||||
if ( nNum[nLen-1] == 0 )
|
||||
nLen -= 1;
|
||||
}
|
||||
|
||||
bool BigInt::IsLess( const BigInt& rVal ) const
|
||||
bool BigInt::ABS_IsLessLong(const BigInt& rVal) const
|
||||
{
|
||||
assert(!IsLong() && !rVal.IsLong());
|
||||
if ( rVal.nLen < nLen)
|
||||
return true;
|
||||
if ( rVal.nLen > nLen )
|
||||
return false;
|
||||
if ( rVal.nLen > nLen )
|
||||
return true;
|
||||
|
||||
int i;
|
||||
for ( i = nLen - 1; i > 0 && nNum[i] == rVal.nNum[i]; i-- )
|
||||
{
|
||||
}
|
||||
return rVal.nNum[i] < nNum[i];
|
||||
return nNum[i] < rVal.nNum[i];
|
||||
}
|
||||
|
||||
void BigInt::AddLong( BigInt& rB, BigInt& rErg )
|
||||
{
|
||||
assert(!IsLong() && !rB.IsLong());
|
||||
if ( bIsNeg == rB.bIsNeg )
|
||||
{
|
||||
int i;
|
||||
@@ -176,48 +169,42 @@ void BigInt::AddLong( BigInt& rB, BigInt& rErg )
|
||||
}
|
||||
|
||||
// Add numerals, starting from the back
|
||||
sal_Int32 k;
|
||||
sal_Int32 nZ = 0;
|
||||
for (i = 0, k = 0; i < len; i++) {
|
||||
nZ = static_cast<sal_Int32>(nNum[i]) + static_cast<sal_Int32>(rB.nNum[i]) + k;
|
||||
if (nZ & 0xff0000L)
|
||||
sal_Int64 k = 0;
|
||||
for (i = 0; i < len; i++) {
|
||||
sal_Int64 nZ = static_cast<sal_Int64>(nNum[i]) + static_cast<sal_Int64>(rB.nNum[i]) + k;
|
||||
if (nZ > sal_Int64(std::numeric_limits<sal_uInt32>::max()))
|
||||
k = 1;
|
||||
else
|
||||
k = 0;
|
||||
rErg.nNum[i] = static_cast<sal_uInt16>(nZ & 0xffffL);
|
||||
rErg.nNum[i] = static_cast<sal_uInt32>(nZ);
|
||||
}
|
||||
// If an overflow occurred, add to solution
|
||||
if (nZ & 0xff0000L) // or if(k)
|
||||
if (k)
|
||||
{
|
||||
assert(i < MAX_DIGITS);
|
||||
rErg.nNum[i] = 1;
|
||||
len++;
|
||||
}
|
||||
// Set length and sign
|
||||
rErg.nLen = len;
|
||||
rErg.bIsNeg = bIsNeg && rB.bIsNeg;
|
||||
rErg.bIsNeg = bIsNeg;
|
||||
}
|
||||
// If one of the values is negative, perform subtraction instead
|
||||
else if (bIsNeg)
|
||||
{
|
||||
bIsNeg = false;
|
||||
rB.SubLong(*this, rErg);
|
||||
bIsNeg = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
rB.bIsNeg = false;
|
||||
SubLong(rB, rErg);
|
||||
rB.bIsNeg = true;
|
||||
bIsNeg = !bIsNeg;
|
||||
rB.SubLong(*this, rErg);
|
||||
bIsNeg = !bIsNeg;
|
||||
}
|
||||
}
|
||||
|
||||
void BigInt::SubLong( BigInt& rB, BigInt& rErg )
|
||||
{
|
||||
assert(!IsLong() && !rB.IsLong());
|
||||
if ( bIsNeg == rB.bIsNeg )
|
||||
{
|
||||
int i;
|
||||
char len;
|
||||
sal_Int32 nZ, k;
|
||||
|
||||
// if length of the two values differ, fill remaining positions
|
||||
// of the smaller value with zeros.
|
||||
@@ -234,119 +221,105 @@ void BigInt::SubLong( BigInt& rB, BigInt& rErg )
|
||||
nNum[i] = 0;
|
||||
}
|
||||
|
||||
if ( IsLess(rB) )
|
||||
const bool bThisIsLess = ABS_IsLessLong(rB);
|
||||
BigInt& rGreater = bThisIsLess ? rB : *this;
|
||||
BigInt& rSmaller = bThisIsLess ? *this : rB;
|
||||
|
||||
sal_Int64 k = 0;
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
for (i = 0, k = 0; i < len; i++)
|
||||
{
|
||||
nZ = static_cast<sal_Int32>(nNum[i]) - static_cast<sal_Int32>(rB.nNum[i]) + k;
|
||||
if (nZ < 0)
|
||||
k = -1;
|
||||
else
|
||||
k = 0;
|
||||
rErg.nNum[i] = static_cast<sal_uInt16>(nZ & 0xffffL);
|
||||
}
|
||||
rErg.bIsNeg = bIsNeg;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0, k = 0; i < len; i++)
|
||||
{
|
||||
nZ = static_cast<sal_Int32>(rB.nNum[i]) - static_cast<sal_Int32>(nNum[i]) + k;
|
||||
if (nZ < 0)
|
||||
k = -1;
|
||||
else
|
||||
k = 0;
|
||||
rErg.nNum[i] = static_cast<sal_uInt16>(nZ & 0xffffL);
|
||||
}
|
||||
// if a < b, revert sign
|
||||
rErg.bIsNeg = !bIsNeg;
|
||||
sal_Int64 nZ = static_cast<sal_Int64>(rGreater.nNum[i]) - static_cast<sal_Int64>(rSmaller.nNum[i]) + k;
|
||||
if (nZ < 0)
|
||||
k = -1;
|
||||
else
|
||||
k = 0;
|
||||
rErg.nNum[i] = static_cast<sal_uInt32>(nZ);
|
||||
}
|
||||
|
||||
// if a < b, revert sign
|
||||
rErg.bIsNeg = bThisIsLess ? !bIsNeg : bIsNeg;
|
||||
rErg.nLen = len;
|
||||
}
|
||||
// If one of the values is negative, perform addition instead
|
||||
else if (bIsNeg)
|
||||
{
|
||||
bIsNeg = false;
|
||||
AddLong(rB, rErg);
|
||||
bIsNeg = true;
|
||||
rErg.bIsNeg = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
rB.bIsNeg = false;
|
||||
bIsNeg = !bIsNeg;
|
||||
AddLong(rB, rErg);
|
||||
rB.bIsNeg = true;
|
||||
rErg.bIsNeg = false;
|
||||
bIsNeg = !bIsNeg;
|
||||
rErg.bIsNeg = bIsNeg;
|
||||
}
|
||||
}
|
||||
|
||||
void BigInt::MultLong( const BigInt& rB, BigInt& rErg ) const
|
||||
{
|
||||
int i, j;
|
||||
sal_uInt32 nZ, k;
|
||||
assert(!IsLong() && !rB.IsLong());
|
||||
|
||||
rErg.bIsNeg = bIsNeg != rB.bIsNeg;
|
||||
rErg.nLen = nLen + rB.nLen;
|
||||
assert(rErg.nLen <= MAX_DIGITS);
|
||||
|
||||
int i;
|
||||
for (i = 0; i < rErg.nLen; i++)
|
||||
rErg.nNum[i] = 0;
|
||||
|
||||
for (j = 0; j < rB.nLen; j++)
|
||||
for (int j = 0; j < rB.nLen; j++)
|
||||
{
|
||||
for (i = 0, k = 0; i < nLen; i++)
|
||||
sal_uInt64 k = 0;
|
||||
for (i = 0; i < nLen; i++)
|
||||
{
|
||||
nZ = static_cast<sal_uInt32>(nNum[i]) * static_cast<sal_uInt32>(rB.nNum[j]) +
|
||||
static_cast<sal_uInt32>(rErg.nNum[i + j]) + k;
|
||||
rErg.nNum[i + j] = static_cast<sal_uInt16>(nZ & 0xffffU);
|
||||
k = nZ >> 16;
|
||||
sal_uInt64 nZ = static_cast<sal_uInt64>(nNum[i]) * static_cast<sal_uInt64>(rB.nNum[j]) +
|
||||
static_cast<sal_uInt64>(rErg.nNum[i + j]) + k;
|
||||
rErg.nNum[i + j] = static_cast<sal_uInt32>(nZ);
|
||||
k = nZ >> 32;
|
||||
}
|
||||
rErg.nNum[i + j] = static_cast<sal_uInt16>(k);
|
||||
rErg.nNum[i + j] = k;
|
||||
}
|
||||
}
|
||||
|
||||
void BigInt::DivLong( const BigInt& rB, BigInt& rErg ) const
|
||||
void BigInt::DivLong( const BigInt& rB, BigInt& rErg, BigInt* pMod ) const
|
||||
{
|
||||
int i, j;
|
||||
sal_uInt16 nK, nQ, nMult;
|
||||
sal_uInt16 nLenB = rB.nLen;
|
||||
sal_uInt16 nLenB1 = rB.nLen - 1;
|
||||
BigInt aTmpA, aTmpB;
|
||||
assert(!IsLong() && !rB.IsLong());
|
||||
|
||||
nMult = static_cast<sal_uInt16>(0x10000L / (static_cast<sal_Int32>(rB.nNum[nLenB1]) + 1));
|
||||
const int nLenB1 = rB.nLen - 1;
|
||||
const sal_uInt32 nMult = static_cast<sal_uInt32>(0x100000000 / (static_cast<sal_Int64>(rB.nNum[nLenB1]) + 1));
|
||||
|
||||
aTmpA.Mult( *this, nMult );
|
||||
BigInt aTmpA = Mult(*this, nMult);
|
||||
if ( aTmpA.nLen == nLen )
|
||||
{
|
||||
assert(aTmpA.nLen < MAX_DIGITS);
|
||||
aTmpA.nNum[aTmpA.nLen] = 0;
|
||||
aTmpA.nLen++;
|
||||
}
|
||||
|
||||
aTmpB.Mult( rB, nMult );
|
||||
BigInt aTmpB = Mult(rB, nMult);
|
||||
|
||||
for (j = aTmpA.nLen - 1; j >= nLenB; j--)
|
||||
const int nLenB = rB.nLen;
|
||||
for (int j = aTmpA.nLen - 1; j >= nLenB; j--)
|
||||
{ // guess divisor
|
||||
sal_uInt32 nTmp = ( static_cast<sal_uInt32>(aTmpA.nNum[j]) << 16 ) + aTmpA.nNum[j - 1];
|
||||
sal_uInt64 nTmp = ( static_cast<sal_uInt64>(aTmpA.nNum[j]) << 32 ) + aTmpA.nNum[j - 1];
|
||||
sal_uInt32 nQ;
|
||||
if (aTmpA.nNum[j] == aTmpB.nNum[nLenB1])
|
||||
nQ = 0xFFFF;
|
||||
nQ = 0xFFFFFFFF;
|
||||
else
|
||||
nQ = static_cast<sal_uInt16>(nTmp / aTmpB.nNum[nLenB1]);
|
||||
nQ = static_cast<sal_uInt32>(nTmp / aTmpB.nNum[nLenB1]);
|
||||
|
||||
if ( (static_cast<sal_uInt32>(aTmpB.nNum[nLenB1 - 1]) * nQ) >
|
||||
((nTmp - static_cast<sal_uInt32>(aTmpB.nNum[nLenB1]) * nQ) << 16) + aTmpA.nNum[j - 2])
|
||||
if ( (static_cast<sal_uInt64>(aTmpB.nNum[nLenB1 - 1]) * nQ) >
|
||||
((nTmp - static_cast<sal_uInt64>(aTmpB.nNum[nLenB1]) * nQ) << 32) + aTmpA.nNum[j - 2])
|
||||
nQ--;
|
||||
// Start division
|
||||
nK = 0;
|
||||
sal_uInt32 nK = 0;
|
||||
int i;
|
||||
for (i = 0; i < nLenB; i++)
|
||||
{
|
||||
nTmp = static_cast<sal_uInt32>(aTmpA.nNum[j - nLenB + i])
|
||||
- (static_cast<sal_uInt32>(aTmpB.nNum[i]) * nQ)
|
||||
nTmp = static_cast<sal_uInt64>(aTmpA.nNum[j - nLenB + i])
|
||||
- (static_cast<sal_uInt64>(aTmpB.nNum[i]) * nQ)
|
||||
- nK;
|
||||
aTmpA.nNum[j - nLenB + i] = static_cast<sal_uInt16>(nTmp);
|
||||
nK = static_cast<sal_uInt16>(nTmp >> 16);
|
||||
aTmpA.nNum[j - nLenB + i] = static_cast<sal_uInt32>(nTmp);
|
||||
nK = static_cast<sal_uInt32>(nTmp >> 32);
|
||||
if ( nK )
|
||||
nK = static_cast<sal_uInt16>(0x10000U - nK);
|
||||
nK = static_cast<sal_uInt32>(0x100000000 - nK);
|
||||
}
|
||||
sal_uInt16& rNum( aTmpA.nNum[j - nLenB + i] );
|
||||
sal_uInt32& rNum( aTmpA.nNum[j - nLenB + i] );
|
||||
rNum -= nK;
|
||||
if (aTmpA.nNum[j - nLenB + i] == 0)
|
||||
rErg.nNum[j - nLenB] = nQ;
|
||||
@@ -357,8 +330,8 @@ void BigInt::DivLong( const BigInt& rB, BigInt& rErg ) const
|
||||
for (i = 0; i < nLenB; i++)
|
||||
{
|
||||
nTmp = aTmpA.nNum[j - nLenB + i] + aTmpB.nNum[i] + nK;
|
||||
aTmpA.nNum[j - nLenB + i] = static_cast<sal_uInt16>(nTmp & 0xFFFFL);
|
||||
if (nTmp & 0xFFFF0000L)
|
||||
aTmpA.nNum[j - nLenB + i] = static_cast<sal_uInt32>(nTmp & 0xFFFFFFFF);
|
||||
if (nTmp > std::numeric_limits<sal_uInt32>::max())
|
||||
nK = 1;
|
||||
else
|
||||
nK = 0;
|
||||
@@ -368,101 +341,24 @@ void BigInt::DivLong( const BigInt& rB, BigInt& rErg ) const
|
||||
|
||||
rErg.bIsNeg = bIsNeg != rB.bIsNeg;
|
||||
rErg.nLen = nLen - rB.nLen + 1;
|
||||
}
|
||||
|
||||
void BigInt::ModLong( const BigInt& rB, BigInt& rErg ) const
|
||||
{
|
||||
sal_uInt16 i, j;
|
||||
sal_uInt16 nK, nQ, nMult;
|
||||
sal_Int16 nLenB = rB.nLen;
|
||||
sal_Int16 nLenB1 = rB.nLen - 1;
|
||||
BigInt aTmpA, aTmpB;
|
||||
|
||||
nMult = static_cast<sal_uInt16>(0x10000L / (static_cast<sal_Int32>(rB.nNum[nLenB1]) + 1));
|
||||
|
||||
aTmpA.Mult( *this, nMult);
|
||||
if ( aTmpA.nLen == nLen )
|
||||
if (pMod)
|
||||
{
|
||||
aTmpA.nNum[aTmpA.nLen] = 0;
|
||||
aTmpA.nLen++;
|
||||
*pMod = aTmpA;
|
||||
sal_uInt32 nQ;
|
||||
pMod->Div(nMult, nQ);
|
||||
}
|
||||
|
||||
aTmpB.Mult( rB, nMult);
|
||||
|
||||
for (j = aTmpA.nLen - 1; j >= nLenB; j--)
|
||||
{ // Guess divisor
|
||||
sal_uInt32 nTmp = ( static_cast<sal_uInt32>(aTmpA.nNum[j]) << 16 ) + aTmpA.nNum[j - 1];
|
||||
if (aTmpA.nNum[j] == aTmpB.nNum[nLenB1])
|
||||
nQ = 0xFFFF;
|
||||
else
|
||||
nQ = static_cast<sal_uInt16>(nTmp / aTmpB.nNum[nLenB1]);
|
||||
|
||||
if ( (static_cast<sal_uInt32>(aTmpB.nNum[nLenB1 - 1]) * nQ) >
|
||||
((nTmp - aTmpB.nNum[nLenB1] * nQ) << 16) + aTmpA.nNum[j - 2])
|
||||
nQ--;
|
||||
// Start division
|
||||
nK = 0;
|
||||
for (i = 0; i < nLenB; i++)
|
||||
{
|
||||
nTmp = static_cast<sal_uInt32>(aTmpA.nNum[j - nLenB + i])
|
||||
- (static_cast<sal_uInt32>(aTmpB.nNum[i]) * nQ)
|
||||
- nK;
|
||||
aTmpA.nNum[j - nLenB + i] = static_cast<sal_uInt16>(nTmp);
|
||||
nK = static_cast<sal_uInt16>(nTmp >> 16);
|
||||
if ( nK )
|
||||
nK = static_cast<sal_uInt16>(0x10000U - nK);
|
||||
}
|
||||
sal_uInt16& rNum( aTmpA.nNum[j - nLenB + i] );
|
||||
rNum = rNum - nK;
|
||||
if (aTmpA.nNum[j - nLenB + i] == 0)
|
||||
rErg.nNum[j - nLenB] = nQ;
|
||||
else
|
||||
{
|
||||
rErg.nNum[j - nLenB] = nQ - 1;
|
||||
nK = 0;
|
||||
for (i = 0; i < nLenB; i++) {
|
||||
nTmp = aTmpA.nNum[j - nLenB + i] + aTmpB.nNum[i] + nK;
|
||||
aTmpA.nNum[j - nLenB + i] = static_cast<sal_uInt16>(nTmp & 0xFFFFL);
|
||||
if (nTmp & 0xFFFF0000L)
|
||||
nK = 1;
|
||||
else
|
||||
nK = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rErg = aTmpA;
|
||||
rErg.Div( nMult, nQ );
|
||||
}
|
||||
|
||||
bool BigInt::ABS_IsLess( const BigInt& rB ) const
|
||||
{
|
||||
if (nLen != 0 || rB.nLen != 0)
|
||||
{
|
||||
BigInt nA, nB;
|
||||
nA.MakeBigInt( *this );
|
||||
nB.MakeBigInt( rB );
|
||||
if (nA.nLen == nB.nLen)
|
||||
{
|
||||
int i;
|
||||
for (i = nA.nLen - 1; i > 0 && nA.nNum[i] == nB.nNum[i]; i--)
|
||||
{
|
||||
}
|
||||
return nA.nNum[i] < nB.nNum[i];
|
||||
}
|
||||
else
|
||||
return nA.nLen < nB.nLen;
|
||||
}
|
||||
return MakeBig().ABS_IsLessLong(rB.MakeBig());
|
||||
|
||||
if ( nVal < 0 )
|
||||
if ( rB.nVal < 0 )
|
||||
return nVal > rB.nVal;
|
||||
else
|
||||
return nVal > -rB.nVal;
|
||||
return nVal > (rB.nVal < 0 ? rB.nVal : -rB.nVal);
|
||||
else
|
||||
if ( rB.nVal < 0 )
|
||||
return nVal < -rB.nVal;
|
||||
else
|
||||
return nVal < rB.nVal;
|
||||
return nVal < (rB.nVal < 0 ? -rB.nVal : rB.nVal);
|
||||
}
|
||||
|
||||
BigInt::BigInt( const BigInt& rBigInt )
|
||||
@@ -527,15 +423,15 @@ BigInt::BigInt( double nValue )
|
||||
{
|
||||
int i=0;
|
||||
|
||||
while ( ( nValue > 65536.0 ) && ( i < MAX_DIGITS ) )
|
||||
while ( ( nValue > 0x100000000 ) && ( i < MAX_DIGITS ) )
|
||||
{
|
||||
nNum[i] = static_cast<sal_uInt16>(fmod( nValue, 65536.0 ));
|
||||
nNum[i] = static_cast<sal_uInt32>(fmod( nValue, 0x100000000 ));
|
||||
nValue -= nNum[i];
|
||||
nValue /= 65536.0;
|
||||
nValue /= 0x100000000;
|
||||
i++;
|
||||
}
|
||||
if ( i < MAX_DIGITS )
|
||||
nNum[i++] = static_cast<sal_uInt16>(nValue);
|
||||
nNum[i++] = static_cast<sal_uInt32>(nValue);
|
||||
|
||||
nLen = i;
|
||||
|
||||
@@ -546,17 +442,15 @@ BigInt::BigInt( double nValue )
|
||||
|
||||
BigInt::BigInt( sal_uInt32 nValue )
|
||||
: nVal(0)
|
||||
, bIsNeg(false)
|
||||
{
|
||||
if ( nValue & 0x80000000U )
|
||||
{
|
||||
bIsNeg = false;
|
||||
nNum[0] = static_cast<sal_uInt16>(nValue & 0xffffU);
|
||||
nNum[1] = static_cast<sal_uInt16>(nValue >> 16);
|
||||
nLen = 2;
|
||||
nNum[0] = nValue;
|
||||
nLen = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
bIsNeg = false;
|
||||
nVal = nValue;
|
||||
nLen = 0;
|
||||
}
|
||||
@@ -575,10 +469,10 @@ BigInt::BigInt( sal_Int64 nValue )
|
||||
else
|
||||
{
|
||||
sal_uInt64 nUValue = static_cast<sal_uInt64>(bIsNeg ? -nValue : nValue);
|
||||
for (int i = 0; (i != sizeof(sal_uInt64) / 2) && (nUValue != 0); ++i)
|
||||
for (int i = 0; (i != sizeof(sal_uInt64) / 4) && (nUValue != 0); ++i)
|
||||
{
|
||||
nNum[i] = static_cast<sal_uInt16>(nUValue & 0xffffUL);
|
||||
nUValue = nUValue >> 16;
|
||||
nNum[i] = static_cast<sal_uInt32>(nUValue);
|
||||
nUValue = nUValue >> 32;
|
||||
++nLen;
|
||||
}
|
||||
}
|
||||
@@ -586,18 +480,18 @@ BigInt::BigInt( sal_Int64 nValue )
|
||||
|
||||
BigInt::operator double() const
|
||||
{
|
||||
if ( nLen == 0 )
|
||||
if (IsLong())
|
||||
return static_cast<double>(nVal);
|
||||
else
|
||||
{
|
||||
int i = nLen-1;
|
||||
double nRet = static_cast<double>(static_cast<sal_uInt32>(nNum[i]));
|
||||
double nRet = static_cast<double>(nNum[i]);
|
||||
|
||||
while ( i )
|
||||
{
|
||||
nRet *= 65536.0;
|
||||
nRet *= 0x100000000;
|
||||
i--;
|
||||
nRet += static_cast<double>(static_cast<sal_uInt32>(nNum[i]));
|
||||
nRet += static_cast<double>(nNum[i]);
|
||||
}
|
||||
|
||||
if ( bIsNeg )
|
||||
@@ -640,10 +534,8 @@ BigInt& BigInt::operator+=( const BigInt& rVal )
|
||||
}
|
||||
}
|
||||
|
||||
BigInt aTmp1, aTmp2;
|
||||
aTmp1.MakeBigInt( *this );
|
||||
aTmp2.MakeBigInt( rVal );
|
||||
aTmp1.AddLong( aTmp2, *this );
|
||||
BigInt aTmp2 = rVal.MakeBig();
|
||||
MakeBig().AddLong(aTmp2, *this);
|
||||
Normalize();
|
||||
return *this;
|
||||
}
|
||||
@@ -666,10 +558,8 @@ BigInt& BigInt::operator-=( const BigInt& rVal )
|
||||
}
|
||||
}
|
||||
|
||||
BigInt aTmp1, aTmp2;
|
||||
aTmp1.MakeBigInt( *this );
|
||||
aTmp2.MakeBigInt( rVal );
|
||||
aTmp1.SubLong( aTmp2, *this );
|
||||
BigInt aTmp2 = rVal.MakeBig();
|
||||
MakeBig().SubLong(aTmp2, *this);
|
||||
Normalize();
|
||||
return *this;
|
||||
}
|
||||
@@ -688,10 +578,7 @@ BigInt& BigInt::operator*=( const BigInt& rVal )
|
||||
}
|
||||
else
|
||||
{
|
||||
BigInt aTmp1, aTmp2;
|
||||
aTmp1.MakeBigInt( rVal );
|
||||
aTmp2.MakeBigInt( *this );
|
||||
aTmp1.MultLong(aTmp2, *this);
|
||||
rVal.MakeBig().MultLong(MakeBig(), *this);
|
||||
Normalize();
|
||||
}
|
||||
return *this;
|
||||
@@ -723,35 +610,29 @@ BigInt& BigInt::operator/=( const BigInt& rVal )
|
||||
return *this;
|
||||
}
|
||||
|
||||
if ( rVal.nVal <= 0xFFFF && rVal.nVal >= -0xFFFF )
|
||||
// Divide BigInt with an sal_uInt32
|
||||
sal_uInt32 nTmp;
|
||||
if ( rVal.nVal < 0 )
|
||||
{
|
||||
// Divide BigInt with an sal_uInt16
|
||||
sal_uInt16 nTmp;
|
||||
if ( rVal.nVal < 0 )
|
||||
{
|
||||
nTmp = static_cast<sal_uInt16>(-rVal.nVal);
|
||||
bIsNeg = !bIsNeg;
|
||||
}
|
||||
else
|
||||
nTmp = static_cast<sal_uInt16>(rVal.nVal);
|
||||
|
||||
Div( nTmp, nTmp );
|
||||
Normalize();
|
||||
return *this;
|
||||
nTmp = static_cast<sal_uInt32>(-rVal.nVal);
|
||||
bIsNeg = !bIsNeg;
|
||||
}
|
||||
else
|
||||
nTmp = static_cast<sal_uInt32>(rVal.nVal);
|
||||
|
||||
Div( nTmp, nTmp );
|
||||
Normalize();
|
||||
return *this;
|
||||
}
|
||||
|
||||
if ( ABS_IsLess( rVal ) )
|
||||
{
|
||||
*this = BigInt( 0 );
|
||||
*this = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Divide BigInt with BigInt
|
||||
BigInt aTmp1, aTmp2;
|
||||
aTmp1.MakeBigInt( *this );
|
||||
aTmp2.MakeBigInt( rVal );
|
||||
aTmp1.DivLong(aTmp2, *this);
|
||||
MakeBig().DivLong(rVal.MakeBig(), *this);
|
||||
Normalize();
|
||||
return *this;
|
||||
}
|
||||
@@ -773,64 +654,57 @@ BigInt& BigInt::operator%=( const BigInt& rVal )
|
||||
return *this;
|
||||
}
|
||||
|
||||
if ( rVal.nVal <= 0xFFFF && rVal.nVal >= -0xFFFF )
|
||||
// Divide Bigint by int16
|
||||
sal_uInt32 nTmp;
|
||||
if ( rVal.nVal < 0 )
|
||||
{
|
||||
// Divide Bigint by int16
|
||||
sal_uInt16 nTmp;
|
||||
if ( rVal.nVal < 0 )
|
||||
{
|
||||
nTmp = static_cast<sal_uInt16>(-rVal.nVal);
|
||||
bIsNeg = !bIsNeg;
|
||||
}
|
||||
else
|
||||
nTmp = static_cast<sal_uInt16>(rVal.nVal);
|
||||
|
||||
Div( nTmp, nTmp );
|
||||
*this = BigInt( nTmp );
|
||||
return *this;
|
||||
nTmp = static_cast<sal_uInt32>(-rVal.nVal);
|
||||
bIsNeg = !bIsNeg;
|
||||
}
|
||||
else
|
||||
nTmp = static_cast<sal_uInt32>(rVal.nVal);
|
||||
|
||||
Div( nTmp, nTmp );
|
||||
*this = BigInt( nTmp );
|
||||
return *this;
|
||||
}
|
||||
|
||||
if ( ABS_IsLess( rVal ) )
|
||||
return *this;
|
||||
|
||||
// Divide BigInt with BigInt
|
||||
BigInt aTmp1, aTmp2;
|
||||
aTmp1.MakeBigInt( *this );
|
||||
aTmp2.MakeBigInt( rVal );
|
||||
aTmp1.ModLong(aTmp2, *this);
|
||||
BigInt tmp;
|
||||
MakeBig().DivLong(rVal.MakeBig(), tmp, this);
|
||||
Normalize();
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==( const BigInt& rVal1, const BigInt& rVal2 )
|
||||
{
|
||||
if (rVal1.nLen == 0 && rVal2.nLen == 0)
|
||||
if (rVal1.IsLong() && rVal2.IsLong())
|
||||
return rVal1.nVal == rVal2.nVal;
|
||||
|
||||
BigInt nA, nB;
|
||||
nA.MakeBigInt(rVal1);
|
||||
nB.MakeBigInt(rVal2);
|
||||
BigInt nA = rVal1.MakeBig(), nB = rVal2.MakeBig();
|
||||
return nA.bIsNeg == nB.bIsNeg && nA.nLen == nB.nLen
|
||||
&& std::equal(nA.nNum, nA.nNum + nA.nLen, nB.nNum);
|
||||
}
|
||||
|
||||
bool operator<( const BigInt& rVal1, const BigInt& rVal2 )
|
||||
std::strong_ordering operator<=>(const BigInt& rVal1, const BigInt& rVal2)
|
||||
{
|
||||
if (rVal1.nLen == 0 && rVal2.nLen == 0)
|
||||
return rVal1.nVal < rVal2.nVal;
|
||||
if (rVal1.IsLong() && rVal2.IsLong())
|
||||
return rVal1.nVal <=> rVal2.nVal;
|
||||
|
||||
BigInt nA, nB;
|
||||
nA.MakeBigInt(rVal1);
|
||||
nB.MakeBigInt(rVal2);
|
||||
BigInt nA = rVal1.MakeBig(), nB = rVal2.MakeBig();
|
||||
if (nA.bIsNeg != nB.bIsNeg)
|
||||
return !nB.bIsNeg;
|
||||
if (nA.nLen != nB.nLen)
|
||||
return nA.bIsNeg ? (nA.nLen > nB.nLen) : (nA.nLen < nB.nLen);
|
||||
return nB.bIsNeg ? std::strong_ordering::less : std::strong_ordering::greater;
|
||||
if (nA.nLen < nB.nLen)
|
||||
return nB.bIsNeg ? std::strong_ordering::greater : std::strong_ordering::less;
|
||||
if (nA.nLen > nB.nLen)
|
||||
return nB.bIsNeg ? std::strong_ordering::less : std::strong_ordering::greater;
|
||||
int i = nA.nLen - 1;
|
||||
while (i > 0 && nA.nNum[i] == nB.nNum[i])
|
||||
--i;
|
||||
return nA.bIsNeg ? (nA.nNum[i] > nB.nNum[i]) : (nA.nNum[i] < nB.nNum[i]);
|
||||
return nB.bIsNeg ? (nB.nNum[i] <=> nA.nNum[i]) : (nA.nNum[i] <=> nB.nNum[i]);
|
||||
}
|
||||
|
||||
tools::Long BigInt::Scale( tools::Long nVal, tools::Long nMul, tools::Long nDiv )
|
||||
|
||||
Reference in New Issue
Block a user