找个时间整理一下代码,下次留着用,主要是大数乘法和大数除法的代码,坑了爹一个下午,很多的细节都疏忽了。
反转字符串函数,方便索引各位数:
void reverse(char * c) { int len = strlen(c); for(int i=0; i<len/2; i++) swap(c[i],c[len-i-1]); }
这样吧,计算机硬件里面有关于大端和小端的概念,这里引申一下,cin之后,大数是按大端法存储的(大数的高位存储在字符串的低位),同理,按照人们的阅读习惯,cout的大数也应该是大端法的(高位存储在字符串的低位)。但是做乘法的时候,为了操作方便,必须把大数改为小端法存储,也就是大数的低位存储在字符串的低位,这是因为乘法是从乘数的低位开始的。为了统一,规定srca和srcb两个乘数都是大端法的,也就是刚刚cin之后的状态,不用你做任何的动作,这都留给multiplication来处理,在做完乘法操作之后,要把srca和srcb都恢复原样。
srca和srcb都是大端法的字符串大数,所以在做乘法的时候要做翻转。
void multiplication(char * srca,char * srcb,char * dest)//未翻转 { int ia,ib,c, na = strlen(srca), nb = strlen(srcb); reverse(srca); reverse(srcb); for(ia=0; ia<na; ia++) { c = 0; for(ib=0; ib<nb; ib++) { int t = (srca[ia]-48) * (srcb[ib]-48) + c,tt; if(dest[ia+ib]>47) tt = dest[ia+ib]-48 + t; else tt = t; dest[ia+ib] = tt%10 +48; c = tt/10; }// for while(c) //处理进位,直到进位为0 { int t; if(dest[ia+ib]>47) t = dest[ia+ib] - 48 + c; else t = c; dest[ia+ib++] = t%10 + 48; c /= 10; }// while }// for //将两个乘数和乘积都改为大端法 reverse(dest); reverse(srca); reverse(srcb); }
除法有所不同的是,从被除数的高位开始处理,所以大端法就可以了,在division内部不用做任何的翻转。
void division(char * src,int n,char * dest) { int len = strlen(src), i, //计数 k, //商的下标 t = 0, //新的余数 s = 0; //余数 bool flag = true; //商是否有了第一个有效位,防止商首部一直出现0 for(i=0,k=0; i<len; i++) { t = s*10+(src[i]-48); //新余数 if(t/n>0 || t==0) //余数为0要修改商 dest[k++] = t/n+48,s = t%n,flag = false; else //不够除,修改余数 { s = t; if(!flag) //商已经有有效位了,补零 dest[k++] = '0'; }// if }// for //::memset(src,0,len); //memcpy(src,dest,strlen(dest)); }
本文完 2012-03-23
捣乱小子 http://blog.csdn.net/daoluanxiaozi