1. 程式人生 > >【片段集】大數運算

【片段集】大數運算

大數就是很大很大的超出64位整數的表示範圍的數。

使用豎式進行加減乘除運算,支援任意位數的整數。暫不支援小數。

上程式碼。


BigNumber.h

#pragma once
#include <iostream>
using namespace std;
#define DIGITS_OF_BIG_NUMBER 50


class CBigNumber
{
public:
	
	//operators
	friend ostream& operator <<(ostream &cout,CBigNumber& bignumber);
	friend istream& operator >>(istream &cin,CBigNumber& bignumber);
	
	friend bool operator >(CBigNumber &bgn1,CBigNumber &bgn2);
	friend bool operator >=(CBigNumber &bgn1,CBigNumber &bgn2);
	friend bool operator ==(CBigNumber &bgn1,CBigNumber &bgn2);
	friend bool operator <(CBigNumber &bgn1,CBigNumber &bgn2);
	friend bool operator <=(CBigNumber &bgn1,CBigNumber &bgn2);
	
	friend CBigNumber& operator +(CBigNumber &bgn1,CBigNumber &bgn2);
	friend CBigNumber& operator +(int n,CBigNumber &bgn2);
	friend CBigNumber& operator +(CBigNumber &bgn1,int n);
	
	friend CBigNumber& operator -(CBigNumber &bgn1,CBigNumber &bgn2);//沒有進行符號處理
	
	friend CBigNumber& operator *(CBigNumber &bgn1,CBigNumber &bgn2);
	 
	friend CBigNumber& operator /(CBigNumber &bgn1,CBigNumber &bgn2);
	
public:
	CBigNumber();
	CBigNumber(char* number);
	CBigNumber(int n);
	CBigNumber(long n);
private:
	char m_cSign;//符號'+' or '-' 【未實現】
	int m_Number[DIGITS_OF_BIG_NUMBER];//儲存資料,棧式儲存
	int m_nDigits;//記錄位數,由於資料是從高到低儲存,初始值為DIGITS_OF_BIG_NUMBER,表示沒有數位。
};

ostream& operator <<(ostream &cout,CBigNumber& bignumber);
istream& operator >>(istream &cin,CBigNumber& bignumber);

bool operator >(CBigNumber &bgn1,CBigNumber &bgn2);
bool operator >=(CBigNumber &bgn1,CBigNumber &bgn2);
bool operator ==(CBigNumber &bgn1,CBigNumber &bgn2);
bool operator <(CBigNumber &bgn1,CBigNumber &bgn2);
bool operator <=(CBigNumber &bgn1,CBigNumber &bgn2);

CBigNumber& operator +(CBigNumber &bgn1,CBigNumber &bgn2);
CBigNumber& operator +(int n,CBigNumber &bgn2);
CBigNumber& operator +(CBigNumber &bgn1,int n);

CBigNumber& operator -(CBigNumber &bgn1,CBigNumber &bgn2);

CBigNumber& operator *(CBigNumber &bgn1,CBigNumber &bgn2);//bgn1為被乘數,bgn2為乘數

CBigNumber& operator /(CBigNumber &bgn1,CBigNumber &bgn2);////bgn1為被除數,bgn2為除數


BigNumber.cpp

#include <iostream>
#include "BigNumber.h"

using namespace std;

