| 
注册时间2010-2-12最后登录1970-1-1威望 星金币 枚贡献 分经验 点鲜花 朵魅力 点上传 次下载 次积分1213在线时间 小时 
 | 
 
 楼主|
发表于 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 ;        
}
//这两个程序实际上是一个,由于太长,只好分开,分别编释。如果放在主函数中也行。
 
 | 
 |