大數模擬 加減乘除 判斷大數是否為素數 板子

帥氣的大馬猴發表於2020-11-16

過載+ - * /


#include<iostream>
#include<vector>
#include<string>
using namespace std;
struct Wint:vector<int>//用標準庫vector做基類,完美解決位數問題,同時更易於實現
{
    //將低精度轉高精度的初始化,可以自動被編譯器呼叫
    //因此無需單獨寫高精度數和低精度數的運算函式,十分方便
    Wint(int n=0)//預設初始化為0,但0的儲存形式為空
    {
        push_back(n);
        check();
    }
    Wint& check()//在各類運算中經常用到的進位小函式,不妨內建
    {
        while(!empty()&&!back())pop_back();//去除最高位可能存在的0
        if(empty())return *this;
        for(int i=1; i<size(); ++i)
        {
            (*this)[i]+=(*this)[i-1]/10;
            (*this)[i-1]%=10;
        }
        while(back()>=10)
        {
            push_back(back()/10);
            (*this)[size()-2]%=10;
        }
        return *this;//為使用方便,將進位後的自身返回引用
    }
};
//輸入輸出
istream& operator>>(istream &is,Wint &n)
{
    string s;
    is>>s;
    n.clear();
    for(int i=s.size()-1; i>=0; --i)n.push_back(s[i]-'0');
    return is;
}
ostream& operator<<(ostream &os,const Wint &n)
{
    if(n.empty())os<<0;
    for(int i=n.size()-1; i>=0; --i)os<<n[i];
    return os;
}
//比較,只需要寫兩個,其他的直接代入即可
//常量引用當引數,避免拷貝更高效
bool operator!=(const Wint &a,const Wint &b)
{
    if(a.size()!=b.size())return 1;
    for(int i=a.size()-1; i>=0; --i)
        if(a[i]!=b[i])return 1;
    return 0;
}
bool operator==(const Wint &a,const Wint &b)
{
    return !(a!=b);
}
bool operator<(const Wint &a,const Wint &b)
{
    if(a.size()!=b.size())return a.size()<b.size();
    for(int i=a.size()-1; i>=0; --i)
        if(a[i]!=b[i])return a[i]<b[i];
    return 0;
}
bool operator>(const Wint &a,const Wint &b)
{
    return b<a;
}
bool operator<=(const Wint &a,const Wint &b)
{
    return !(a>b);
}
bool operator>=(const Wint &a,const Wint &b)
{
    return !(a<b);
}
//加法,先實現+=,這樣更簡潔高效
Wint& operator+=(Wint &a,const Wint &b)
{
    if(a.size()<b.size())a.resize(b.size());
    for(int i=0; i!=b.size(); ++i)a[i]+=b[i];
    return a.check();
}
Wint operator+(Wint a,const Wint &b)
{
    return a+=b;
}
//減法,返回差的絕對值,由於後面有交換,故引數不用引用
Wint& operator-=(Wint &a,Wint b)
{
    if(a<b)swap(a,b);
    for(int i=0; i!=b.size(); a[i]-=b[i],++i)
        if(a[i]<b[i])//需要借位
        {
            int j=i+1;
            while(!a[j])++j;
            while(j>i)
            {
                --a[j];
                a[--j]+=10;
            }
        }
    return a.check();
}
Wint operator-(Wint a,const Wint &b)
{
    return a-=b;
}
//乘法不能先實現*=,原因自己想
Wint operator*(const Wint &a,const Wint &b)
{
    Wint n;
    n.assign(a.size()+b.size()-1,0);
    for(int i=0; i!=a.size(); ++i)
        for(int j=0; j!=b.size(); ++j)
            n[i+j]+=a[i]*b[j];
    return n.check();
}
Wint& operator*=(Wint &a,const Wint &b)
{
    return a=a*b;
}
//除法和取模先實現一個帶餘除法函式
Wint divmod(Wint &a,const Wint &b)
{
    Wint ans;
    for(int t=a.size()-b.size(); a>=b; --t)
    {
        Wint d;
        d.assign(t+1,0);
        d.back()=1;
        Wint c=b*d;
        while(a>=c)
        {
            a-=c;
            ans+=d;
        }
    }
    return ans;
}
Wint operator/(Wint a,const Wint &b)
{
    return divmod(a,b);
}
Wint& operator/=(Wint &a,const Wint &b)
{
    return a=a/b;
}
Wint& operator%=(Wint &a,const Wint &b)
{
    divmod(a,b);
    return a;
}
Wint operator%(Wint a,const Wint &b)
{
    return a%=b;
}
//順手實現一個快速冪,可以看到和普通快速冪幾乎無異
Wint pow(const Wint &n,const Wint &k)
{
    if(k.empty())return 1;
    if(k==2)return n*n;
    if(k.back()%2)return n*pow(n,k-1);
    return pow(pow(n,k/2),2);
}
//通過過載運算子,還可以實現++、--、^、!、邏輯運算子等很多運算,十分簡單,此處都不寫了
int main()//現在你完全可以像int一般便捷地使用Wint,如下
{
    Wint a,b;
    //可以把b改成int型,仍能正常使用
    cin>>a>>b;
    cout<<(a<b)<<endl
        <<(a==b)<<endl
        <<a+b<<endl
        <<a-b<<endl
        <<a*b<<endl
        <<a/b<<endl
        <<a%b<<endl
        <<pow(a,b);
}