CBigNumber::CBigNumber()
{
	m_cSign='+';
	m_nDigits=DIGITS_OF_BIG_NUMBER;
	memset(m_Number,0,DIGITS_OF_BIG_NUMBER*4);
}
CBigNumber::CBigNumber(char* number)
{
	m_nDigits=DIGITS_OF_BIG_NUMBER;
	memset(m_Number,0,DIGITS_OF_BIG_NUMBER*4);
	char c=*number;
	if(c!='-') m_cSign='+';//如果以'-'開頭就認為是負數,否則都認為是正數
	else m_cSign='-';
	while(c!='\0')
	{
		if(c>='0'&&c<='9')
		{
			m_nDigits--;
			m_Number[m_nDigits]=c-'0';
			if(m_nDigits==0)
				break;
		}
		number++;
		c=*number;
	}
	//翻轉成從低到高的閱讀順序
	int d=(DIGITS_OF_BIG_NUMBER-1-m_nDigits)/2;
	for(int i=0;i<=d;i++)
	{
		char c=m_Number[m_nDigits+i];
		m_Number[m_nDigits+i]=m_Number[DIGITS_OF_BIG_NUMBER-1-i];
		m_Number[DIGITS_OF_BIG_NUMBER-1-i]=c;
	}
}
CBigNumber::CBigNumber(long n)
{
	m_nDigits=DIGITS_OF_BIG_NUMBER;
	memset(m_Number,0,DIGITS_OF_BIG_NUMBER*4);
	while(n>0)//n=0時不用操作,因為BigNumber初始化就是0
	{
		m_nDigits--;
		m_Number[m_nDigits]=n%10;
		n=n/10;
	}
}
CBigNumber::CBigNumber(int n)
{
	m_nDigits=DIGITS_OF_BIG_NUMBER;
	memset(m_Number,0,DIGITS_OF_BIG_NUMBER*4);
	while(n>0)//n=0時不用操作,因為BigNumber初始化就是0
	{
		m_nDigits--;
		m_Number[m_nDigits]=n%10;
		n=n/10;
	}
}
ostream& operator <<(ostream& cout,CBigNumber &bignumber)
{
	if(bignumber.m_nDigits==DIGITS_OF_BIG_NUMBER)
		cout<<0;
	for(int i=bignumber.m_nDigits;i<DIGITS_OF_BIG_NUMBER;i++)
		cout<<bignumber.m_Number[i];
	return cout;
}
istream& operator >>(istream &cin,CBigNumber &bignumber)
{
	char c;
	c=getchar();
	while(c>='0'||c<=9)
	{
		bignumber.m_nDigits--;
		bignumber.m_Number[bignumber.m_nDigits]=c-'0';
		c=getchar();
		if(bignumber.m_nDigits==0) break;
	}
	return cin;
}
bool operator >(CBigNumber &bgn1,CBigNumber &bgn2)
{
	if(bgn1.m_nDigits<bgn2.m_nDigits)//bgn1的位數多
		return true;
	else if(bgn1.m_nDigits>bgn2.m_nDigits)//bgn1的位數少
		return false;
	for(int i=bgn1.m_nDigits;i<DIGITS_OF_BIG_NUMBER;i++)//二者位數相同
	{
		if(bgn1.m_Number[i]>bgn2.m_Number[i])//
		{
			return true;
		}
		else if(bgn1.m_Number[i]<bgn2.m_Number[i])
		{
			return false;
		}
	}
	//執行到這裡說明是等於
	return false;
}
bool operator >=(CBigNumber &bgn1,CBigNumber &bgn2)
{
	if(bgn1.m_nDigits<bgn2.m_nDigits)//bgn1的位數多
		return true;
	else if(bgn1.m_nDigits>bgn2.m_nDigits)//bgn1的位數少
		return false;
	for(int i=bgn1.m_nDigits;i<DIGITS_OF_BIG_NUMBER;i++)//二者位數相同
	{
		if(bgn1.m_Number[i]>bgn2.m_Number[i])//
		{
			return true;
		}
		else if(bgn1.m_Number[i]<bgn2.m_Number[i])
		{
			return false;
		}
	}
	//執行到這裡說明是等於
	return true;
}
bool operator ==(CBigNumber &bgn1,CBigNumber &bgn2)
{
	if(bgn1.m_nDigits!=bgn2.m_nDigits)//二者位數不相同
		return false;
	for(int i=bgn1.m_nDigits;i<DIGITS_OF_BIG_NUMBER;i++)//二者位數相同
	{
		if(bgn1.m_Number[i]!=bgn2.m_Number[i])
		{
			return false;
		}
	}
	//執行到這裡說明是等於
	return true;
}
bool operator <(CBigNumber &bgn1,CBigNumber &bgn2)
{
	if(bgn1.m_nDigits<bgn2.m_nDigits)//bgn1的位數多
		return false;
	else if(bgn1.m_nDigits>bgn2.m_nDigits)//bgn1的位數少
		return true;
	for(int i=bgn1.m_nDigits;i<DIGITS_OF_BIG_NUMBER;i++)//二者位數相同
	{
		if(bgn1.m_Number[i]<bgn2.m_Number[i])//
		{
			return true;
		}
		else if(bgn1.m_Number[i]>bgn2.m_Number[i])
		{
			return false;
		}
	}
	//執行到這裡說明是等於
	return false;
}
bool operator <=(CBigNumber &bgn1,CBigNumber &bgn2)
{
	if(bgn1.m_nDigits<bgn2.m_nDigits)//bgn1的位數多
		return false;
	else if(bgn1.m_nDigits>bgn2.m_nDigits)//bgn1的位數少
		return true;
	for(int i=bgn1.m_nDigits;i<DIGITS_OF_BIG_NUMBER;i++)//二者位數相同
	{
		if(bgn1.m_Number[i]<bgn2.m_Number[i])//
		{
			return true;
		}
		else if(bgn1.m_Number[i]>bgn2.m_Number[i])
		{
			return false;
		}
	}
	//執行到這裡說明是等於
	return true;
}


CBigNumber& operator +(CBigNumber &bgn1,CBigNumber &bgn2)
{
	static CBigNumber bgnSum;//較大的數作為被加數,和放在較大的數裡
	static CBigNumber *pBgnAddend;//較小的數作為加數
	if(bgn1.m_nDigits<bgn2.m_nDigits)
	{
		bgnSum=bgn1;
		pBgnAddend=&bgn2;
	}
	else
	{
		bgnSum=bgn2;
		pBgnAddend=&bgn1;
	}
	
	int carry=0;
	for(int i=DIGITS_OF_BIG_NUMBER-1;i>=bgnSum.m_nDigits;i--)
	{
		carry+=bgnSum.m_Number[i]+pBgnAddend->m_Number[i];
		if(carry>=10)//如果大於10的話向前進位
		{
			bgnSum.m_Number[i]=carry-10;
			carry=1;
		}
		else
		{
			bgnSum.m_Number[i]=carry;
			carry=0;
		}
		if(carry==0&&pBgnAddend->m_nDigits>=i)//加數加完了且沒有進位就結束加法
			break;
	}
	//bgnSum.m_nDigits=t;
	if(carry&&bgnSum.m_nDigits>0)//加完了還有進位且不會溢位(被加數加完了),就補上
	{
		bgnSum.m_nDigits--;
		bgnSum.m_Number[bgnSum.m_nDigits]=1;	
	}
	return bgnSum;
}

CBigNumber& operator +(int n,CBigNumber &bgn2)
{
	CBigNumber bgn1(n);
	return bgn1+bgn2;
}
CBigNumber& operator +(CBigNumber &bgn1,int n)
{
	CBigNumber bgn2(n);
	return bgn1+bgn2;
}

CBigNumber& operator -(CBigNumber &bgn1,CBigNumber &bgn2)
{
	static CBigNumber bgnDif;//較大的數作為被減數,差放在被減數中
	static CBigNumber *pBgnSubtractor;//較小的數作為減數
	if(bgn1>bgn2)
	{
		bgnDif=bgn1;
		pBgnSubtractor=&bgn2;
	}
	else
	{
		bgnDif=bgn2;
		pBgnSubtractor=&bgn1;
	}
	int carry=0;
	for(int i=DIGITS_OF_BIG_NUMBER-1;i>=bgnDif.m_nDigits;i--)
	{
		bgnDif.m_Number[i]-=carry;
		carry=0;
		if(bgnDif.m_Number[i]<pBgnSubtractor->m_Number[i])
		{
			carry=1;
			bgnDif.m_Number[i]=bgnDif.m_Number[i]+10-pBgnSubtractor->m_Number[i];
		}
		else
		{
			bgnDif.m_Number[i]=bgnDif.m_Number[i]-pBgnSubtractor->m_Number[i];
		}
		if(carry==0&&pBgnSubtractor->m_nDigits>=i)//如果進位為0且減數減完了就結束
			break;
	}
	//被減數減到頭了還沒減完,這種情況不存在
	carry=0;
	while(!bgnDif.m_Number[carry]) carry++;//重新計算位數
	bgnDif.m_nDigits=carry;
	
	return bgnDif;
}

CBigNumber& operator *(CBigNumber &bgn1,CBigNumber &bgn2)
{
	static CBigNumber bgnProduct;//積放在這裡面
	static CBigNumber *pBgn;
	memset(&bgnProduct,0,sizeof(CBigNumber));
	int carry=0;
	int i,j;
	for(i=DIGITS_OF_BIG_NUMBER-1;i>=bgn2.m_nDigits;i--)//乘數去成被乘數,迴圈的次數是乘數的位數
	{
		carry=0;
		for(j=DIGITS_OF_BIG_NUMBER-1;j>=bgn1.m_nDigits;j--)//乘以被乘數的每一位
		{
			carry=bgn2.m_Number[i]*bgn1.m_Number[j]+carry+bgnProduct.m_Number[j-(DIGITS_OF_BIG_NUMBER-1-i)];
			if(carry>=10)
			{
				bgnProduct.m_Number[j-(DIGITS_OF_BIG_NUMBER-1-i)]+=carry%10;
				carry/=10;
			}
			else
			{
				bgnProduct.m_Number[j-(DIGITS_OF_BIG_NUMBER-1-i)]=carry;
				carry=0;
			}
		}
		if(carry!=0)//被乘數乘空了還有進位
		{
			bgnProduct.m_Number[j-(DIGITS_OF_BIG_NUMBER-1-i)]=carry;
		}
	}
	i=0;
	while(bgnProduct.m_Number[i]==0) i++;
	bgnProduct.m_nDigits=i;
	return bgnProduct;
}

