第一种方法解题思路
这是2012年蓝桥杯全国软件大赛预赛(C++本科组)第6题,有图片可知是个简单的大数计算的问题。
对于32位字长的机器,大约超过20亿,用int类型就无法表示了,我们可以选择int64类型,但无论怎样扩展,固定的整数类型总是有表达的极限!如果对超级大整数进行精确运算呢?一个简单的办法是:仅仅使用现有类型,但是把大整数的运算化解为若干小整数的运算,即所谓:“分块法”。
如图【1.jpg】表示了分块乘法的原理。可以把大数分成多段(此处为2段)小数,然后用小数的多次运算组合表示一个大数。可以根据int的承载能力规定小块的大小,比如要把int分成2段,则小块可取10000为上限值。注意,小块在进行纵向累加后,需要进行进位校正。
# include <stdio.h> void bigmul(int x, int y, int r[]) { int base = 10000; int x2 = x / base; int x1 = x % base; int y2 = y / base; int y1 = y % base; int n1 = x1 * y1; int n2 = x1 * y2; int n3 = x2 * y1; int n4 = x2 * y2; r[3] = n1 % base; r[2] = n1 / base + n2 % base + n3 % base; r[1] = n2 / base + n3 / base + n4 % base; // 填空 r[0] = n4 / base; r[1] += r[2] / base; // 填空 r[2] = r[2] % base; r[0] += r[1] / base; r[1] = r[1] % base; } int main(int argc, char* argv[]) { int x[] = {0,0,0,0}; bigmul(87654321, 12345678, x); printf("%d%d%d%d\n", x[0],x[1],x[2],x[3]); return 0; }
第二种方法,对数据的长度没有任何限制
#include <stdio.h> #include <stdlib.h> #include <string.h> #define N 100 /* *将在数组中保存的字符串转成数字存到int数组中 */ void getdigits(int *a,char *s){ int i; char digit; int len = strlen(s); //对数组初始化 for(i = 0; i < N; ++i) *(a + i) = 0; for(i = 0; i < len; ++i){ digit = *(s + i); //字符串s="12345",因此第一个字符应该存在int数组的最后一个位置 *(a + len - 1 - i) = digit - '0'; } } /* *将数组a与数组b逐位相乘以后存入数组c */ void multiply(int *a,int *b,int *c) { int i,j; //数组初始化 for(i = 0; i < 2 * N; ++i) *(c + i) = 0; /* *数组a中的每位逐位与数组b相乘,并把结果存入数组c *比如,12345*12345,a中的5与12345逐位相乘 *对于数组c:*(c+i+j)在i=0,j=0,1,2,3,4时存的是5与各位相乘的结果 *而在i=1,j=0,1,2,3,4时不光会存4与各位相乘的结果, *还会累加上上次相乘的结果.这一点是需要注意的!!! */ for(i = 0; i < N; ++i) for(j = 0; j < N; ++j) *(c + i + j) += *(a + i) * *(b + j); /* *这里是移位、进位 */ for(i = 0; i < 2 * N - 1; ++i){ *(c + i + 1) += *(c + i)/10;//将十位上的数向前进位,并加上原来这个位上的数 *(c + i) = *(c + i)%10;//将剩余的数存原来的位置上 } } int main() { int a[N],b[N],c[2*N]; char s1[N],s2[N]; int j = 2*N-1; int i; printf("input the first number:"); scanf("%s",s1); printf("/ninput the second number:"); scanf("%s",s2); getdigits(a,s1); getdigits(b,s2); multiply(a,b,c); while(c[j] == 0) j--; for(i = j;i >= 0; --i) printf("%d",c[i]); printf("/n"); return 0; }
第三种方法,没怎么看懂
/** 语法:mult(char a[],char b[],char s[]); 参数:a[]:被乘数,用字符串表示,位数不限 b[]:乘数,用字符串表示,位数不限 t[]:结果,用字符串表示 返回值:null 注意:空间复杂度为 o(n^2) 需要 string.h */ void mult(char a[],char b[],char s[]) { int i,j,k=0,alen,blen,sum=0,res[65][65]={0},flag=0; char result[65]; alen=strlen(a);blen=strlen(b); for (i=0;i<alen;i++) for (j=0;j<blen;j++) res[i][j]=(a[i]-'0')*(b[j]-'0'); for (i=alen-1;i>=0;i--) { for (j=blen-1;j>=0;j--) sum=sum+res[i+blen-j-1][j]; result[k]=sum%10; k=k+1; sum=sum/10; } for (i=blen-2;i>=0;i--) { for (j=0;j<=i;j++) sum=sum+res[i-j][j]; result[k]=sum%10; k=k+1; sum=sum/10; } if (sum!=0) {result[k]=sum;k=k+1;} for (i=0;i<k;i++) result[i]+='0'; for (i=k-1;i>=0;i--) s[i]=result[k-1-i]; s[k]='\0'; while(1) { if (strlen(s)!=strlen(a)&&s[0]=='0') strcpy(s,s+1); else break; } }