/* -*- 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 .
*/
/** * 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.
*/
// Normalization in DivLong requires that dividend is multiplied by a number, and the resulting // value has 1 more 32-bit "digits". 'ret' provides enough room for that. Use of std::span gives // run-time index checking in debug builds. static std::span<sal_uInt32> Mult(std::span<const sal_uInt32> aNum, sal_uInt32 nMul, std::span<sal_uInt32> retBuf)
{
assert(retBuf.size() >= aNum.size());
sal_uInt64 nK = 0; for (size_t i = 0; i < aNum.size(); i++)
{
sal_uInt64 nTmp = static_cast<sal_uInt64>(aNum[i]) * nMul + nK;
nK = nTmp >> 32;
retBuf[i] = static_cast<sal_uInt32>(nTmp);
}
if ( nK )
{
assert(retBuf.size() > aNum.size());
retBuf[aNum.size()] = nK; return retBuf.subspan(0, aNum.size() + 1);
}
return retBuf.subspan(0, aNum.size());
}
static size_t DivInPlace(std::span<sal_uInt32> aNum, sal_uInt32 nDiv, sal_uInt32& rRem)
{
assert(aNum.size() > 0);
sal_uInt64 nK = 0; for (int i = aNum.size() - 1; i >= 0; i--)
{
sal_uInt64 nTmp = aNum[i] + (nK << 32);
aNum[i] = nTmp / nDiv;
nK = nTmp % nDiv;
}
rRem = nK;
if (aNum[aNum.size() - 1] == 0) return aNum.size() - 1;
int i = nLen - 1; while (i > 0 && nNum[i] == rVal.nNum[i])
--i; return nNum[i] < rVal.nNum[i];
}
void BigInt::AddBig(BigInt& rB, BigInt& rRes)
{
assert(IsBig() && rB.IsBig()); 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_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;
rRes.nNum[i] = static_cast<sal_uInt32>(nZ);
} // If an overflow occurred, add to solution if (k)
{
assert(i < MAX_DIGITS);
rRes.nNum[i] = 1;
len++;
} // Set length and sign
rRes.nLen = len;
rRes.bIsNeg = bIsNeg;
} // If one of the values is negative, perform subtraction instead else
{
bIsNeg = !bIsNeg;
rB.SubBig(*this, rRes);
bIsNeg = !bIsNeg;
}
}
// if length of the two values differ, fill remaining positions // of the smaller value with zeros. if (nLen >= rB.nLen)
{
len = nLen; for (int i = rB.nLen; i < len; i++)
rB.nNum[i] = 0;
} else
{
len = rB.nLen; for (int i = nLen; i < len; i++)
nNum[i] = 0;
}
if (rVal.nVal == 1)
{ if (pDiv)
{
*pDiv = *this;
pDiv->Normalize();
} if (pMod)
*pMod = 0; return;
}
if (!IsBig())
{ // No overflows may occur here 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 (pDiv)
{
*pDiv = *this;
pDiv->bIsNeg = !bIsNeg;
pDiv->Normalize();
} if (pMod)
*pMod = 0; return;
}
BigInt tmpA = MakeBig(), tmpB = rVal.MakeBig(); if (tmpA.ABS_IsLessBig(tmpB))
{ // 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, pDiv, pMod);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.