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:
Mike Kaganski
2023-12-17 22:34:02 +01:00
parent 5e3a367159
commit bcbc0857bf
2 changed files with 238 additions and 389 deletions
+51 -76
View File
@@ -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
View File
@@ -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 )