summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Kaganski <mike.kaganski@collabora.com>2023-12-20 12:17:31 +0300
committerMike Kaganski <mike.kaganski@collabora.com>2023-12-20 20:30:01 +0100
commit36df3f9ad2f71c122af3cf9fbc58c661f416658e (patch)
tree076d19ec3feb7bb82bb63e8435e1ea76e26e4a9c
parentc684aa9cf33fdbae5bf5f05d2c391f27a140b56d (diff)
Make BigInt::DivMod public, to allow optimized division
Change-Id: I4f79c30b9ab997d01e59a0dec76986e74abfc11f Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161053 Tested-by: Jenkins Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
-rw-r--r--include/tools/bigint.hxx5
-rw-r--r--tools/source/generic/bigint.cxx95
-rw-r--r--vcl/source/control/longcurr.cxx11
3 files changed, 74 insertions, 37 deletions
diff --git a/include/tools/bigint.hxx b/include/tools/bigint.hxx
index 1b089e173ef0..644bb4c3e29d 100644
--- a/include/tools/bigint.hxx
+++ b/include/tools/bigint.hxx
@@ -46,8 +46,7 @@ private:
TOOLS_DLLPRIVATE void AddBig(BigInt& rB, BigInt& rRes);
TOOLS_DLLPRIVATE void SubBig(BigInt& rB, BigInt& rRes);
TOOLS_DLLPRIVATE void MultBig(BigInt const& rB, BigInt& rRes) const;
- TOOLS_DLLPRIVATE void DivModBig(BigInt const& rB, BigInt& rRes, bool bMod) const;
- TOOLS_DLLPRIVATE void DivMod(BigInt const& rVal, bool bMod);
+ TOOLS_DLLPRIVATE void DivModBig(BigInt const& rB, BigInt* pDiv, BigInt* pMod) const;
public:
BigInt()
@@ -113,6 +112,8 @@ public:
BigInt& operator =( sal_Int32 nValue );
+ void DivMod(BigInt const& rVal, BigInt* pDiv, BigInt* pMod) const;
+
/* Scale and round value */
static tools::Long Scale(tools::Long nVal, tools::Long nMult, tools::Long nDiv);
diff --git a/tools/source/generic/bigint.cxx b/tools/source/generic/bigint.cxx
index 3f4a82ffe33e..240494dfc15d 100644
--- a/tools/source/generic/bigint.cxx
+++ b/tools/source/generic/bigint.cxx
@@ -276,7 +276,7 @@ void BigInt::MultBig(const BigInt& rB, BigInt& rRes) const
}
}
-void BigInt::DivModBig(const BigInt& rB, BigInt& rRes, bool bMod) const
+void BigInt::DivModBig(const BigInt& rB, BigInt* pDiv, BigInt* pMod) const
{
assert(IsBig() && rB.IsBig());
assert(nLen >= rB.nLen);
@@ -299,6 +299,9 @@ void BigInt::DivModBig(const BigInt& rB, BigInt& rRes, bool bMod) const
assert(nDenMostSig >= 0x100000000 / 2);
const sal_uInt64 nDen2ndSig = rB.nLen > 1 ? den[rB.nLen - 2] : 0;
+ BigInt aTmp;
+ BigInt& rRes = pDiv ? *pDiv : aTmp;
+
for (size_t j = num.size() - 1; j >= den.size(); j--)
{ // guess divisor
assert(num[j] < nDenMostSig || (num[j] == nDenMostSig && num[j - 1] == 0));
@@ -344,17 +347,19 @@ void BigInt::DivModBig(const BigInt& rB, BigInt& rRes, bool bMod) const
}
}
- if (bMod)
+ if (pMod)
{
- rRes.nLen = DivInPlace(num, nMult, nMult);
- assert(rRes.nLen <= MAX_DIGITS);
- rRes.bIsNeg = bIsNeg;
- std::copy_n(num.begin(), rRes.nLen, rRes.nNum);
+ pMod->nLen = DivInPlace(num, nMult, nMult);
+ assert(pMod->nLen <= MAX_DIGITS);
+ pMod->bIsNeg = bIsNeg;
+ std::copy_n(num.begin(), pMod->nLen, pMod->nNum);
+ pMod->Normalize();
}
- else
+ if (pDiv) // rRes references pDiv
{
- rRes.bIsNeg = bIsNeg != rB.bIsNeg;
- rRes.nLen = nLen - rB.nLen + 1;
+ pDiv->bIsNeg = bIsNeg != rB.bIsNeg;
+ pDiv->nLen = nLen - rB.nLen + 1;
+ pDiv->Normalize();
}
}
@@ -566,8 +571,9 @@ BigInt& BigInt::operator*=( const BigInt& rVal )
return *this;
}
-void BigInt::DivMod(const BigInt& rVal, bool bMod)
+void BigInt::DivMod(const BigInt& rVal, BigInt* pDiv, BigInt* pMod) const
{
+ assert(pDiv || pMod); // Avoid useless calls
if (!rVal.IsBig())
{
if ( rVal.nVal == 0 )
@@ -578,66 +584,99 @@ void BigInt::DivMod(const BigInt& rVal, bool bMod)
if (rVal.nVal == 1)
{
- if (bMod)
- *this = 0;
+ if (pDiv)
+ {
+ *pDiv = *this;
+ pDiv->Normalize();
+ }
+ if (pMod)
+ *pMod = 0;
return;
}
if (!IsBig())
{
// No overflows may occur here
- nVal = bMod ? nVal % rVal.nVal : nVal / rVal.nVal;
+ const sal_Int32 nDiv = nVal / rVal.nVal; // Compilers usually optimize adjacent
+ const sal_Int32 nMod = nVal % rVal.nVal; // / and % into a single instruction
+ if (pDiv)
+ *pDiv = nDiv;
+ if (pMod)
+ *pMod = nMod;
return;
}
if ( rVal.nVal == -1 )
{
- if (bMod)
- *this = 0;
- else
- bIsNeg = !bIsNeg;
+ if (pDiv)
+ {
+ *pDiv = *this;
+ pDiv->bIsNeg = !bIsNeg;
+ pDiv->Normalize();
+ }
+ if (pMod)
+ *pMod = 0;
return;
}
// Divide BigInt with an sal_uInt32
sal_uInt32 nTmp;
+ bool bNegate;
if ( rVal.nVal < 0 )
{
nTmp = static_cast<sal_uInt32>(-rVal.nVal);
- bIsNeg = !bIsNeg;
+ bNegate = true;
}
else
+ {
nTmp = static_cast<sal_uInt32>(rVal.nVal);
+ bNegate = false;
+ }
- nLen = DivInPlace({ nNum, nLen }, nTmp, nTmp);
- if (bMod)
- *this = BigInt(nTmp);
+ BigInt aTmp;
+ BigInt& rDiv = pDiv ? *pDiv : aTmp;
+ rDiv = *this;
+ rDiv.nLen = DivInPlace({ rDiv.nNum, rDiv.nLen }, nTmp, nTmp);
+ if (pDiv)
+ {
+ if (bNegate)
+ pDiv->bIsNeg = !pDiv->bIsNeg;
+ pDiv->Normalize();
+ }
+ if (pMod)
+ {
+ *pMod = BigInt(nTmp);
+ }
return;
}
BigInt tmpA = MakeBig(), tmpB = rVal.MakeBig();
if (tmpA.ABS_IsLessBig(tmpB))
{
- if (!bMod)
- *this = 0;
+ // First store *this to *pMod, then nullify *pDiv, to handle 'pDiv == this' case
+ if (pMod)
+ {
+ *pMod = *this;
+ pMod->Normalize();
+ }
+ if (pDiv)
+ *pDiv = 0;
return;
}
// Divide BigInt with BigInt
- tmpA.DivModBig(tmpB, *this, bMod);
+ tmpA.DivModBig(tmpB, pDiv, pMod);
}
BigInt& BigInt::operator/=( const BigInt& rVal )
{
- DivMod(rVal, false);
- Normalize();
+ DivMod(rVal, this, nullptr);
return *this;
}
BigInt& BigInt::operator%=( const BigInt& rVal )
{
- DivMod(rVal, true);
- Normalize();
+ DivMod(rVal, nullptr, this);
return *this;
}
diff --git a/vcl/source/control/longcurr.cxx b/vcl/source/control/longcurr.cxx
index ee9451d79655..587c99cf1724 100644
--- a/vcl/source/control/longcurr.cxx
+++ b/vcl/source/control/longcurr.cxx
@@ -56,10 +56,9 @@ OUString ImplGetCurr( const LocaleDataWrapper& rLocaleDataWrapper, const BigInt
return rLocaleDataWrapper.getCurr( static_cast<tools::Long>(rNumber), nDigits, rCurrSymbol, bShowThousandSep );
BigInt aTmp( ImplPower10( nDigits ) );
- BigInt aInteger(rNumber.Abs());
- BigInt aFraction(aInteger);
- aInteger /= aTmp;
- aFraction %= aTmp;
+ BigInt aInteger;
+ BigInt aFraction;
+ rNumber.Abs().DivMod(aTmp, &aInteger, &aFraction);
if ( !aInteger.IsZero() )
{
aFraction += aTmp;
@@ -71,9 +70,7 @@ OUString ImplGetCurr( const LocaleDataWrapper& rLocaleDataWrapper, const BigInt
OUStringBuffer aTemplate(rLocaleDataWrapper.getCurr( static_cast<tools::Long>(aFraction), nDigits, rCurrSymbol, bShowThousandSep ));
while( !aInteger.IsZero() )
{
- aFraction = aInteger;
- aFraction %= aTmp;
- aInteger /= aTmp;
+ aInteger.DivMod(aTmp, &aInteger, &aFraction);
if( !aInteger.IsZero() )
aFraction += aTmp;