summaryrefslogtreecommitdiffstats
path: root/tools/source/generic/bigint.cxx
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /tools/source/generic/bigint.cxx
parentInitial commit. (diff)
downloadlibreoffice-upstream/4%7.4.7.tar.xz
libreoffice-upstream/4%7.4.7.zip
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'tools/source/generic/bigint.cxx')
-rw-r--r--tools/source/generic/bigint.cxx852
1 files changed, 852 insertions, 0 deletions
diff --git a/tools/source/generic/bigint.cxx b/tools/source/generic/bigint.cxx
new file mode 100644
index 000000000..51810cab1
--- /dev/null
+++ b/tools/source/generic/bigint.cxx
@@ -0,0 +1,852 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <math.h>
+
+#include <osl/diagnose.h>
+#include <tools/bigint.hxx>
+
+#include <algorithm>
+#include <string.h>
+
+/**
+ * The range in which we can perform add/sub without fear of overflow
+ */
+const sal_Int32 MY_MAXLONG = 0x3fffffff;
+const sal_Int32 MY_MINLONG = -MY_MAXLONG;
+
+/*
+ * The algorithms for Addition, Subtraction, Multiplication and Division
+ * of large numbers originate from SEMINUMERICAL ALGORITHMS by
+ * DONALD E. KNUTH in the series The Art of Computer Programming:
+ * chapter 4.3.1. The Classical Algorithms.
+ */
+
+// TODO: Needs conversion to sal_uInt16/INT16/sal_uInt32/sal_Int32
+void BigInt::MakeBigInt( const BigInt& rVal )
+{
+ if ( rVal.nLen != 0 )
+ {
+ memcpy( static_cast<void*>(this), static_cast<const void*>(&rVal), sizeof( BigInt ) );
+ while ( nLen > 1 && nNum[nLen-1] == 0 )
+ nLen--;
+ }
+ 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;
+ }
+}
+
+void BigInt::Normalize()
+{
+ if ( nLen != 0 )
+ {
+ while ( nLen > 1 && nNum[nLen-1] == 0 )
+ nLen--;
+
+ if ( nLen < 3 )
+ {
+ 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;
+ }
+ // 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 )
+{
+ sal_uInt16 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);
+ }
+
+ if ( nK )
+ {
+ nNum[rVal.nLen] = nK;
+ nLen = rVal.nLen + 1;
+ }
+ else
+ nLen = rVal.nLen;
+
+ bIsNeg = rVal.bIsNeg;
+}
+
+void BigInt::Div( sal_uInt16 nDiv, sal_uInt16& rRem )
+{
+ sal_uInt32 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);
+ nK = nTmp % nDiv;
+ }
+ rRem = static_cast<sal_uInt16>(nK);
+
+ if ( nNum[nLen-1] == 0 )
+ nLen -= 1;
+}
+
+bool BigInt::IsLess( const BigInt& rVal ) const
+{
+ if ( rVal.nLen < nLen)
+ return true;
+ if ( rVal.nLen > nLen )
+ return false;
+
+ int i;
+ for ( i = nLen - 1; i > 0 && nNum[i] == rVal.nNum[i]; i-- )
+ {
+ }
+ return rVal.nNum[i] < nNum[i];
+}
+
+void BigInt::AddLong( BigInt& rB, BigInt& rErg )
+{
+ if ( bIsNeg == rB.bIsNeg )
+ {
+ int i;
+ char len;
+
+ // if length of the two values differ, fill remaining positions
+ // of the smaller value with zeros.
+ if (nLen >= rB.nLen)
+ {
+ len = nLen;
+ for (i = rB.nLen; i < len; i++)
+ rB.nNum[i] = 0;
+ }
+ else
+ {
+ len = rB.nLen;
+ for (i = nLen; i < len; i++)
+ nNum[i] = 0;
+ }
+
+ // 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)
+ k = 1;
+ else
+ k = 0;
+ rErg.nNum[i] = static_cast<sal_uInt16>(nZ & 0xffffL);
+ }
+ // If an overflow occurred, add to solution
+ if (nZ & 0xff0000L) // or if(k)
+ {
+ rErg.nNum[i] = 1;
+ len++;
+ }
+ // Set length and sign
+ rErg.nLen = len;
+ rErg.bIsNeg = bIsNeg && rB.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;
+ }
+}
+
+void BigInt::SubLong( BigInt& rB, BigInt& rErg )
+{
+ 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.
+ if (nLen >= rB.nLen)
+ {
+ len = nLen;
+ for (i = rB.nLen; i < len; i++)
+ rB.nNum[i] = 0;
+ }
+ else
+ {
+ len = rB.nLen;
+ for (i = nLen; i < len; i++)
+ nNum[i] = 0;
+ }
+
+ if ( IsLess(rB) )
+ {
+ 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;
+ }
+ 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;
+ AddLong(rB, rErg);
+ rB.bIsNeg = true;
+ rErg.bIsNeg = false;
+ }
+}
+
+void BigInt::MultLong( const BigInt& rB, BigInt& rErg ) const
+{
+ int i, j;
+ sal_uInt32 nZ, k;
+
+ rErg.bIsNeg = bIsNeg != rB.bIsNeg;
+ rErg.nLen = nLen + rB.nLen;
+
+ for (i = 0; i < rErg.nLen; i++)
+ rErg.nNum[i] = 0;
+
+ for (j = 0; j < rB.nLen; j++)
+ {
+ for (i = 0, k = 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;
+ }
+ rErg.nNum[i + j] = static_cast<sal_uInt16>(k);
+ }
+}
+
+void BigInt::DivLong( const BigInt& rB, BigInt& rErg ) const
+{
+ int i, j;
+ sal_uInt16 nK, nQ, nMult;
+ sal_uInt16 nLenB = rB.nLen;
+ sal_uInt16 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 )
+ {
+ aTmpA.nNum[aTmpA.nLen] = 0;
+ aTmpA.nLen++;
+ }
+
+ 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 - static_cast<sal_uInt32>(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 -= 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.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 )
+ {
+ aTmpA.nNum[aTmpA.nLen] = 0;
+ aTmpA.nLen++;
+ }
+
+ 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;
+ }
+ if ( nVal < 0 )
+ if ( rB.nVal < 0 )
+ return nVal > rB.nVal;
+ else
+ return nVal > -rB.nVal;
+ else
+ if ( rB.nVal < 0 )
+ return nVal < -rB.nVal;
+ else
+ return nVal < rB.nVal;
+}
+
+BigInt::BigInt( const BigInt& rBigInt )
+ : nLen(0)
+ , bIsNeg(false)
+{
+ if ( rBigInt.nLen != 0 )
+ memcpy( static_cast<void*>(this), static_cast<const void*>(&rBigInt), sizeof( BigInt ) );
+ else
+ nVal = rBigInt.nVal;
+}
+
+BigInt::BigInt( std::u16string_view rString )
+ : nLen(0)
+{
+ bIsNeg = false;
+ nVal = 0;
+
+ bool bNeg = false;
+ auto p = rString.begin();
+ auto pEnd = rString.end();
+ if (p == pEnd)
+ return;
+ if ( *p == '-' )
+ {
+ bNeg = true;
+ p++;
+ }
+ if (p == pEnd)
+ return;
+ while( p != pEnd && *p >= '0' && *p <= '9' )
+ {
+ *this *= 10;
+ *this += *p - '0';
+ p++;
+ }
+ if ( nLen != 0 )
+ bIsNeg = bNeg;
+ else if( bNeg )
+ nVal = -nVal;
+}
+
+BigInt::BigInt( double nValue )
+ : nVal(0)
+{
+ if ( nValue < 0 )
+ {
+ nValue *= -1;
+ bIsNeg = true;
+ }
+ else
+ {
+ bIsNeg = false;
+ }
+
+ if ( nValue < 1 )
+ {
+ nVal = 0;
+ nLen = 0;
+ }
+ else
+ {
+ int i=0;
+
+ while ( ( nValue > 65536.0 ) && ( i < MAX_DIGITS ) )
+ {
+ nNum[i] = static_cast<sal_uInt16>(fmod( nValue, 65536.0 ));
+ nValue -= nNum[i];
+ nValue /= 65536.0;
+ i++;
+ }
+ if ( i < MAX_DIGITS )
+ nNum[i++] = static_cast<sal_uInt16>(nValue);
+
+ nLen = i;
+
+ if ( i < 3 )
+ Normalize();
+ }
+}
+
+BigInt::BigInt( sal_uInt32 nValue )
+ : nVal(0)
+{
+ if ( nValue & 0x80000000U )
+ {
+ bIsNeg = false;
+ nNum[0] = static_cast<sal_uInt16>(nValue & 0xffffU);
+ nNum[1] = static_cast<sal_uInt16>(nValue >> 16);
+ nLen = 2;
+ }
+ else
+ {
+ bIsNeg = false;
+ nVal = nValue;
+ nLen = 0;
+ }
+}
+
+BigInt::BigInt( sal_Int64 nValue )
+ : nVal(0)
+{
+ bIsNeg = nValue < 0;
+ nLen = 0;
+
+ if ((nValue >= SAL_MIN_INT32) && (nValue <= SAL_MAX_INT32))
+ {
+ nVal = static_cast<sal_Int32>(nValue);
+ }
+ else
+ {
+ sal_uInt64 nUValue = static_cast<sal_uInt64>(bIsNeg ? -nValue : nValue);
+ for (int i = 0; (i != sizeof(sal_uInt64) / 2) && (nUValue != 0); ++i)
+ {
+ nNum[i] = static_cast<sal_uInt16>(nUValue & 0xffffUL);
+ nUValue = nUValue >> 16;
+ ++nLen;
+ }
+ }
+}
+
+BigInt::operator double() const
+{
+ if ( nLen == 0 )
+ return static_cast<double>(nVal);
+ else
+ {
+ int i = nLen-1;
+ double nRet = static_cast<double>(static_cast<sal_uInt32>(nNum[i]));
+
+ while ( i )
+ {
+ nRet *= 65536.0;
+ i--;
+ nRet += static_cast<double>(static_cast<sal_uInt32>(nNum[i]));
+ }
+
+ if ( bIsNeg )
+ nRet *= -1;
+
+ return nRet;
+ }
+}
+
+BigInt& BigInt::operator=( const BigInt& rBigInt )
+{
+ if (this == &rBigInt)
+ return *this;
+
+ if ( rBigInt.nLen != 0 )
+ memcpy( static_cast<void*>(this), static_cast<const void*>(&rBigInt), sizeof( BigInt ) );
+ else
+ {
+ nLen = 0;
+ nVal = rBigInt.nVal;
+ }
+ return *this;
+}
+
+BigInt& BigInt::operator+=( const BigInt& rVal )
+{
+ if ( nLen == 0 && rVal.nLen == 0 )
+ {
+ if( nVal <= MY_MAXLONG && rVal.nVal <= MY_MAXLONG
+ && nVal >= MY_MINLONG && rVal.nVal >= MY_MINLONG )
+ { // No overflows may occur here
+ nVal += rVal.nVal;
+ return *this;
+ }
+
+ if( (nVal < 0) != (rVal.nVal < 0) )
+ { // No overflows may occur here
+ nVal += rVal.nVal;
+ return *this;
+ }
+ }
+
+ BigInt aTmp1, aTmp2;
+ aTmp1.MakeBigInt( *this );
+ aTmp2.MakeBigInt( rVal );
+ aTmp1.AddLong( aTmp2, *this );
+ Normalize();
+ return *this;
+}
+
+BigInt& BigInt::operator-=( const BigInt& rVal )
+{
+ if ( nLen == 0 && rVal.nLen == 0 )
+ {
+ if ( nVal <= MY_MAXLONG && rVal.nVal <= MY_MAXLONG &&
+ nVal >= MY_MINLONG && rVal.nVal >= MY_MINLONG )
+ { // No overflows may occur here
+ nVal -= rVal.nVal;
+ return *this;
+ }
+
+ if ( (nVal < 0) == (rVal.nVal < 0) )
+ { // No overflows may occur here
+ nVal -= rVal.nVal;
+ return *this;
+ }
+ }
+
+ BigInt aTmp1, aTmp2;
+ aTmp1.MakeBigInt( *this );
+ aTmp2.MakeBigInt( rVal );
+ aTmp1.SubLong( aTmp2, *this );
+ Normalize();
+ return *this;
+}
+
+BigInt& BigInt::operator*=( const BigInt& rVal )
+{
+ static const sal_Int32 MY_MAXSHORT = 0x00007fff;
+ static const sal_Int32 MY_MINSHORT = -MY_MAXSHORT;
+
+ if ( nLen == 0 && rVal.nLen == 0
+ && nVal <= MY_MAXSHORT && rVal.nVal <= MY_MAXSHORT
+ && nVal >= MY_MINSHORT && rVal.nVal >= MY_MINSHORT )
+ // TODO: not optimal !!! W.P.
+ { // No overflows may occur here
+ nVal *= rVal.nVal;
+ }
+ else
+ {
+ BigInt aTmp1, aTmp2;
+ aTmp1.MakeBigInt( rVal );
+ aTmp2.MakeBigInt( *this );
+ aTmp1.MultLong(aTmp2, *this);
+ Normalize();
+ }
+ return *this;
+}
+
+BigInt& BigInt::operator/=( const BigInt& rVal )
+{
+ if ( rVal.nLen == 0 )
+ {
+ if ( rVal.nVal == 0 )
+ {
+ OSL_FAIL( "BigInt::operator/ --> divide by zero" );
+ return *this;
+ }
+
+ if ( nLen == 0 )
+ {
+ // No overflows may occur here
+ nVal /= rVal.nVal;
+ return *this;
+ }
+
+ if ( rVal.nVal == 1 )
+ return *this;
+
+ if ( rVal.nVal == -1 )
+ {
+ bIsNeg = !bIsNeg;
+ return *this;
+ }
+
+ if ( rVal.nVal <= 0xFFFF && rVal.nVal >= -0xFFFF )
+ {
+ // 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;
+ }
+ }
+
+ if ( ABS_IsLess( rVal ) )
+ {
+ *this = BigInt( 0 );
+ return *this;
+ }
+
+ // Divide BigInt with BigInt
+ BigInt aTmp1, aTmp2;
+ aTmp1.MakeBigInt( *this );
+ aTmp2.MakeBigInt( rVal );
+ aTmp1.DivLong(aTmp2, *this);
+ Normalize();
+ return *this;
+}
+
+BigInt& BigInt::operator%=( const BigInt& rVal )
+{
+ if ( rVal.nLen == 0 )
+ {
+ if ( rVal.nVal == 0 )
+ {
+ OSL_FAIL( "BigInt::operator/ --> divide by zero" );
+ return *this;
+ }
+
+ if ( nLen == 0 )
+ {
+ // No overflows may occur here
+ nVal %= rVal.nVal;
+ return *this;
+ }
+
+ if ( rVal.nVal <= 0xFFFF && rVal.nVal >= -0xFFFF )
+ {
+ // 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;
+ }
+ }
+
+ if ( ABS_IsLess( rVal ) )
+ return *this;
+
+ // Divide BigInt with BigInt
+ BigInt aTmp1, aTmp2;
+ aTmp1.MakeBigInt( *this );
+ aTmp2.MakeBigInt( rVal );
+ aTmp1.ModLong(aTmp2, *this);
+ Normalize();
+ return *this;
+}
+
+bool operator==( const BigInt& rVal1, const BigInt& rVal2 )
+{
+ if (rVal1.nLen == 0 && rVal2.nLen == 0)
+ return rVal1.nVal == rVal2.nVal;
+
+ BigInt nA, nB;
+ nA.MakeBigInt(rVal1);
+ nB.MakeBigInt(rVal2);
+ 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 )
+{
+ if (rVal1.nLen == 0 && rVal2.nLen == 0)
+ return rVal1.nVal < rVal2.nVal;
+
+ BigInt nA, nB;
+ nA.MakeBigInt(rVal1);
+ nB.MakeBigInt(rVal2);
+ if (nA.bIsNeg != nB.bIsNeg)
+ return !nB.bIsNeg;
+ if (nA.nLen != nB.nLen)
+ return nA.bIsNeg ? (nA.nLen > nB.nLen) : (nA.nLen < nB.nLen);
+ 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]);
+}
+
+tools::Long BigInt::Scale( tools::Long nVal, tools::Long nMul, tools::Long nDiv )
+{
+ BigInt aVal( nVal );
+
+ aVal *= nMul;
+
+ if ( aVal.IsNeg() != ( nDiv < 0 ) )
+ aVal -= nDiv / 2; // for correct rounding
+ else
+ aVal += nDiv / 2; // for correct rounding
+
+ aVal /= nDiv;
+
+ return tools::Long( aVal );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */