【片段集】大數運算
阿新 • • 發佈:2018-11-02
大數就是很大很大的超出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; }