大數除法

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int L=110;
int sub(int *a,int *b,int La,int Lb)
{
    if(La<Lb) return -1;//如果a小於b,則返回-1
    if(La==Lb)
    {
        for(int i=La-1;i>=0;i--)
            if(a[i]>b[i]) break;
            else if(a[i]<b[i]) return -1;//如果a小於b,則返回-1

    }
    for(int i=0;i<La;i++)//高精度減法
    {
        a[i]-=b[i];
        if(a[i]<0) a[i]+=10,a[i+1]--;
    }
    for(int i=La-1;i>=0;i--)
        if(a[i]) return i+1;//返回差的位數
    return 0;//返回差的位數

}
string div(string n1,string n2,int nn)//n1,n2是字串表示的被除數,除數,nn是選擇返回商還是餘數
{
    string s,v;//s存商,v存餘數
    int a[L],b[L],r[L],La=n1.size(),Lb=n2.size(),i,tp=La;//a,b是整形陣列表示被除數,除數,tp儲存被除數的長度
    fill(a,a+L,0);fill(b,b+L,0);fill(r,r+L,0);//陣列元素都置為0
    for(i=La-1;i>=0;i--) a[La-1-i]=n1[i]-'0';
    for(i=Lb-1;i>=0;i--) b[Lb-1-i]=n2[i]-'0';
    if(La<Lb || (La==Lb && n1<n2)) {
        //cout<<0<<endl;
        return n1;}//如果a<b,則商為0,餘數為被除數
    int t=La-Lb;//除被數和除數的位數之差
    for(int i=La-1;i>=0;i--)//將除數擴大10^t倍
        if(i>=t) b[i]=b[i-t];
        else b[i]=0;
    Lb=La;
    for(int j=0;j<=t;j++)
    {
        int temp;
        while((temp=sub(a,b+j,La,Lb-j))>=0)//如果被除數比除數大繼續減
        {
            La=temp;
            r[t-j]++;
        }
    }
    for(i=0;i<L-10;i++) r[i+1]+=r[i]/10,r[i]%=10;//統一處理進位
    while(!r[i]) i--;//將整形陣列表示的商轉化成字串表示的
    while(i>=0) s+=r[i--]+'0';
    //cout<<s<<endl;
    i=tp;
    while(!a[i]) i--;//將整形陣列表示的餘數轉化成字串表示的</span>
    while(i>=0) v+=a[i--]+'0';
    if(v.empty()) v="0";
    //cout<<v<<endl;
    if(nn==1) return s;
    if(nn==2) return v;
}
int main()
{
    string a,b;
    while(cin>>a>>b){
        cout<<div(a,b,1)<<endl;
        cout<<div(a,b,2)<<endl;
    }
    return 0;
}

