C++ 大整數類(BigInteger類)實現

Gxysbra發表於2020-10-17

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;
}

相關文章