C++ 大数模板
#include<stdio.h>//不能连续复合运算,要保存结果 #include<stdlib.h>//所以一个技巧就是用strcpy来代替等号 #include<string.h>//c=a+b改写为strcpy(c,BigAdd(a,b)) #include <iostream> using namespace std; #define BASE 10 //确定进制 #define N 90001 //确定 最大位数+1 int l = 0; //每次记录缓存区用了多长,还原时节省时间 char res[N] = { '\0' }; //保存结果 void ini(char * x , int l); //初始化x数组 int BigCmp(char * a, char * b); // 大数a < 大数b 返回1 ,相等返回0 ,a>b返回-1 void Clean(char * x, int l);//清除尾部的‘0’ void rev(char * x);//倒置字符串 ,与Clean联用,清除前导0 char * BigAdd(char * a, char * b); char * BigSub(char * a,char * b); char * BigMul(char * a,char * b); char * BigDivNum(char * num,int n);//大数除以一个int char * BigDivBig(char * a,char * b);//大数除以一个大数 char * BigPow(char *num ,int n); char * BigMod(char * num , int mod); char * BigFuc(int num); int main() { char a[N] = {'\0'},b[N]={'\0'}; int n; while(~scanf("%s%s%d",a,b,&n)) { cout<<"a+b="<<" "; puts(BigAdd(a,b)); cout<<"a-b="<<" "; puts(BigSub(a,b)); cout<<"a*b="<<" "; puts(BigMul(a,b)); cout<<"a/b="<<" "; puts(BigDivBig(a,b)); cout<<"a/n="<<" "; puts(BigDivNum(a,n)); cout<<"a^n="<<" "; puts(BigPow(a,n)); cout<<"a%n="<<" "; puts(BigMod(a,n)); cout<<"n!="<<" "; puts(BigFuc(n)); puts(""); } return 0; } char * BigAdd( char * a, char * b) { int i,j,k; int sum,la,lb,carry,flag,cmp; char *ans,*temp; ini(res,l); carry = 0; flag = 0; ans = &res[1]; if(a[0] == '-' && b[0] != '-') //判断正负 return BigSub(b,a+1); else if(a[0] != '-' && b[0] == '-') return BigSub(a,b+1); else if(a[0] == '-' && b[0] == '-') { flag = 1; a++; b++; } la=strlen(a); lb=strlen(b); if(b[0] == '0' && lb == 1) //判断0 { strcpy(ans,a); l = strlen(ans); return ans; } else if(a[0] == '0' && la ==1) { strcpy(ans,b); l = strlen(ans); return ans; } rev(a); rev(b); if(BigCmp(a,b) == 1) //保持大数a>大数b { temp = a; a = b; b =temp; k = la; la = lb; lb = k; } for(i = lb ; i < la ; i++) //空位补0 b[i] = '0'; for(i = 0 ; i < la ; i++) { sum = (a[i]-48) + (b[i]-48) + carry; if( sum < BASE ) { ans[i] = sum + 48; carry = 0; } else { ans[i] = sum - BASE + 48; carry = 1; } } if(carry) //补充最高位 { ans[i] = carry + 48; i++; } Clean(ans,i); for(i = lb ; i < la ; i++)//删除后补上的0 b[i] = '\0'; rev(ans); rev(a); rev(b); if(flag) { res[0] = '-'; ans = res; } l = strlen(ans); return ans; } char * BigSub(char * a,char * b) { char *ans,*temp; int i,j,k; int borrow,flag,la,lb,sub,cmp; ini(res,l); ans = &res[1]; flag = 0; //结果没有负号 borrow = 0; if(a[0]=='-' && b[0]!='-') //被减数为负,减数为正,结果为负 { BigAdd(b,a+1); res[0] = '-'; return res; } else if(a[0]!='-' && b[0]=='-') //被减数为正,减数为负,结果为正 return BigAdd(a,b+1); else if(a[0]=='-' && b[0]=='-') //如果a,b为同时负,交换他们并都改为正,保证为“a-b”的形式 { temp=a; a=b; b=temp; a++; b++; } la = strlen(a); lb = strlen(b); if(b[0] == '0' && lb == 1) //判断0 { l = strlen(strcpy(ans,a)); return ans; } else if(a[0] == '0' && la == 1) { if(b[0] == '-') { l = strlen(strcpy(ans,b+1)); return ans; } else { res[0] = '-'; l = strlen(strcpy(ans,b)); return res; } } cmp = BigCmp(a,b); if(cmp == 0) { l = 1; res[0] = '0'; res[1] = '\0'; return res; } else if(cmp == 1) //保持大数a>=大数b { temp=a; a=b; b=temp; flag=1; //结果有负号 k = la; la = lb; lb = k; } rev(a); rev(b); for(i=0; i<lb ; i++) { sub = a[i] - borrow - b[i]; if( sub >= 0) { ans[i] = sub + 48; borrow = 0 ; } else // 溢出时的计算方法 { ans[i] = sub + BASE + 48; borrow = 1; } } while(i < la) // 计算剩余位 { sub = a[i] - borrow ; if(a[i] >= borrow) { ans[i] = sub ; borrow = 0; } else // 溢出时的计算方法 { ans[i] = sub +BASE ; borrow = 1; } i++; } Clean(ans,i); rev(ans); rev(a); rev(b); if(flag) { res[0] = '-'; ans = res; } l = strlen(ans); return ans; } char * BigMul(char * a,char * b) { char *temp,*ans; char mul[N] = {'\0'},cal[N] = {'\0'},num[N] = {'\0'}; int i,j,k; int carry,flag,la,lb,product,lmul; int sign,sign_a,sign_b; ini(res,l); ans = &res[1]; carry = 0; flag = 0; sign = sign_a = sign_b = 0; if(a == b) //重复拷贝 b = strcpy(num,a); if(a[0] == '-' ) { flag = 1; sign_a = 1; a++; } if(b[0] == '-' ) { flag = 1; sign_b = 1; b++; } if(sign_a && sign_b) flag = 0; la = strlen(a); lb = strlen(b); if((a[0] == '0' && la == 1) || (b[0] == '0' && lb == 1)) //任何一个大数为0,结果为0 { l = 1; res[0] = '0'; res[1] = '\0'; return res; } if(BigCmp(a,b) == 1) //保证大数a >= 大数b { temp = a; a = b ; b = temp; k = la; la = lb; lb =k; } rev(a); rev(b); Clean(a,la);//清除自带的前导0 Clean(b,lb); la = strlen(a);//重新计算长度 lb = strlen(b); lmul = 0; for(i = 0 ; i < lb ; i++) { ini(mul,lmul); for( j = 0 ; j < la ; j++) { product = (a[j] - 48) * (b[i] - 48) + carry ; mul[j] = product % BASE + 48 ; carry = product / BASE ; } if(carry) { mul[j] = carry + 48; j++; carry = 0; } lmul = j; //计算缓冲区长度 if(i == 0) { strcpy(cal,mul); rev(cal); } else { //清除前导0 Clean(mul,lmul); //翻转字符串 rev(mul); //以0补位,每次相当于乘10 for(k = 0 ; k < i ;k++) mul[lmul++] = '0'; //保存 ans = BigAdd(cal,mul); ini(cal,strlen(cal)); strcpy(cal,ans); } } strcpy(ans,cal); rev(a); rev(b); if(flag) { res[0] = '-'; ans = res; } l = strlen(ans); return ans; } char * BigDivBig(char * a,char * b) { char *ans, *temp; int i,j,k,la,lb,cmp,times,tran_min; int sign,sign_a,sign_b,flag; ini(res,l); ans = &res[1]; sign_a = sign_b = flag = 0; if(a[0] == '-') { sign_a = flag = 1; a++; } if(b[0] == '-') { sign_b = flag = 1; b++; } if(sign_a && sign_b) flag = 0; la = strlen(a); lb = strlen(b); rev(a); rev(b); Clean(a,la); Clean(b,lb); rev(a); rev(b); la = strlen(a); lb = strlen(b); if(la == 1 && a[0] == '0') { l = 1; res[0] = '0'; res[1] = '\0'; return res; } if(lb == 1 && b[0] == '0') { puts("除数不能为0!"); exit(1); } if(lb == 1 && b[0] == '1') { l = strlen(strcpy(res,a)); return res; } cmp = BigCmp(a,b); if(cmp == 1) { l = 2; ans[0] = '0'; ans[1] = '\0'; return ans; } else if(cmp == 0) { l = 2; ans[0] = '1'; ans[1] = '\0'; if(flag) { res[0]='-'; ans = res; } return ans; } ///对齐最高位试除 char pre[N] = {'\0'},num[N] = {'\0'},now[N] = {'\0'},tran[N] = {'\0'}; char mul[N] = {'\0'},sub[N] = {'\0'},div[N]={'\0'}; char carry[N] = {'0'};///注意是 0 memset(carry,'0',sizeof(carry)); now[0] = '0'; //大数now初始化为0 carry[0] = '1';//大数carry初始化为1000000000…… times = la - lb;//确定最高倍数 strcpy(num,a); //复制a的值 strcpy(div,b);//复制b的值 for(i = 0 ; i < times ; i++) //对齐最高位 div[lb+i] = '0'; for(i = times ; i >= 0 ;i--) { //最小的倍数为:a最高位/(b最高位+1),试一下就知道了 tran_min = (num[0] - '0')/(div[0]-'0'+1); ///????? for(j = 9 ; j >= tran_min ; j--) { sprintf(tran,"%d",j); //把试乘值转换成字符串 strcpy(pre,BigMul(div,tran)); strcpy(sub,BigSub(num,pre)); //sub = a - b*j; //从大到小找第一个可以被减的数 if(sub[0] != '-') { carry[i+1] = '\0'; //截断carry得到倍数 strcpy(mul,BigMul(carry,tran));//乘上这次的值 strcpy(now,BigAdd(now,mul));//将商保存在now中 strcpy(num,sub); //更新a的值 break; } } div[lb+i-1] = '\0'; //每次循环降低一位直至复原 memset(res,'\0',sizeof(res)); } strcpy(ans,now); if(flag) { res[0] = '-'; ans = res; } l = strlen(ans); return ans; } char * BigDivNum(char * num , int n) { char * ans; int i,j,digit,divis,lnum,flag; int sign_num,sign_n; ini(res,l); ans = &res[1]; digit = divis = flag = 0; sign_num = sign_n = 0; if(n == 0) { puts("除数不能等于0"); exit(1); } if(n < 0) { n = -n; flag = 1; sign_n = 1; } if(num[0] == '-') { num++; flag = 1; sign_num = 1; } if(sign_n && sign_num) flag = 0; lnum = strlen(num); if(lnum == 1 && num[0] == '0') { l = 1; res[0] = '0'; res[1] = '\0'; return res; //被除数为0,结果为0 } for(i = 0 ; i < lnum ; i++) { divis = divis * 10 + (num[i]-48) ; if(divis >= n) { ans[digit++] = divis / n + 48; divis %= n; } } if(!digit) ans[digit++] = '0'; ans[digit] = '\0'; if(flag) { res[0] = '-'; ans = res; } l = strlen(ans); return ans; } char * BigPow(char * num, int n) { char * ans; char cal[N] = {'\0'},pow[N] = {'\0'}; int flag; if(n == 0) { l = 1; res[0] = '1'; res[1] = '\0'; return res; } if(strlen(num) == 1 && num[0] == '0') { l = 1; res[0] = '0'; res[1] = '\0'; return res; } ini(res,l); ans = &res[1]; flag = 0; strcpy(pow,num); //备份 cal[0] = '1'; if(pow[0] == '-' && n&1) flag = 1; while(n) { if(n&1) { ans = BigMul(cal,num); ini(cal,strlen(cal)); strcpy(cal,ans); } ans = BigMul(num,num); ini(num,strlen(num)); strcpy(num,ans); n >>= 1; } strcpy(num,pow); //还原 strcpy(ans,cal); if(flag) { res[0] = '-'; ans = res; } l = strlen(ans); return ans; } char * BigMod(char * num , int mod) { char * ans; int i,lnum,cal; if(mod == 0) { puts("除数不能等于0"); exit(1); } ini(res,l); ans = &res[1]; cal = 0; lnum = strlen(num); for(i = 0 ; i < lnum ; i++) //循环利用同余定理 cal = ( ((cal*BASE)%mod) + ((num[i]-48)%mod) ) % mod ; sprintf(ans,"%d",cal); //转换为字符串 l = strlen(ans); return ans; } char * BigFuc(int num) { int i,j,k; int digit,carry,temp; char * ans; ini(res,l); ans = &res[1]; if(num == 0) { l = 1; res[0] = '1'; res[1] = '\0'; return res; } ans[0] = '1'; digit = 1; for(i = 2 ; i <= num ; i++) { carry = 0; //初始化为0 for(j = 0 ; j < digit ; j++) { temp = (ans[j]-48)* i + carry; //中间值 ans[j] = temp % BASE +48 ; carry = temp / BASE; } while(carry) //处理剩余位数 { ans[digit++] = carry % BASE + 48; carry /= BASE ; } } rev(ans); l = strlen(ans); return ans; } int BigCmp(char * a, char * b) // 大数a < 大数b 返回1 ,相等返回0 ,a>b返回-1 { int i,j,k; int la = strlen(a),lb = strlen(b); char * temp; if(a[0] == '-' && b[0] != '-') return 1; else if(a[0] != '-' && b[0] == '-') return -1; else if(a[0] == '-' && b[0] == '-') { a++; b++; temp = a; a = b; b = temp; la--; lb--; k = la; la =lb; lb = k; } if(la < lb) return 1; if(la > lb) return -1; if(la == lb) { for(i = 0 ; i < la ; i++) { if(a[i] < b[i]) return 1; else if(a[i] > b[i]) return -1; } } return 0; } void ini(char * x ,int l) { int i; if(l < N) l++; for(i = 0 ; i < l ;i++) x[i] = '\0'; } void Clean(char * x,int l) { for(l--; x[l] == '0';l--) x[l] = '\0'; } void rev(char * x) { int right = strlen(x)-1; int left = 0; char temp; while(left < right) { temp = x[left]; x[left++] = x[right]; x[right--] = temp; } }
每一个不曾刷题的日子
都是对生命的辜负
从弱小到强大,需要一段时间的沉淀,就是现在了
~buerdepepeqi