- 注册时间
- 2010-2-12
- 最后登录
- 1970-1-1
- 威望
- 星
- 金币
- 枚
- 贡献
- 分
- 经验
- 点
- 鲜花
- 朵
- 魅力
- 点
- 上传
- 次
- 下载
- 次
- 积分
- 1214
- 在线时间
- 小时
|
楼主 |
发表于 2015-2-16 23:11:40
|
显示全部楼层
本帖最后由 只是呼吸 于 2015-2-17 00:11 编辑
根据liangbch的建议,我把程序作了修改。修改后的程序能处理任意两个不超过8000位数(十进制数)的整数除法。由于增加了从屏幕输入的语句,所以程序太长,不清晰,只好分成两部分:前一部分把屏幕输入的字符转化为数组,后一部分把数组相除得到结果。程序中给出全部注释。给出笔算除法的实现步骤。
笔算除法的实现步骤:
1) 输入字符串a
2)输入字符串b
3)转化字符串a为被除数数组A,每4个数字为一组,(万进制)
4)转化字符串b为除数数组B,每4个数字为一组,但第一个元素B[0]必须是5位十进制数。
5)除法开始:
6)求试商:n=(A[0]*10000+A[1])/B[0]
7)做乘法:C=B*n
8)做减法:D=A-C
9)判断:if(D>=0)
则n就是准确商。
10)把余数D和未参与计算的A组成新的A
11)if(D<0)
则n-1就是准确商。
12)做加法,D=D+B (把负的余数转变为正的)
13)把余数D和未参与计算的A组成新的A
14)返回5
15)程序结束,输出商和余数。
我用的是vc++6.0,采用分别编译的方式,给出商和余数。
- #include <stdio.h>
- #include <string.h>
- int main()
- {
- extern void BigDigit_DIV(int *dividend,int LENdividend, int *divR,int LENdivR,int AddZero); //外部函数,函数功能:将两个数相除得到结果
- void string_digitArray(char *a,char *b,int *ArrayA,int *ArrayB,int *LEN_A,int *LEN_B,int *Add_Zero);//内部函数,函数功能:将两个字符串转化为数组
- int digit_control(char a[]); //内部函数,函数功能:控制数字规模
- int count_zero(char b[]); //内部函数,函数功能:统计0的个数
- void Vary(char a[],int pr[],int AddZero); //内部函数,函数功能:转化字符串为数组
- int ArrayA[2010]={0}; //被除数
- int ArrayB[2010]={0}; //除数
- int quotient[2010]={0}; //商
- //int rm[2010]={0}; //余数
- int LEN_ArrayA,LEN_ArrayB,AddZero;
- int *LEN_A,*LEN_B,*Add_Zero;
- char a[10010];
- char b[10010];
- LEN_A=&LEN_ArrayA;
- LEN_B=&LEN_ArrayB;
- Add_Zero=&AddZero;
- string_digitArray(a,b,ArrayA,ArrayB,LEN_A,LEN_B,Add_Zero);//把字符串a,b,转化为数字数组ArrayA,ArrayB,并返回数组的最大下标,每个元素中存4个十进制数字。
- BigDigit_DIV(ArrayA,LEN_ArrayA,ArrayB,LEN_ArrayB,AddZero);
- return 0;
- }
- void Vary(char dm[],int kk[],int ss,int yy) //转化字符串A为数组存入kk[]中
- {
- int r,s,kd;
- r=0;
- if (yy==0)
- {
- for(s=0;s<=ss;s++,r+=4)
- kk[s]=dm[r]*1000+dm[r+1]*100+dm[r+2]*10+dm[r+3]-53328;
- }
- else
- {
- for (kd=0;kd<=yy-2;kd++)
- {
- kk[0]+=dm[kd]-48;
- kk[0]*=10;
- }
- kk[0]+=dm[yy-1]-48;
- for(s=1;s<=ss;s++,yy+=4)
- kk[s]=dm[yy]*1000+dm[yy+1]*100+dm[yy+2]*10+dm[yy+3]-53328;
- }
- }
- int count_zero(char b[])
- {
- int j,s;
- j=strlen(b);
- s=0;
- while(b[s]=='0')//找出除数中第一个非零的数的位置
- s++;
- j=j-s;//求出非零的实际长度。
- return j;
- }
- int digit_control(char a[])
- {
- int t,i,s,lenA;
- i=strlen(a);//计算输入数组中的数字位数。
- for(s=0;s<i;s++)
- {
- if(isdigit(a[s])==0)
- {
- printf("输入的符号中有数字以外的其它字符,请重新输入\n");
- t=1;
- break;
- }
- }
- if(t!=1)
- {
- lenA=count_zero(a);//求出非零位数
- if(lenA>8000)
- {
- printf("输入的数字超过8000个,程序不能处理,请重新输入\n");
- t=1;
- }
- }
- return t;
- }
- void string_digitArray(char *a,char *b,int *ArrayA,int *ArrayB,int *LEN_A,int *LEN_B,int *Add_Zero)
- {
- int t,lenB,lenA,s,AddZero,i,j;
- do
- {
- printf("输入被除数:");
- gets(a);//-----从屏幕输入一个大数。
- t=digit_control(a);
- }
- while(t==1);
- do
- {
- printf("输入除数:");
- gets(b);//-----从屏幕输入一个大数
- t=digit_control(b);
- }
- while(t==1);
- lenB=count_zero(b);//求出字符串非零的实际长度。
- lenA=count_zero(a);
- if(lenB==0)
- {
- printf("除数是零,无确定商\n");
- return ;//退出计算
- }
- if(lenA==0)
- {
- printf("商:%d\n",0);
- printf("余数:%d\n",0);
- return ;//退出计算
- }
- if(lenA<lenB)
- {
- printf("商:%d\n",0);
- printf("余数:%s\n",a);
- return ;//退出计算
- }
- s=strlen(a);//计算输入数组中的数字位数。
- if(s>lenA)//说明输入的字符前面有0
- {
- for(i=0;i<=lenA;i++)
- a[i]=a[i+s-lenA];//移动数字,消去前面的0
- }
- s=strlen(b);//计算输入数组中的数字位数。
- if(s>lenB)//说明输入的字符前面有0
- {
- for(i=0;i<=lenB;i++)
- b[i]=b[i+s-lenB];//移动数字,消去前面的0
- }
- AddZero=lenB%4;
- //AddZero=1,补4个零,AddZero=2,补3个零,AddZero=3,补2个零,AddZero=0,补1个0
- switch(AddZero)
- {
- case 3: strcat(a,"00"); strcat(b,"00");t=2;break;
- case 2: strcat(a,"000"); strcat(b,"000");t=3;break;
- case 1: strcat(a,"0000"); strcat(b,"0000");t=4;break;
- case 0: strcat(a,"0"); strcat(b,"0");t=1;break;
- }
- i=strlen(a);
- lenA=i/4;//计算字符数组转化为数字数组的参数。
- j=i%4;
- if(j==0) lenA-=1; //lenA为数组的最大下标
- Vary(a,ArrayA,lenA,j);//处理字符串a为数组
-
- i=strlen(b);
- lenB=i/4;//计算字符数组转化为数字数组的参数。
- lenB-=1; //lenB为数组的最大下标
- Vary(b,ArrayB,lenB,5);//处理字符串b为数组
- *LEN_A=lenA;//返回被除数数组的最大下标,数组长度=数组最大下标+1;
- *LEN_B=lenB;//返回除数数组的最大下标, 数组长度=数组最大下标+1;
- *Add_Zero=t;//返回数组增加的零的个数。
- return;
- }
- //这两个程序实际上是一个,由于太长,只好分开,分别编释。如果放在主函数中也行。
复制代码- #include <stdio.h>
- //#include <stdlib.h>
- void BigDigit_DIV(int dividend[],int LENdividend, int divR[],int LENdivR,int AddZero)
- {
- //int dividend[]; // 被除数 dividend
- int Cdiv[2001]={0}; // 被除数镜像 copy_dividend
- //int divR[]; // 除数 divisor
- int qut[1000]={0}; // 商 quotient
- int CTRL[7]={0}; // 控制 control
-
- int temp,f0,i,j,n;
- void quotient_MUL_divisor(int *Cdiv,int *divR,int *CTRL);//定义内部函数,函数功能:将试商定为确定商
- CTRL[0]=0; //试商由1变为0时的判断依据。CTRL[0]=1时表示试商由1变为0
- //CTRL[1] 未定义
- CTRL[2]=LENdivR; //除数数组的最大下标
- CTRL[3]=0; //每次循环参与计算的被除数起始下标
- //CTRL[4] 未定义
- //CTRL[5] 临时存贮试商的值
- CTRL[6]=LENdivR+1; //每次循环参与计算的被除数终点下标
-
- for(i=0;i<=LENdividend;i++)//为镜像数组赋值。i<=len(dividend[])-1
- Cdiv[i]=dividend[i];
- i=0;
- while(i<=LENdividend-LENdivR-1)//-----(i<=len(dividend[])-len(divR[])-1) //除法开始
- {
- f0=CTRL[3];
- temp=(Cdiv[f0]*10000+Cdiv[f0+1])/divR[0]; // 求试商
- if((temp==0)||(CTRL[0]==1))
- {
- i++;//总循环次数增1
- CTRL[6]++; //被除数下标加1,被除数增加一项
- if(CTRL[6]>LENdividend)//满足条件时程序结束。------------(CTRL[6]>len(dividend[])-1)
- {
- i++;
- continue;
- }
- temp=(Cdiv[f0]*100000000+Cdiv[f0+1]*10000+Cdiv[f0+2])/divR[0]; //试商等于零,增加一项再求商。
- }
- CTRL[5]=temp;
- quotient_MUL_divisor(Cdiv,divR,CTRL);////内部函数,将试商确定为真实商
- if(CTRL[0]==1) continue;
- qut[i]=CTRL[5];
- j=CTRL[3];
- while((Cdiv[j]==0)&&(j<=LENdividend))//计算余数从左端起非零第一项的位置下标------j<=len(dividend[])-1)
- j++;
- if(j>CTRL[6])//说明本次运算余数是零,
- {
- i=i+j-CTRL[6]+CTRL[2]+1;//计算主循环下标。//......
- CTRL[3]=j;//返回被除数下标
- CTRL[6]=CTRL[3]+CTRL[2]+1;//返回被除数下标
- }
- if(j<=CTRL[6])//说明本次运算有非零的余数。
- {
- n=CTRL[6]-j+1;//求余数剩下的位数
- if(n<=CTRL[2]+1)
- {
- temp=CTRL[2]+1-n+1;//求出要补充的新被除数个数。////。。。。
- CTRL[3]=j;//返回被除数下标
- CTRL[6]=CTRL[6]+temp;//返回被除数下标/////。。。
- i=i+temp;//计算主循环下标。
- }
- else
- {
- CTRL[3]=j;
- }
- }
- }
- //===========================================================
- //输出商和余数,这里本来应该从外部函数返回求出的商和余数的,这里偷懒了。
- printf("商=%d",qut[0]);
- for(i=1;i<LENdividend-LENdivR;i++)
- printf("%04d",qut[i]);
- printf("\n");
- if(CTRL[3]>LENdividend)
- {
- printf("余数=0");
- }
- else
- {
- printf("余数=%d",Cdiv[CTRL[3]]);
- for(i=CTRL[3]+1;i<LENdividend;i++)
- printf("%04d",Cdiv[i]);
- if(AddZero!=4)
- {
- for(i=1;i<=AddZero;i++)
- Cdiv[LENdividend]/=10;
- printf("%d",Cdiv[LENdividend]);
- }
- }
- printf("\n");
- //===========================================================
- return ;
- }
- void quotient_MUL_divisor(int *Cdiv,int *divR,int *CTRL)
- {
- int i,temp=0,n;
- int result[2003]={0};//----2003=len(dividend[])+3
- n=CTRL[6]-CTRL[3]-CTRL[2];//对位计算。
- for(i=CTRL[2];i>=0;i--)//CTRL[2]是除数数组的最大下标。
- result[i+n+CTRL[3]]=divR[i]*CTRL[5];//------------------乘法。赋给result[];
- for(i=CTRL[6];i>CTRL[3];i--) //将result[]按四位一组数字进位
- {
- temp=result[i]/10000;
- result[i-1]=result[i-1]+temp;
- result[i]=result[i]-temp*10000;
- }
-
- temp=0;
- for(i=CTRL[6];i>=CTRL[3];i--)
- {
- Cdiv[i]=Cdiv[i]-result[i]-temp;//---------------------减法。减剩的就是余数,直接赋给Cdiv[]
- temp=0;
- if(Cdiv[i]<0)//把余数数组内的负数变为正的。
- {
- Cdiv[i]=Cdiv[i]+10000;//////....
- temp=1;
- }
- }
- CTRL[0]=0;
-
- if(temp==1) /// temp==1表示余数是负的。
- {
- for(i=CTRL[2];i>=0;i--)
- Cdiv[i+n+CTRL[3]]=divR[i]+Cdiv[i+n+CTRL[3]];//-------加法,余数为负是时做一次加法
-
- for(i=CTRL[2]+CTRL[3]+n;i>CTRL[3];i--)//对相加的结果作进位处理
- {
- temp=Cdiv[i]/10000;
- Cdiv[i-1]=Cdiv[i-1]+temp;
- Cdiv[i]=Cdiv[i]-temp*10000;
- }
- Cdiv[CTRL[3]]=Cdiv[CTRL[3]]-10000;
- if(CTRL[5]==1)
- {
- CTRL[0]=1;
- }
- else
- {
- CTRL[0]=0;
- }
- CTRL[5]=CTRL[5]-1;//余数为负时,试商减去1
- }
- return ;
- }
- //这两个程序实际上是一个,由于太长,只好分开,分别编释。如果放在主函数中也行。
复制代码
|
|