大數+ - *



#include<iostream>
#include<string>
#include<algorithm>
#include<sstream>
using namespace std;
//string轉換為int
int strint(string s) {
	int num;
	stringstream ss(s);
	ss >> num;
	return num;
}
//int轉換為string
string intstr(int num) {
	string s;
	stringstream ss;
	ss << num;
	ss >> s;
	return s;
}
//前置0 ,因為大數的長度必須要為2^n的倍數,才能劃分
void removePrezero(string &s) {
	if (s.length() == 1)return;
	int k = 0;
	for (int i = 0; i < s.length(); i++) {
		if (s[i] == '0')k++;
		else break;
	}
	if (k == s.length())s = "0";
	else s = s.substr(k);
}
//大數相加
string add(string s1, string s2) {
	string s = "";
	removePrezero(s1);	//去掉前置0
	removePrezero(s2);
	reverse(s1.begin(), s1.end()); //先把字串顛倒,方便相加
	reverse(s2.begin(), s2.end());
	int c = 0;
	for (int i = 0;c|| i < max(s1.length(), s2.length()); i++) {
		int t = c;
		if (i < s1.length())t += s1[i] - '0';
		if (i < s2.length())t += s2[i] - '0';
		int d = t % 10;
		s.insert(0, intstr(d));		
		c = t / 10;
	}
	return s;	
} 
//大數相減
string subtra(string &s1, string &s2) {
	string s = "";
	string flag;
	removePrezero(s1);	//去掉前置0
	removePrezero(s2);
	int len1 = s1.length();
	int len2 = s2.length();
	int len = len1>len2 ? len1 : len2;	
	if (len1 < len2)flag = "-";
	else if (len1 > len2)flag = "+";
	else {
		int i;
		for (i = 0; i < len1; i++) {
			if (s1.at(i) > s2.at(i)) {
				flag = "+";	 break;
			}
			else if (s1.at(i) < s2.at(i)) {
				flag = "-"; break;
			}
		}
		if (i == len1)s == "0";
	}
	int* num = (int*)malloc(sizeof(int)*len);
	reverse(s1.begin(), s1.end());	//方便相減
	reverse(s2.begin(), s2.end());
	int c = 0;
	for (int j = 0; j < len; j++) {
		int n1 = j < len1 ? s1[j] - '0' : 0;
		int n2 = j < len2 ? s2[j] - '0' : 0;
		if (flag == "+")num[c++] = n1 - n2;
		else num[c++] = n2 - n1;
	}
	for (int j = 0; j < c; j++) {
		if (num[j] < 0) {
			num[j] += 10; num[j + 1] -= 1;
		}
	}
	c--;
	while (num[c] == 0)c--;
	for (int j = 0; j <=c; j++){
		s.insert(0, intstr(num[j]));
	}
	if (flag == "-")return flag + s;
	else return s;
}
//增加前置0
void addPrezero(string &s, int L) {
	for (int i = 0; i < L; i++)
		s = s.insert(0, "0");
}
//增加後置0,大數*10^n	相當於在數的後面加n個0
string addLastzero(string s, int L) {
	string s1 = s;
	for (int i = 0; i < L; i++)
		s1 += "0";
	return s1;
}
//大數相乘
string multi(string &s1, string &s2) {
	bool flag1 = false, flag2 = false;	
	string sign;	 //作用是判斷結果是正數還是負數
	if (s1.at(0) == '-') {
		flag1 = true; s1 = s1.substr(1);
	}
	if (s1.at(0) == '-') {
		flag2 = true; s2 = s2.substr(1);
	}
	if (flag1&&flag2)sign = "+";
	else if (flag1 || flag2) sign = "-";
	else sign = "+";
	int L = 4;	 //將數前置若干個0,使其長度為2^n的倍數
	if (s1.length() > 2 || s2.length() > 2) {
		if (s1.length() >= s2.length()) {
			while (L < s1.length())L *= 2;
			if (L != s1.length()) 
		    addPrezero(s1, L - s1.length());
			addPrezero(s2, L - s2.length());				          
		}else {
			while (L < s2.length())L*=2;
			if (L != s2.length())
			addPrezero(s2, L - s2.length());
			addPrezero(s1, L - s1.length());
		}
	}
		if (s1.length() == 1)addPrezero(s1, 1);
		if (s2.length() == 1)addPrezero(s2, 1);
 
	int n = s1.length();
	string result, a0, a1, b0, b1;
	if (n > 1) {
		a1 = s1.substr(0, n / 2);
		a0 = s1.substr(n / 2, n);
		b1 = s2.substr(0, n / 2);
		b0 = s2.substr(n / 2, n);
	}
	if (n == 2) {
		int x1 = strint(a1);
		int x2 = strint(a0);
		int y1 = strint(b1);
		int y2 = strint(b0);
		int num = (x1 * 10 + x2)*(y1 * 10 + y2);
		result = intstr(num);
	}else {
		string c2 = multi(a1, b1);
		string c0 = multi(a0, b0);
		string temp1 = add(a0, a1);
		string temp2 = add(b1, b0);
		string temp3 = add(c2, c0);
		string temp_c1 = multi(temp1, temp2);
		string c1 = subtra(temp_c1, temp3);
		string s1 = addLastzero(c1, n / 2);
		string s2 =addLastzero(c2, n);
		result = add(add(s1, s2), c0);
	}
	if (sign == "-")result.insert(0, sign);
	return result;
}
int main() {
	//text
	string s1 = "-1234999999999999999999999", s2 = "12348976543";
	cout << multi(s1, s2);	
}

