C++實現大整數運算包(加、減、乘、除、冪模、GCD、乘法逆)
阿新 • • 發佈:2019-01-09
Miller-Rabin大素數檢測演算法請看我的這篇文章 https://blog.csdn.net/qq_34490018/article/details/79844036#include <iostream> #include <string> #include <cstdlib> #include <algorithm>//reverse函式所需新增的標頭檔案 using namespace std; /* 大整數類 */ class BigInt { private: inline int compare(string s1, string s2) { if(s1.size() < s2.size()) return -1; else if(s1.size() > s2.size()) return 1; else return s1.compare(s2); } public: bool flag;//true表示正數,false表示負數,0預設為正數 string values;//儲存所有位上的數字 BigInt():values("0"),flag(true){};//建構函式 BigInt(string str)//型別轉換建構函式(預設為正整數) { values = str; flag = true; } public: friend ostream& operator << (ostream& os, const BigInt& bigInt);//過載輸出操作符 friend istream& operator>>(istream& is, BigInt& bigInt);//輸入操作符過載 BigInt operator+(const BigInt& rhs);//加法操作過載 BigInt operator-(const BigInt& rhs);//減法操作過載 BigInt operator*(const BigInt& rhs);//乘法操作過載 BigInt operator/(const BigInt& rhs);//除法操作過載 BigInt operator%(const BigInt& rhs);//求餘操作過載 }; /* 過載流提取運算子'>>',輸出一個整數 */ ostream& operator << (ostream& os, const BigInt& bigInt) { if (!bigInt.flag) { os << '-'; } os << bigInt.values; return os; } /* 過載流插入運算子'>>',輸入一個正整數 */ istream& operator >> (istream& is, BigInt& bigInt) { string str; is >> str; bigInt.values = str; bigInt.flag = true; return is; } /* 兩個正整數相加 */ BigInt BigInt::operator+(const BigInt& rhs) { BigInt ret; ret.flag = true;//正整數相加恆為正數 string lvalues(values), rvalues(rhs.values); //處理特殊情況 if (lvalues == "0") { ret.values = rvalues; return ret; } if (rvalues == "0") { ret.values = lvalues; return ret; } //調整s1與s2的長度 unsigned int i, lsize, rsize; lsize = lvalues.size(); rsize = rvalues.size(); if (lsize < rsize) { for (i = 0; i < rsize - lsize; i++)//在lvalues左邊補零 { lvalues = "0" + lvalues; } } else { for (i = 0; i < lsize - rsize; i++)//在rvalues左邊補零 { rvalues = "0" + rvalues; } } //處理本質情況 int n1, n2; n2 = 0; lsize = lvalues.size(); string res = ""; reverse(lvalues.begin(), lvalues.end());//顛倒字串,以方便從低位算起計算 reverse(rvalues.begin(), rvalues.end()); for (i = 0; i < lsize; i++) { n1 = (lvalues[i] - '0' + rvalues[i] - '0' + n2) % 10;//n1代表當前位的值 n2 = (lvalues[i] - '0' + rvalues[i] - '0' + n2) / 10;//n2代表進位 res = res + char(n1 + '0'); } if (n2 == 1) { res = res + "1"; } reverse(res.begin(), res.end()); ret.values = res; return ret; } /* 兩個正整數相減 */ BigInt BigInt::operator-(const BigInt& rhs) { BigInt ret; string lvalues(values), rvalues(rhs.values); //負數減負數 if(flag==false&&rhs.flag==false) { string tmp = lvalues; lvalues = rvalues; rvalues = tmp; } //負數減正數 if(flag==false&&rhs.flag==true) { BigInt res(lvalues); ret=res+rhs; ret.flag = false; return ret; } if(flag==true&&rhs.flag==false) { BigInt rel(lvalues),res(rhs.values); ret=rel+res; ret.flag = true; return ret; } //處理特殊情況 if (rvalues == "0") { ret.values = lvalues; ret.flag = true; return ret; } if (lvalues == "0") { ret.values = rvalues; ret.flag = false; return ret; } //調整s1與s2的長度 unsigned int i, lsize, rsize; lsize = lvalues.size(); rsize = rvalues.size(); if (lsize < rsize) { for (i = 0; i < rsize - lsize; i++)//在lvalues左邊補零 { lvalues = "0" + lvalues; } } else { for (i = 0; i < lsize - rsize; i++)//在rvalues左邊補零 { rvalues = "0" + rvalues; } } //調整使‘-’號前邊的數大於後邊的數 int t = lvalues.compare(rvalues);//相等返回0,str1<str2返回負數,str1>str2返回正數 if (t < 0) { ret.flag = false; string tmp = lvalues; lvalues = rvalues; rvalues = tmp; } else if (t == 0) { ret.values = "0"; ret.flag = true; return ret; } else { ret.flag = true; } //處理本質情況 unsigned int j; lsize = lvalues.size(); string res = ""; reverse(lvalues.begin(), lvalues.end());//顛倒字串,以方便從低位算起計算 reverse(rvalues.begin(), rvalues.end()); for (i = 0; i < lsize; i++) { if (lvalues[i] < rvalues[i])//不足,向前借一維 { j = 1; while(lvalues[i+j] == '0') { lvalues[i+j] = '9'; j++; } lvalues[i+j] -= 1; res = res + char(lvalues[i] + ':' - rvalues[i]); } else { res = res + char(lvalues[i] - rvalues[i] + '0'); } } reverse(res.begin(), res.end()); res.erase(0, res.find_first_not_of('0'));//去掉前導零 ret.values = res; return ret; } /* 兩個正整數相乘 */ BigInt BigInt::operator*(const BigInt& rhs) { BigInt ret; string lvalues(values), rvalues(rhs.values); //處理0或結果正負 if (lvalues == "0" || rvalues == "0") { ret.values = "0"; ret.flag = true; return ret; } if(flag==false||rhs.flag==false) { ret.flag=false; } //處理特殊情況 unsigned int lsize, rsize; lsize = lvalues.size(); rsize = rvalues.size(); string temp; BigInt res, itemp; //讓lvalues的長度最長 if (lvalues < rvalues) { temp = lvalues; lvalues = rvalues; rvalues = temp; lsize = lvalues.size(); rsize = rvalues.size(); } //處理本質情況 int i, j, n1, n2, n3, t; reverse(lvalues.begin(), lvalues.end());//顛倒字串 reverse(rvalues.begin(), rvalues.end()); for (i = 0; i < rsize; i++) { temp = ""; n1 = n2 = n3 = 0; for (j = 0; j < i; j++) { temp = temp + "0"; } n3 = rvalues[i] - '0'; for (j = 0; j < lsize; j++) { t = (n3*(lvalues[j] - '0') + n2); n1 = t % 10;//n1記錄當前位置的值 n2 = t / 10;//n2記錄進位的值 temp = temp + char(n1 + '0'); } if (n2) { temp = temp + char(n2 + '0'); } reverse(temp.begin(), temp.end()); itemp.values = temp; res = res + itemp; } ret.values = res.values; return ret; } /* 兩個正整數相除 */ BigInt BigInt::operator/(const BigInt& rhs) { BigInt ret; string lvalues(values), rvalues(rhs.values); string quotient; string temp; //處理特殊情況 if(rvalues == "0") { ret.values = "error";//輸出錯誤 ret.flag = true; return ret; } if(lvalues == "0") { ret.values = "0"; ret.flag = true; return ret; } if(compare(lvalues, rvalues) < 0) { ret.values = "0"; ret.flag = true; return ret; } else if(compare(lvalues, rvalues) == 0) { ret.values = "1"; ret.flag = true; return ret; } else { //處理本質情況 unsigned int lsize, rsize; lsize = lvalues.size(); rsize = rvalues.size(); int i; if(rsize > 1) temp.append(lvalues, 0, rsize-1); for(i = rsize - 1; i < lsize; i++) { temp = temp + lvalues[i]; //試商 for(char c = '9'; c >= '0'; c--) { BigInt t = (BigInt)rvalues * (BigInt)string(1, c); BigInt s = (BigInt)temp - t; if(s.flag == true) { temp = s.values; quotient = quotient + c; break; } } } } //去除前導零 quotient.erase(0, quotient.find_first_not_of('0')); ret.values = quotient; ret.flag = true; return ret; } /* 兩個正整數取餘 */ BigInt BigInt::operator%(const BigInt& rhs) { BigInt ret,kj(values),ki(rhs.values); string lvalues(values), rvalues(rhs.values); string quotient; string temp; //處理特殊情況 if(rvalues == "0") { ret.values = "error";//輸出錯誤 ret.flag = true; return ret; } if(lvalues == "0") { ret.values = "0"; ret.flag = true; return ret; } if(compare(lvalues, rvalues) < 0) { if(flag==false) { ret.values=(ki-kj).values; ret.flag = true; return ret; }else{ ret.values = lvalues; ret.flag = true; return ret; } } else if(compare(lvalues, rvalues) == 0) { ret.values = "0"; ret.flag = true; return ret; } else { //處理本質情況 unsigned int lsize, rsize; lsize = lvalues.size(); rsize = rvalues.size(); int i; if(rsize > 1) temp.append(lvalues, 0, rsize-1); for(i = rsize - 1; i < lsize; i++) { if(temp=="0"){ temp=lvalues[i]; }else{ temp = temp + lvalues[i]; } //試商 for(char c = '9'; c >= '0'; c--) { BigInt t = (BigInt)rvalues * (BigInt)string(1, c); BigInt s = (BigInt)temp - t; if(s.flag == true) { //cout<<s.values<<endl; temp = s.values; quotient = quotient + c; break; } } } } //去除前導零 quotient.erase(0, quotient.find_first_not_of('0')); ret.values = temp; ret.flag = true; return ret; } /* 一個大整數和一個小整數的取餘 int divMod(string ch,int num) { int s=0; for(int i=0;ch[i]!='\0';i++) s=(s*10+ch[i]-'0')%num; return s; }*/ /* 歐幾里德求GCD */ BigInt gcd(BigInt a,BigInt b) { BigInt stemp; //cout<<a<<endl; //cout<<b<<endl; if((a-b).flag==false)//判斷大小 { stemp.values=a.values; a.values=b.values; b.values=stemp.values; } if(b.values=="0") return a; else return gcd(b,a%b); } /* 快速冪 */ BigInt fast(BigInt a,BigInt b) { BigInt aa=a,t("1"),k("2"); // int b2=atoi(b1[lsize-1].c_str()); while(b.values!="0") { if((b%k).values!="0") { t=t*aa; } aa=aa*aa; b=b/k; } return t; } /* 快速冪模 */ BigInt mod_fast(BigInt a,BigInt b,BigInt p) { BigInt aa=a,t("1"),k("2"); // int b2=atoi(b1[lsize-1].c_str()); while(b.values!="0") { if((b%k).values!="0") { t=(t%p)*(aa%p)%p; } aa=(aa%p)*(aa%p)%p; b=b/k; } return t%p; } /* 擴充套件歐幾里德實現乘法逆 */ BigInt extgcd(BigInt a, BigInt b, BigInt& x, BigInt& y) { BigInt d(a.values); if(b.values != "0"){ d = extgcd(b, a % b, y, x); y = y-(a / b) * x; // cout<<"a:"<<a<<endl; // cout<<"b:"<<b<<endl; // cout<<"x:"<<x<<endl; // cout<<"y:"<<y<<endl<<endl<<endl; }else { x.values = "1"; y.values = "0"; } return d; } BigInt mod_inverse(BigInt a, BigInt m) { BigInt x, y; extgcd(a, m, x, y); if(x.flag==false) { x.flag=true; x=m-x; } return (m + x % m) % m; } int main() { BigInt a,b,n; char op; while(1){ cout<<"請按提示數字進行操作。。。。"<<endl<<endl; cout<<"1-------計算(a+b)mod n的值-------"<<endl; cout<<"2-------計算(a-b)mod n的值-------"<<endl; cout<<"3-------計算(a*b)mod n的值-------"<<endl; cout<<"4-------計算(a/b)mod n的值-------"<<endl; cout<<"5-------計算(a%b)mod n的值-------"<<endl; cout<<"6-------計算(a^b)mod n的值-------"<<endl; cout<<"7-------計算 GCD(a,b) 的值-------"<<endl; cout<<"8-------計算a和n乘法逆的值-------"<<endl; cout<<endl<<endl<<"請輸入數字進行計算:"; cin >> op; switch(op) { case '1': cout<<"請輸入a、b和n的值:"; cin>>a>>b>>n; cout<<endl; cout<<"a+b的值:"<<a+b<<endl; cout<<"(a+b)mod n的值: "<< (a+b)%n<<endl<<endl<<endl<<endl; break; case '2': cout<<"請輸入a、b和n的值:"; cin>>a>>b>>n; cout<<endl; cout<<"a-b的值:"<<a-b<<endl; cout<<"(a-b)mod n的值: "<< (a-b)%n<<endl<<endl<<endl<<endl; break; case '3': cout<<"請輸入a、b和n的值:"; cin>>a>>b>>n; cout<<endl; cout<<"a*b的值:"<<a*b<<endl; cout<<"(a*b)mod n的值: "<< (a*b)%n<<endl<<endl<<endl<<endl; break; case '4': cout<<"請輸入a、b和n的值:"; cin>>a>>b>>n; cout<<endl; cout<<"a/b的值:"<<a/b<<endl; cout<<"(a/b)mod n的值: "<< (a/b)%n<<endl<<endl<<endl<<endl; break; case '5': cout<<"請輸入a、b和n的值:"; cin>>a>>b>>n; cout<<endl; cout<<"a%b的值:"<<a%b<<endl; cout<<"(a%b)mod n的值: "<< (a%b)%n<<endl<<endl<<endl<<endl; break; case '6': cout<<"請輸入a、b和n的值:"; cin>>a>>b>>n; cout<<endl; cout<<"a^b的值:"<<fast(a,b)<<endl; cout<<"(a^b)mod n的值: "<<mod_fast(a,b,n)<<endl<<endl<<endl<<endl; break; case '7': cout<<"請輸入a和b的值:"; cin>>a>>b; cout<<endl; cout<<"GCD(a,b)的值:"<<gcd(a,b)<<endl<<endl<<endl<<endl; break; case '8': cout<<"請輸入a和n的值:"; cin>>a>>n; cout<<endl; cout<<"a和n的乘法逆: "<< mod_inverse(a,n)<<endl<<endl<<endl<<endl; break; default:break; } } return 0; }