428 lines
11 KiB
C++
428 lines
11 KiB
C++
/*
|
|
* (c) Copyright Ascensio System SIA 2010-2023
|
|
*
|
|
* This program is a free software product. You can redistribute it and/or
|
|
* modify it under the terms of the GNU Affero General Public License (AGPL)
|
|
* version 3 as published by the Free Software Foundation. In accordance with
|
|
* Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
|
|
* that Ascensio System SIA expressly excludes the warranty of non-infringement
|
|
* of any third-party rights.
|
|
*
|
|
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
|
|
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For
|
|
* details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
|
|
*
|
|
* You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish
|
|
* street, Riga, Latvia, EU, LV-1050.
|
|
*
|
|
* The interactive user interfaces in modified source and object code versions
|
|
* of the Program must display Appropriate Legal Notices, as required under
|
|
* Section 5 of the GNU AGPL version 3.
|
|
*
|
|
* Pursuant to Section 7(b) of the License you must retain the original Product
|
|
* logo when distributing the program. Pursuant to Section 7(e) we decline to
|
|
* grant you any rights under trademark law for use of our trademarks.
|
|
*
|
|
* All the Product's GUI elements, including illustrations and icon sets, as
|
|
* well as technical writing content are licensed under the terms of the
|
|
* Creative Commons Attribution-ShareAlike 4.0 International. See the License
|
|
* terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
|
*
|
|
*/
|
|
#ifndef _BUILD_BIGINTEGER_CROSSPLATFORM_H_
|
|
#define _BUILD_BIGINTEGER_CROSSPLATFORM_H_
|
|
|
|
#include <string>
|
|
|
|
class CBigInteger
|
|
{
|
|
protected:
|
|
std::string m_value;
|
|
bool m_isNegative;
|
|
|
|
public:
|
|
|
|
CBigInteger()
|
|
{
|
|
m_value = "0";
|
|
m_isNegative = false;
|
|
}
|
|
|
|
CBigInteger(unsigned char* data, int size)
|
|
{
|
|
m_isNegative = false;
|
|
m_value = "0";
|
|
|
|
for (int i = 0; i < size; i++)
|
|
{
|
|
CBigInteger tmp((int)data[i]);
|
|
|
|
for (int j = size - 1 - i; j > 0; --j)
|
|
tmp *= 256;
|
|
|
|
*this += tmp;
|
|
}
|
|
}
|
|
|
|
CBigInteger(std::string data, int nBase = 10)
|
|
{
|
|
m_isNegative = false;
|
|
|
|
if (10 == nBase)
|
|
{
|
|
m_value = data;
|
|
}
|
|
else
|
|
{
|
|
m_value = "0";
|
|
int len = (int)data.length();
|
|
for (int i = 0; i < len; i++)
|
|
{
|
|
int val = 0;
|
|
char _c = data[i];
|
|
if (_c >= '0' && _c <= '9')
|
|
val = _c - '0';
|
|
else if (_c >= 'A' && _c <= 'F')
|
|
val = 10 + _c - 'A';
|
|
else if (_c >= 'a' && _c <= 'f')
|
|
val = 10 + _c - 'a';
|
|
|
|
CBigInteger tmp(val);
|
|
for (int j = len - 1 - i; j > 0; --j)
|
|
tmp *= nBase;
|
|
|
|
*this += tmp;
|
|
}
|
|
}
|
|
}
|
|
|
|
CBigInteger(int value)
|
|
{
|
|
if (value < 0)
|
|
{
|
|
m_isNegative = true;
|
|
m_value = std::to_string(-value);
|
|
}
|
|
else
|
|
{
|
|
m_isNegative = false;
|
|
m_value = std::to_string(value);
|
|
}
|
|
}
|
|
|
|
std::string GetValue()
|
|
{
|
|
return m_value;
|
|
}
|
|
bool IsNegative()
|
|
{
|
|
return m_isNegative;
|
|
}
|
|
|
|
void operator = (CBigInteger b)
|
|
{
|
|
m_value = b.m_value;
|
|
m_isNegative = b.m_isNegative;
|
|
}
|
|
|
|
bool operator == (CBigInteger b)
|
|
{
|
|
return equals((*this) , b);
|
|
}
|
|
|
|
bool operator != (CBigInteger b)
|
|
{
|
|
return !equals((*this) , b);
|
|
}
|
|
|
|
bool operator > (CBigInteger b)
|
|
{
|
|
return greater((*this) , b);
|
|
}
|
|
|
|
bool operator < (CBigInteger b)
|
|
{
|
|
return less((*this) , b);
|
|
}
|
|
|
|
bool operator >= (CBigInteger b)
|
|
{
|
|
return equals((*this) , b) || greater((*this), b);
|
|
}
|
|
|
|
bool operator <= (CBigInteger b)
|
|
{
|
|
return equals((*this) , b) || less((*this) , b);
|
|
}
|
|
|
|
CBigInteger absolute()
|
|
{
|
|
return CBigInteger(m_value); // +ve by default
|
|
}
|
|
|
|
CBigInteger& operator ++()
|
|
{
|
|
// prefix
|
|
(*this) = (*this) + 1;
|
|
return (*this);
|
|
}
|
|
|
|
CBigInteger operator ++(int)
|
|
{
|
|
// postfix
|
|
CBigInteger before = (*this);
|
|
(*this) = (*this) + 1;
|
|
return before;
|
|
}
|
|
|
|
CBigInteger& operator --()
|
|
{
|
|
// prefix
|
|
(*this) = (*this) - 1;
|
|
return (*this);
|
|
}
|
|
|
|
CBigInteger operator --(int)
|
|
{
|
|
// postfix
|
|
CBigInteger before = (*this);
|
|
(*this) = (*this) - 1;
|
|
return before;
|
|
}
|
|
|
|
CBigInteger operator + (CBigInteger b)
|
|
{
|
|
CBigInteger addition;
|
|
if (m_isNegative == b.m_isNegative)
|
|
{
|
|
// both +ve or -ve
|
|
addition.m_value = (add(m_value, b.m_value));
|
|
addition.m_isNegative = m_isNegative;
|
|
}
|
|
else
|
|
{
|
|
// sign different
|
|
if (absolute() > b.absolute())
|
|
{
|
|
addition.m_value = subtract(m_value, b.m_value);
|
|
addition.m_isNegative = m_isNegative;
|
|
}
|
|
else
|
|
{
|
|
addition.m_value = subtract(b.m_value, m_value);
|
|
addition.m_isNegative = b.m_isNegative;
|
|
}
|
|
}
|
|
|
|
if (addition.m_value == "0") // avoid (-0) problem
|
|
addition.m_isNegative = false;
|
|
|
|
return addition;
|
|
}
|
|
|
|
CBigInteger operator - (CBigInteger b)
|
|
{
|
|
b.m_isNegative = !b.m_isNegative; // x - y = x + (-y)
|
|
return (*this) + b;
|
|
}
|
|
|
|
CBigInteger operator * (CBigInteger b)
|
|
{
|
|
CBigInteger mul;
|
|
|
|
mul.m_value = multiply(m_value, b.m_value);
|
|
mul.m_isNegative = (m_isNegative != b.m_isNegative);
|
|
|
|
if (mul.m_value == "0") // avoid (-0) problem
|
|
mul.m_isNegative = false;
|
|
|
|
return mul;
|
|
}
|
|
|
|
CBigInteger& operator += (CBigInteger b)
|
|
{
|
|
(*this) = (*this) + b;
|
|
return (*this);
|
|
}
|
|
|
|
CBigInteger& operator -= (CBigInteger b)
|
|
{
|
|
(*this) = (*this) - b;
|
|
return (*this);
|
|
}
|
|
|
|
CBigInteger& operator *= (CBigInteger b)
|
|
{
|
|
(*this) = (*this) * b;
|
|
return (*this);
|
|
}
|
|
|
|
CBigInteger operator -() { // unary minus sign
|
|
return (*this) * -1;
|
|
}
|
|
|
|
std::string ToString()
|
|
{
|
|
// for conversion from BigInteger to string
|
|
std::string signedString = ( m_isNegative ) ? "-" : ""; // if +ve, don't print + sign
|
|
signedString += m_value;
|
|
return signedString;
|
|
}
|
|
|
|
private:
|
|
bool equals(CBigInteger n1, CBigInteger n2)
|
|
{
|
|
return ((n1.m_value == n2.m_value) && (n1.m_isNegative == n2.m_isNegative));
|
|
}
|
|
|
|
bool less(CBigInteger n1, CBigInteger n2)
|
|
{
|
|
bool sign1 = n1.m_isNegative;
|
|
bool sign2 = n2.m_isNegative;
|
|
|
|
if (sign1 && !sign2)
|
|
return true;
|
|
else if (!sign1 && sign2)
|
|
return false;
|
|
else if (!sign1)
|
|
{
|
|
std::string::size_type _size1 = n1.m_value.length();
|
|
std::string::size_type _size2 = n2.m_value.length();
|
|
if (_size1 < _size2)
|
|
return true;
|
|
if (_size1 > _size2)
|
|
return false;
|
|
return n1.m_value < n2.m_value;
|
|
}
|
|
else
|
|
{
|
|
std::string::size_type _size1 = n1.m_value.length();
|
|
std::string::size_type _size2 = n2.m_value.length();
|
|
|
|
if (_size1 > _size2)
|
|
return true;
|
|
if (_size1 < _size2)
|
|
return false;
|
|
return n1.m_value.compare(n2.m_value) > 0;
|
|
}
|
|
}
|
|
|
|
bool greater(CBigInteger n1, CBigInteger n2)
|
|
{
|
|
return !equals(n1, n2) && !less(n1, n2);
|
|
}
|
|
|
|
std::string add(std::string number1, std::string number2)
|
|
{
|
|
std::string add = (number1.length() > number2.length()) ? number1 : number2;
|
|
char carry = '0';
|
|
int differenceInLength = (int)(number1.size() - number2.size());
|
|
|
|
if (differenceInLength > 0)
|
|
number2.insert(0, differenceInLength, '0');
|
|
else
|
|
number1.insert(0, -differenceInLength, '0');
|
|
|
|
if (differenceInLength < 0)
|
|
differenceInLength = -differenceInLength;
|
|
|
|
for (int i = (int)(number1.size()) - 1; i >= 0; --i)
|
|
{
|
|
add[i] = ((carry-'0')+(number1[i]-'0')+(number2[i]-'0')) + '0';
|
|
|
|
if(i != 0)
|
|
{
|
|
if(add[i] > '9')
|
|
{
|
|
add[i] -= 10;
|
|
carry = '1';
|
|
}
|
|
else
|
|
{
|
|
carry = '0';
|
|
}
|
|
}
|
|
}
|
|
if (add[0] > '9')
|
|
{
|
|
add[0] -= 10;
|
|
add.insert(0, 1, '1');
|
|
}
|
|
return add;
|
|
}
|
|
|
|
std::string subtract(std::string number1, std::string number2)
|
|
{
|
|
std::string sub = (number1.length() > number2.length()) ? number1 : number2;
|
|
int differenceInLength = (int)(number1.size() - number2.size());
|
|
|
|
if (differenceInLength > 0)
|
|
number2.insert(0, differenceInLength, '0');
|
|
else
|
|
number1.insert(0, -differenceInLength, '0');
|
|
|
|
if (differenceInLength < 0)
|
|
differenceInLength = -differenceInLength;
|
|
|
|
for (int i = (int)(number1.length()) - 1; i >= 0; --i)
|
|
{
|
|
if (number1[i] < number2[i])
|
|
{
|
|
number1[i] += 10;
|
|
number1[i-1]--;
|
|
}
|
|
sub[i] = ((number1[i]-'0')-(number2[i]-'0')) + '0';
|
|
}
|
|
|
|
while (sub[0]=='0' && sub.length() != 1) // erase leading zeros
|
|
sub.erase(0, 1);
|
|
|
|
return sub;
|
|
}
|
|
|
|
std::string multiply(std::string n1, std::string n2)
|
|
{
|
|
if (n1.length() > n2.length())
|
|
n1.swap(n2);
|
|
|
|
std::string res = "0";
|
|
for (int i = (int)(n1.length()) - 1; i >= 0; --i)
|
|
{
|
|
std::string temp = n2;
|
|
int currentDigit = n1[i] - '0';
|
|
int carry = 0;
|
|
|
|
for (int j = (int)(temp.length()) - 1; j >= 0; --j)
|
|
{
|
|
temp[j] = ((temp[j]-'0') * currentDigit) + carry;
|
|
|
|
if (temp[j] > 9)
|
|
{
|
|
carry = (temp[j] / 10);
|
|
temp[j] -= (carry * 10);
|
|
}
|
|
else
|
|
{
|
|
carry = 0;
|
|
}
|
|
|
|
temp[j] += '0'; // back to string mood
|
|
}
|
|
|
|
if (carry > 0)
|
|
temp.insert(0, 1, (char)(carry+'0'));
|
|
|
|
temp.append((n1.length() - i - 1), '0'); // as like mult by 10, 100, 1000, 10000 and so on
|
|
|
|
res = add(res, temp); // O(n)
|
|
}
|
|
|
|
while (res[0] == '0' && res.length() != 1) // erase leading zeros
|
|
res.erase(0,1);
|
|
|
|
return res;
|
|
}
|
|
};
|
|
|
|
#endif //_BUILD_BIGINTEGER_CROSSPLATFORM_H_
|