判斷大數是否為素數

#include<iostream>
#include<ctime>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn = 1000000+10;
ll mul(ll a, ll b, ll m)
//求a*b%m
{
    ll ans = 0;
    a %= m;
    while(b)
    {
        if(b & 1)ans = (ans + a) % m;
        b /= 2;
        a = (a + a) % m;
    }
    return ans;
}
ll pow(ll a, ll b, ll m)
//a^b % m
{
    ll ans = 1;
    a %= m;
    while(b)
    {
        if(b & 1)ans = mul(a, ans, m);
        b /= 2;
        a = mul(a, a, m);
    }
    ans %= m;
    return ans;
}
bool Miller_Rabin(ll n, int repeat)//n是測試的大數,repeat是測試重複次數
{
    if(n == 2 || n == 3)return true;//特判
    if(n % 2 == 0 || n == 1)return false;//偶數和1

    //將n-1分解成2^s*d
    ll d = n - 1;
    int s = 0;
    while(!(d & 1)) ++s, d >>= 1;
    srand((unsigned)time(NULL));
    for(int i = 0; i < repeat; i++)//重複repeat次
    {
        ll a = rand() % (n - 3) + 2;//取一個隨機數,[2,n-1)
        ll x = pow(a, d, n);
        ll y = 0;
        for(int j = 0; j < s; j++)
        {
            y = mul(x, x, n);
            if(y == 1 && x != 1 && x != (n - 1))return false;
            x = y;
        }
        if(y != 1)return false;//費馬小定理
    }
    return true;
}
int main()
{
    int T;
    cin >> T;
    ll n;
    while(T--)
    {
        cin >> n;
        if(Miller_Rabin(n, 50))cout<<"Yes"<<endl;
        else cout<<"No"<<endl;
    }
}

相關文章