C++ 大整數類(BigInteger類)實現
C++ BigInteger類實現,儲存任意大小的非負整數
參考
演算法競賽入門經典第二版 5.3 節——大整數類
程式碼(先放程式碼,後續追加註釋與可以為負數的實現)
#include <string>
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
/**
* 儲存任意大小的非負整數
*/
class BigInteger
{
friend ostream& operator << (ostream &out, const BigInteger &num);
friend istream& operator << (istream &in, BigInteger &num);
public:
BigInteger(long long num = 0)
{
*this = num;
}
// 利用表示非負整數的字串構造物件
BigInteger(const string &numStr)
{
*this = numStr;
}
BigInteger& operator = (long long num)
{
m_bits.clear();
do
{
m_bits.push_back(num % BASE);
num /= BASE;
} while (num > 0);
return *this;
}
// 利用表示非負整數的字串賦值給物件
BigInteger& operator = (const string &numStr)
{ m_bits.clear();
int bit, len = (numStr.length() - 1) / WIDTH + 1;
for (int i = 0; i < len; i++)
{
int end = numStr.length() - i * WIDTH;
int start = max(0, end - WIDTH);
sscanf(numStr.substr(start, end - start).c_str(), "%d", &bit);
m_bits.push_back(bit);
}
return *this;
}
// 加法運算
BigInteger operator + (const BigInteger &rhs) const
{
BigInteger result;
result.m_bits.clear();
for (int i = 0, carry = 0; ; i++)
{
if (i >= m_bits.size() && i >= rhs.m_bits.size() && carry == 0)
break;
int num = carry;
if (i < m_bits.size())
num += m_bits[i];
if (i < rhs.m_bits.size())
num += rhs.m_bits[i];
result.m_bits.push_back(num % BASE);
carry = num / BASE;
}
return result;
}
BigInteger& operator += (const BigInteger &rhs)
{
*this = *this + rhs;
return *this;
}
// 減法運算,因為BigInteger只能表示非負整數,所以返回值為減法運算結果的絕對值
BigInteger operator - (const BigInteger &rhs) const
{
// lhs > rhs, 則結果為 lhs - rhs;否則結果為 rhs - lhs
if (*this > rhs)
return sub(*this, rhs);
else
return sub(rhs, *this);
}
BigInteger& operator -= (const BigInteger &rhs)
{
*this = *this - rhs;
return *this;
}
// 乘法運算
BigInteger operator * (const BigInteger &rhs) const
{
BigInteger result;
result.m_bits.clear();
result.m_bits.resize(m_bits.size() + rhs.m_bits.size(), 0);
for (size_t i = 0; i < m_bits.size(); i++)
{
for (size_t j = 0; j < rhs.m_bits.size(); j++)
{
// 由於int的精度限制,兩者的乘積不能溢位,所以BASE的值不要超過10^4
int num = m_bits[i] * rhs.m_bits[j];
result.m_bits[i + j] += num;
}
}
formatBits(result);
removeHighestZero(result);
return result;
}
BigInteger& operator *= (const BigInteger &rhs)
{
*this = *this * rhs;
return *this;
}
// 整除運算
BigInteger operator / (const BigInteger &rhs) const
{
if (rhs == 0)
throw runtime_error("Divisor cannot be 0!");
BigInteger temp = *this;
return divide(temp, rhs);
}
BigInteger& operator /= (const BigInteger &rhs)
{
*this = *this / rhs;
return *this;
}
// 求餘運算
BigInteger operator % (const BigInteger &rhs) const
{
BigInteger result = *this;
divide(result, rhs);
return result;
}
BigInteger& operator %= (const BigInteger &rhs)
{
divide(*this, rhs);
return *this;
}
bool operator > (const BigInteger &rhs) const
{
// 如果數位不相等
if (m_bits.size() != rhs.m_bits.size())
return m_bits.size() > rhs.m_bits.size();
// 數位相等則逐位進行比較
for (int i = m_bits.size() - 1; i >= 0; i--)
{
if (m_bits[i] != rhs.m_bits[i])
return m_bits[i] > rhs.m_bits[i];
}
return false;
}
bool operator >= (const BigInteger &rhs) const
{
return (*this > rhs || *this == rhs);
}
bool operator < (const BigInteger &rhs) const
{
return !(*this >= rhs);
}
bool operator <= (const BigInteger &rhs) const
{
return !(*this > rhs);
}
bool operator == (const BigInteger &rhs) const
{
return m_bits == rhs.m_bits;
}
bool operator != (const BigInteger &rhs) const
{
return m_bits != rhs.m_bits;
}
private:
// 該函式假設 lhs >= rhs
static BigInteger sub(const BigInteger &lhs, const BigInteger &rhs)
{
BigInteger result;
result.m_bits.clear();
for (int i = 0, carry = 0; ; i++)
{
if (i >= lhs.m_bits.size() && i >= rhs.m_bits.size() && carry == 0)
break;
int num = carry;
if (i < lhs.m_bits.size())
num += lhs.m_bits[i];
if (i < rhs.m_bits.size())
num -= rhs.m_bits[i];
num += BASE;
result.m_bits.push_back(num % BASE);
carry = num / BASE - 1;
}
removeHighestZero(result);
return result;
}
// 利用長除法進行除法運算
static BigInteger divide(BigInteger &lhs, const BigInteger &rhs)
{
BigInteger result;
result.m_bits.clear();
result.m_bits.resize(lhs.m_bits.size() - rhs.m_bits.size() + 1, 0);
BigInteger temp;
int pos = 0, quotient = 0;
while (lhs >= rhs)
{
if (lhs.m_bits.back() >= rhs.m_bits.back())
{
quotient = lhs.m_bits.back() / rhs.m_bits.back();
pos = lhs.m_bits.size() - rhs.m_bits.size();
}
else
{
// 由於int的精度限制,所以quotient的運算不能產生溢位,因而BASE的值不能太大
quotient = lhs.m_bits.back() * BASE / rhs.m_bits.back();
pos = lhs.m_bits.size() - rhs.m_bits.size() - 1;
}
temp.m_bits.clear();
temp.m_bits.resize(pos + 1, 0);
temp.m_bits[pos] = quotient;
result.m_bits[pos] += quotient;
lhs = lhs - rhs * temp;
}
removeHighestZero(result);
return result;
}
// 去掉最高位的0
static void removeHighestZero(BigInteger &num)
{
while (num.m_bits.size() > 1 && num.m_bits.back() == 0)
num.m_bits.pop_back();
}
// 格式化各數位,使其符合進位制
static void formatBits(BigInteger &num)
{
int carry = 0;
for (size_t i = 0; i < num.m_bits.size(); i++)
{
int temp = num.m_bits[i] + carry;
num.m_bits[i] = temp % BASE;
carry = temp / BASE;
}
while (carry != 0)
{
num.m_bits.push_back(carry % BASE);
carry /= BASE;
}
}
private:
// 採用BASE進位制記錄任意大小的非負整數
// BASE為10的指數,因乘法運算具體實現的限制,BASE的值不要超過10^4
static const int BASE = 10000;
static const int WIDTH = 4;
// BASE進位制各數位,從低位到高位對應陣列從左到右
vector<int> m_bits;
};
ostream& operator << (ostream &out, const BigInteger &num)
{
static string format = "%0" + to_string(BigInteger::WIDTH) +"d";
out << num.m_bits.back();
for (int i = num.m_bits.size() - 2; i >= 0; i--)
{
char buf[20];
sprintf(buf, format.c_str(), num.m_bits[i]);
out << buf;
}
return out;
}
istream& operator >> (istream &in, BigInteger &num)
{
string str;
if (!(in >> str))
return in;
num = str;
return in;
}
int main()
{
cout << "-----------------------Test procedure for BigInteger-----------------------" << endl;
BigInteger num1, num2;
char instruction;
while (1)
{
cout << "Enter q to exit and other to start" << endl;
cin >> instruction;
if (instruction == 'q')
break;
cout << "please input num1:" << endl;
cin >> num1;
cout << "please input num2:" << endl;
cin >> num2;
cout << "the result of (num1 + num2) is:" << endl;
cout << num1 + num2 << endl;
cout << "the result of (num1 - num2):" << endl;
cout << num1 - num2 << endl;
cout << "the result of (num1 * num2):" << endl;
cout << num1 * num2 << endl;
cout << "the result of (num1 / num2):" << endl;
cout << num1 / num2 << endl;
cout << "the result of (num1 % num2):" << endl;
cout << num1 % num2 << endl;
cout << endl;
}
return 0;
}
相關文章
- 【java】Maths類、Random類、System類、BigInteger類、BigDecimal類、Date類、SimpleDateFormat類JavarandomDecimalORM
- 實現一個原子的正整數類:AtomicPositiveInteger
- 整數取模類
- C++有理數類設計C++
- 包裝類型別,跳脫字元,BigDecimal,BigInteger,Ca型別字元Decimal
- Java大數相乘(使用BigInteger和BigDecimal)JavaDecimal
- 漫畫:如何實現大整數相加?
- muduo網路庫AtomicIntegerT原子整數類
- 類轉json的基類實現JSON
- HashSet 實現類
- 一個隨機數的類c++隨機C++
- LeetCode題庫13. 羅馬數字轉整數(c++實現)LeetCodeC++
- Map類及其主要的實現類
- C++ 類 & 物件C++物件
- C++分類C++
- java中介面多個實現類,如何指定實現類,根據子類型別選擇實現方法Java型別
- 自實現string類
- TypeScript 類實現介面TypeScript
- string類的實現
- Java之BigInteger(能夠存取比Long更大的整數,可以任意大小)Java
- 實現不可變類如何禁止子類化?
- delphi 判斷類是否實現介面,獲取類實現的介面
- Java集合為什麼設計為:實現類繼承了抽象類,同時實現抽象類實現的介面Java繼承抽象
- c++類和物件C++物件
- C++ | 類繼承C++繼承
- C++ 類和物件C++物件
- C++ 類的大小C++
- C++的代理類C++
- C++共享之道:用extern實現原始檔變數與類成員函式的巧妙共享C++變數函式
- c++類與類的聚合(Aggregation)關係C++
- Set介面及其實現類
- 自定義實現Complex類
- python 介面實現類的Python
- Pytorch實現分類器PyTorch
- C++類和物件是什麼?C++類和物件詳解C++物件
- leetcode 整數拆分(c++)LeetCodeC++
- 【JAVA】自定義類載入器實現類隔離Java
- C++ Templates (2.1 類别範本Stack的實現 Implementation of Class Template Stack)C++