CBigNumber& operator /(CBigNumber &bgn1,CBigNumber &bgn2)
{
	static CBigNumber bgnQuotient;//商
	static CBigNumber bgnTemp;//除法的中間量
	memset(&bgnQuotient,0,sizeof(CBigNumber));
	memset(&bgnTemp,0,sizeof(CBigNumber));
	bgnQuotient.m_nDigits=DIGITS_OF_BIG_NUMBER;
	if(bgn1<bgn2)//小於的話結果為0
		return bgnQuotient;
	
	int nIndex=bgn1.m_nDigits-1;//當前取到除數的第幾位,指向上一次讀的位置
	
	//取被除數的前n個數放進temp,n為除數的位數
	for(int i=DIGITS_OF_BIG_NUMBER-bgn2.m_nDigits;i>0;i--)
	{
		nIndex++;
		bgnTemp.m_Number[DIGITS_OF_BIG_NUMBER-i]=bgn1.m_Number[nIndex];
	}
	bgnTemp.m_nDigits=bgn2.m_nDigits;
	//cout<<bgnTemp<<endl;
	
	bgnQuotient.m_nDigits=0;
	while(nIndex<DIGITS_OF_BIG_NUMBER-1)//被除數的所有位都取完結束運算
	{
		//如果temp小於除數,再取一個數放進去
		while(bgnTemp<bgn2&&nIndex<DIGITS_OF_BIG_NUMBER-1)
		{
			for(int i=bgnTemp.m_nDigits;i<DIGITS_OF_BIG_NUMBER;i++)//temp中資料左移
				bgnTemp.m_Number[i-1]=bgnTemp.m_Number[i];

			bgnTemp.m_nDigits--;
			nIndex++;
			bgnTemp.m_Number[DIGITS_OF_BIG_NUMBER-1]=bgn1.m_Number[nIndex];
			bgnQuotient.m_nDigits++;//準備迎接下一個商,如果是繼續去數放進temp,那麼商中會增加一個0
		}
		
		//計算temp/除數的結果,以及餘數放進temp
		while(bgnTemp>=bgn2)
		{
			bgnQuotient.m_Number[bgnQuotient.m_nDigits]++;
			bgnTemp=bgnTemp-bgn2;
			//cout<<"/.."<<bgnTemp<<"\t"<<bgnQuotient.m_Number[bgnQuotient.m_nDigits]<<endl;
		}
	}
	
	//左移
	for(int i=bgnQuotient.m_nDigits;i>=0;i--)
	{
		bgnQuotient.m_Number[DIGITS_OF_BIG_NUMBER-1-bgnQuotient.m_nDigits+i]=bgnQuotient.m_Number[i];
	}
	bgnQuotient.m_nDigits=DIGITS_OF_BIG_NUMBER-1-bgnQuotient.m_nDigits;
	return bgnQuotient;
}


main.cpp

#include <iostream>
#include "BigNumber.h"
using namespace std;


int main(int argc, char* argv[])
{
	CBigNumber bignumber1("123456789123456789");
	CBigNumber bignumber2("123456789123456780");
	
	cout<<"條件運算:"<<endl;
	cout<<"> "<<(bignumber1>bignumber2)<<endl;
	cout<<">="<<(bignumber1>=bignumber2)<<endl;
	cout<<"=="<<(bignumber1==bignumber2)<<endl;
	cout<<"< "<<(bignumber1<bignumber2)<<endl;
	cout<<"<="<<(bignumber1<=bignumber2)<<endl;
	
	cout<<"\n四則運算:"<<endl;
	cout<<"+"<<bignumber1+bignumber2<<endl;
	cout<<"-"<<bignumber1-bignumber2<<endl;
	//cout<<"*"<<bignumber1*bignumber2<<endl;
	cout<<"*"<<CBigNumber("123456789")*CBigNumber("123456789")<<endl;
	cout<<"/"<<CBigNumber("78945613")/CBigNumber("123")<<endl;
	
	CBigNumber bgnI("1"),bgnJ("1");double n=1,m=1;
	cout<<1<<'\t'<<bgnI<<"\t\t\t"<<n<<endl;
	cout<<2<<'\t'<<bgnI<<"\t\t\t"<<endl;
	for(int i=2;i<200;i+=2)
	{
		bgnI=bgnI+bgnJ; n=m+n;
		bgnJ=bgnI+bgnJ; m=m+n;
		cout<<i<<'\t'<<bgnI<<"\t\t\t"<<n<<endl;
		cout<<i+1<<'\t'<<bgnJ<<"\t\t\t"<<m<<endl;
	}
	
	return 0;
}