diff options
-rw-r--r-- | include/tools/bigint.hxx | 5 | ||||
-rw-r--r-- | tools/source/generic/bigint.cxx | 95 | ||||
-rw-r--r-- | vcl/source/control/longcurr.cxx | 11 |
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; |