ACM_大数运算 模板&&讲解&&各大oj题目
2015-05-01 16:27
489 查看
///////////////////////////////////////////////////////////////////////////////////////////////////////
作者:tt2767
声明:本文遵循以下协议自由转载-非商用-非衍生-保持署名|Creative Commons BY-NC-ND 3.0
查看本文更新与讨论请点击:/article/1843639.html
链接被删请百度: CSDN t2767
///////////////////////////////////////////////////////////////////////////////////////////////////////
本模板的代码中,大数加,减,乘,除,求幂以及阶乘已经通过各大oj,取模算法暂时没有做到大数运算的题,但本地测试正确。
如果你还不太明白大数运算,建议你拿一张白纸边看边试一下,并且本方法默认大数字符串初始化为‘\0’。
一. 大数加法的原理
想象一下我们手算加法的时候怎么算?比如说678 + 78 ,开始算的时候是第一个数的个位 + 第二个数的个位,也就是8+8=16,结果中的个位是6,而1要进位进到十位上去,我们可以设一个变量carry来代表进位的值,由于单个数相加的最大值为9+9=18 所以carry的只能是1或0 。再向下看,个位算完了应该算十位了,由于个位有进位,所以计算十位时是carry+7+7 == 1+7+7 = 15,这时十位的值为5,1要进位,carry=1;最后看百位,我们手算的时候由于78没有百位的值所以百位的值为carry+6,但是计算机对齐的时候由于初始化为‘\0’所以百位对齐的值是‘\0‘会造成计算错误,所以,在大数相加的时候应该对较小的数补充前导0使两数位对齐。如果是999+999这种情况,要考虑新增的位数,所以我们把数组转置,让低位在前,高位在后计算。
二. 大数减法
与大数加法类似,只不过,不需要对齐数位,把进位改成借位了。
三. 大数乘法
大数乘法的实现要调用大数加法,想一下手算的时候怎么算??还是算678*78,手算的时候会先算8*678=5424,然后算7*678=4746,但是4746会错开一位去写,因为这里的7其实是70所以4746真实值为47460,然后把两个结果相加得到的最后乘法运算的结果为5424+47460 = 52884
四. 大数除法
(这里说的除法是一个较大的数除以较小的数,其它的都可以转化成这种算法或直接得出结果)
大数除法是这里最耗费时间,也是最复杂的算法了。
因为我们几乎无法去模拟真实的手算,因为无法试除,但想一想除法的本质,除法的本质其实就是多个减法,但如果我们循环相减的话实在太浪费时间了,计数就是一个麻烦的问题。
那要怎么办呢?仍然是对齐法,只不过这次我们把最高位对齐,其他位补0,就是相当于把除数乘以10的某次幂使数位对齐这样就减少了减法的次数,我们还可以继续优化,对齐之后乘以某个数使除数接近于被除数,大家可以试一下这个数最小是被除数的最高位除以除数最高位与1的和即 (a[0]-‘0’)/(b[0]-‘0’+1),而最大值为9,这样我们就能算出一个最接近与被除数的数,而除数乘上的这两个值(10的某次幂与这个数)相乘就是商的一部分,我们让被除数减去这个计算出来接近被除数的值,然后仍旧让原除数对齐,新被除数,依次循环直至运算结束,每次累加出来的和就是商。说着有些绕,大家手算一下就明白了。举个例子:8000/99,先对齐99→9900,然而8000-9900得0,结果累加为0 ,进行下一步,99→990,990乘以9~0之间某个值最接近8000,这个值为8,故为8000-990*8=80,商累加为0+8*10=80,新被除数为80,99→99,然而无法再减,最后结果为80.
五. 大数除一个整形数
完全模拟手算就可以,和大数加减差不多,主要为了特殊情况节约时间;
六. 大数幂
使用二分求幂的方法去计算,需要调用大数乘法,二分幂详见/article/2634872.html
七. 大数求模
大数求模,原理就是对每一位循环利用同余定理
如果 C = A + B
那么C % mod =( A % mod + B % mod)%mod 成立
八. 大数阶乘
这个输入一个整型数就可以了,输出结果为大数形式,按位计算,结果存在字符串中就好,类似于大数加减
九. 大数比较
大数比较就很简单了,主要了对比长度,然后从高位到低位对比每一位就好
十. 一些需要注意的事
每一个运算中都存在这WA点可能使你的程序得到错误的结果,看看你是否注意到了下面的一些情况?
1. 特殊值的处理:当值为0或1的时候怎么处理?正值与负值怎么处理?
2. 每次运算是否都把结果保存了下来?
3. 新运算之前是否清空了保存结果的缓存区?
4. 需不需要增加前导0?需不需要删去前导0?进位时怎么处理?
5. 是否破坏了原始数据,有没有把原始数据拷贝或还原?
6. 是否考虑了每一步计算对后面产生的影响?
如果你能处理好这些问题,那么大数计算对你来说就不是问题了
大家可以先写一写自己的算法,然后按照后边的题自己测试一下,你写的正确与否,再查看模板,模板中已经详细注释了,请仔细查看!
各大OJ上的练习题:
1.大数的加减乘除
加:hdu 1002A+B Problem II http://acm.hdu.edu.cn/showproblem.php?pid=1002
减:百炼2736 http://bailian.openjudge.cn/practice/2736/
乘:百炼2980 http://bailian.openjudge.cn/practice/2980/
除:百炼2737 http://bailian.openjudge.cn/practice/2737/
除法把主程序改成这样,其他的直接输入输出就好~
2.hdu 1042 N!
http://acm.hdu.edu.cn/showproblem.php?pid=1042
把模版里的主程序改成这样就过了 =。=
3.poj3982 序列
http://poj.org/problem?id=3982
再把主程序改成这样 =。=
4 . NYOJ 73 比大小
http://acm.nyist.net/JudgeOnline/problem.php?pid=73
改主程序。。。。。
5.NYOJ 45 棋盘覆盖 (递推 + 大数)
http://acm.nyist.net/JudgeOnline/problem.php?pid=45
可以算出公式为 f[i] = 4 * f[i-1] + 1,用大数打个表加快速度
套用模板后,增加增加代表4和0的大数并修改主程序:
6.hdu 1047 多组大数相加
http://acm.hdu.edu.cn/showproblem.php?pid=1047
这题表达的很乱,大致意思就是先输入一个整数代表数据组数,每组数据由0结尾,注意的是0后必有结果而且输出之间要有空行
这个模板因为是所以计算函数共用一个数组保存结果,故每以一计算都需要把结果保存下来!
7 . hdu1715 大菲波数
http://acm.hdu.edu.cn/showproblem.php?pid=1715
这个题和上边那个“棋盘覆盖”的题是一样的,只不过递推公式变了,其实还能更快求更大的斐波那契数(一亿多),只不过那需要用到矩阵递推了。
下面是我的模板,讲解都在注释里面了,仔细看!
作者:tt2767
声明:本文遵循以下协议自由转载-非商用-非衍生-保持署名|Creative Commons BY-NC-ND 3.0
查看本文更新与讨论请点击:/article/1843639.html
链接被删请百度: CSDN t2767
///////////////////////////////////////////////////////////////////////////////////////////////////////
本模板的代码中,大数加,减,乘,除,求幂以及阶乘已经通过各大oj,取模算法暂时没有做到大数运算的题,但本地测试正确。
如果你还不太明白大数运算,建议你拿一张白纸边看边试一下,并且本方法默认大数字符串初始化为‘\0’。
一. 大数加法的原理
想象一下我们手算加法的时候怎么算?比如说678 + 78 ,开始算的时候是第一个数的个位 + 第二个数的个位,也就是8+8=16,结果中的个位是6,而1要进位进到十位上去,我们可以设一个变量carry来代表进位的值,由于单个数相加的最大值为9+9=18 所以carry的只能是1或0 。再向下看,个位算完了应该算十位了,由于个位有进位,所以计算十位时是carry+7+7 == 1+7+7 = 15,这时十位的值为5,1要进位,carry=1;最后看百位,我们手算的时候由于78没有百位的值所以百位的值为carry+6,但是计算机对齐的时候由于初始化为‘\0’所以百位对齐的值是‘\0‘会造成计算错误,所以,在大数相加的时候应该对较小的数补充前导0使两数位对齐。如果是999+999这种情况,要考虑新增的位数,所以我们把数组转置,让低位在前,高位在后计算。
二. 大数减法
与大数加法类似,只不过,不需要对齐数位,把进位改成借位了。
三. 大数乘法
大数乘法的实现要调用大数加法,想一下手算的时候怎么算??还是算678*78,手算的时候会先算8*678=5424,然后算7*678=4746,但是4746会错开一位去写,因为这里的7其实是70所以4746真实值为47460,然后把两个结果相加得到的最后乘法运算的结果为5424+47460 = 52884
四. 大数除法
(这里说的除法是一个较大的数除以较小的数,其它的都可以转化成这种算法或直接得出结果)
大数除法是这里最耗费时间,也是最复杂的算法了。
因为我们几乎无法去模拟真实的手算,因为无法试除,但想一想除法的本质,除法的本质其实就是多个减法,但如果我们循环相减的话实在太浪费时间了,计数就是一个麻烦的问题。
那要怎么办呢?仍然是对齐法,只不过这次我们把最高位对齐,其他位补0,就是相当于把除数乘以10的某次幂使数位对齐这样就减少了减法的次数,我们还可以继续优化,对齐之后乘以某个数使除数接近于被除数,大家可以试一下这个数最小是被除数的最高位除以除数最高位与1的和即 (a[0]-‘0’)/(b[0]-‘0’+1),而最大值为9,这样我们就能算出一个最接近与被除数的数,而除数乘上的这两个值(10的某次幂与这个数)相乘就是商的一部分,我们让被除数减去这个计算出来接近被除数的值,然后仍旧让原除数对齐,新被除数,依次循环直至运算结束,每次累加出来的和就是商。说着有些绕,大家手算一下就明白了。举个例子:8000/99,先对齐99→9900,然而8000-9900得0,结果累加为0 ,进行下一步,99→990,990乘以9~0之间某个值最接近8000,这个值为8,故为8000-990*8=80,商累加为0+8*10=80,新被除数为80,99→99,然而无法再减,最后结果为80.
五. 大数除一个整形数
完全模拟手算就可以,和大数加减差不多,主要为了特殊情况节约时间;
六. 大数幂
使用二分求幂的方法去计算,需要调用大数乘法,二分幂详见/article/2634872.html
七. 大数求模
大数求模,原理就是对每一位循环利用同余定理
如果 C = A + B
那么C % mod =( A % mod + B % mod)%mod 成立
八. 大数阶乘
这个输入一个整型数就可以了,输出结果为大数形式,按位计算,结果存在字符串中就好,类似于大数加减
九. 大数比较
大数比较就很简单了,主要了对比长度,然后从高位到低位对比每一位就好
十. 一些需要注意的事
每一个运算中都存在这WA点可能使你的程序得到错误的结果,看看你是否注意到了下面的一些情况?
1. 特殊值的处理:当值为0或1的时候怎么处理?正值与负值怎么处理?
2. 每次运算是否都把结果保存了下来?
3. 新运算之前是否清空了保存结果的缓存区?
4. 需不需要增加前导0?需不需要删去前导0?进位时怎么处理?
5. 是否破坏了原始数据,有没有把原始数据拷贝或还原?
6. 是否考虑了每一步计算对后面产生的影响?
如果你能处理好这些问题,那么大数计算对你来说就不是问题了
大家可以先写一写自己的算法,然后按照后边的题自己测试一下,你写的正确与否,再查看模板,模板中已经详细注释了,请仔细查看!
**模板在最后,详细解析在模板的注释里面!!**
各大OJ上的练习题:
1.大数的加减乘除
加:hdu 1002A+B Problem II http://acm.hdu.edu.cn/showproblem.php?pid=1002
减:百炼2736 http://bailian.openjudge.cn/practice/2736/
乘:百炼2980 http://bailian.openjudge.cn/practice/2980/
除:百炼2737 http://bailian.openjudge.cn/practice/2737/
除法把主程序改成这样,其他的直接输入输出就好~
int main() { char a = {'\0'},b ={'\0'}; int n; scanf("%d",&n); while(n--) { scanf("%s%s",a,b); puts(BigDivBig(a,b)); } return 0; }
2.hdu 1042 N!
http://acm.hdu.edu.cn/showproblem.php?pid=1042
把模版里的主程序改成这样就过了 =。=
int main() { int n; while(~scanf("%d",&n)) { puts(BigFuc(n)); } return 0; }
3.poj3982 序列
http://poj.org/problem?id=3982
再把主程序改成这样 =。=
int main() { char ans[105] = {'\0'}; char temp ={'\0'}; int n,i; while(~scanf("%s%s%s",ans[0],ans[1],ans[2])) { for(i = 3 ; i <=99 ; i++) { strcpy(temp,BigAdd(ans[i-3],ans[i-2])); strcpy(ans[i],BigAdd(temp,ans[i-1])); } puts(ans[99]); } return 0; }
4 . NYOJ 73 比大小
http://acm.nyist.net/JudgeOnline/problem.php?pid=73
改主程序。。。。。
int main() { char a = {'\0'},b ={'\0'}; int n; while(scanf("%s%s",a,b)) { n = BigCmp(a,b); if(n == 0 && a[0] == '0' && b[0] == '0') break; if(n == 0) puts("a==b"); else if(n == 1) puts("a<b"); else puts("a>b"); } return 0; }
5.NYOJ 45 棋盘覆盖 (递推 + 大数)
http://acm.nyist.net/JudgeOnline/problem.php?pid=45
可以算出公式为 f[i] = 4 * f[i-1] + 1,用大数打个表加快速度
套用模板后,增加增加代表4和0的大数并修改主程序:
int main() { char four[2] = {'4','\0'};//增加代表4和0的大数 char one[2] = {'1','\0'}; char ans[105] = {'\0'}; char temp ={'\0'}; int n,i,k,Case; ans[1][0] = '1'; ans[1][1] = '\0'; for(i = 2 ; i <= 100 ; i++) { strcpy(temp,BigMul(ans[i-1],four)); strcpy(ans[i],BigAdd(temp,one)); } scanf("%d",&Case); while(Case--) { scanf("%d",&k); puts(ans[k]); } return 0; }
6.hdu 1047 多组大数相加
http://acm.hdu.edu.cn/showproblem.php?pid=1047
这题表达的很乱,大致意思就是先输入一个整数代表数据组数,每组数据由0结尾,注意的是0后必有结果而且输出之间要有空行
这个模板因为是所以计算函数共用一个数组保存结果,故每以一计算都需要把结果保存下来!
int main() { char a = {'\0'},ans = {'\0'}; int Case; int i,j; scanf("%d",&Case); while(Case--) { ans[0] = '0'; ans[1] = '\0'; while(~scanf("%s",a)) { if(strlen(a) == 1 && a[0] == '0') break; strcpy(ans,BigAdd(a,ans)); } puts(ans); if(Case>0) puts(""); } return 0; }
7 . hdu1715 大菲波数
http://acm.hdu.edu.cn/showproblem.php?pid=1715
这个题和上边那个“棋盘覆盖”的题是一样的,只不过递推公式变了,其实还能更快求更大的斐波那契数(一亿多),只不过那需要用到矩阵递推了。
下面是我的模板,讲解都在注释里面了,仔细看!
#include<stdio.h>//不能连续复合运算,要保存结果 #include<stdlib.h>//所以一个技巧就是用strcpy来代替等号 #include<string.h>//c=a+b改写为strcpy(c,BigAdd(a,b)) #define BASE 10 //确定进制 #define N 90001 //确定 最大位数+1 int l = 0; //每次记录缓存区用了多长,还原时节省时间 char res = { '\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 = {'\0'},b ={'\0'}; int n; while(~scanf("%s%s%d",a,b,&n)) { puts("a + b得:"); puts(BigAdd(a,b)); puts("a - b 得:"); puts(BigSub(a,b)); puts("a * b 得:"); puts(BigMul(a,b)); puts("a / b 得:"); puts(BigDivBig(a,b)); puts("a / n 得:"); puts(BigDivNum(a,n)); puts("a^n 得:"); puts(BigPow(a,n)); puts("a % n 得:"); puts(BigMod(a,n)); puts("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 = {'\0'},cal = {'\0'},num = {'\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 = {'\0'},num = {'\0'},now = {'\0'},tran = {'\0'}; char mul = {'\0'},sub = {'\0'},div ={'\0'}; char carry = {'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 = {'\0'},pow = {'\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; } }
相关文章推荐
- ACM: 大数运算(正整数)
- ACM~大数加法&&hdu题目样例
- 类模板&结构体模板的new运算
- ACM各题型OJ题目总结
- 浙大OJ网址及ACM题目分类
- ACM: 数论 台州OJ 3151 (久违的数…
- LeetCode|【模拟大数的运算题目汇总】
- ACM学习历程—HDU1041 Computer Transformation(递推 && 大数)
- 整理:ACM相关好的网站 && OJ && Blog (不断更新)
- (高精度运算4.7.27)UVA 10494 If We Were a Child Again(大数除法&&大数取余)
- 大数的任意进制之间的转换(九度OJ题目1080)
- 【转载】北大acm&nbsp;题目分类
- 华为OJ题目:24点运算
- ACM: 水题 分数运算 poj 3979
- <九度 OJ>题目1028:继续畅通工程
- 杭电acm 1297 Children's Queue.大数加递归
- 大数的加法运算,杭电oj-1002
- SDUT 选夫婿1 http://acm.sdut.edu.cn/sdutoj/showproblem.php?pid=1569&cid=1211
- ACM 第一天 大数运算
- ACM学习历程—HDU 3092 Least common multiple(数论 && 动态规划 && 大数)