笔算除法的代码
包括本人在内的大数运算爱好者,都喜欢自己写出大整数的加、减、乘、除的程序。很多的爱好者都对笔算除法望而却步,主要原因是程序实现过程中对笔算除法的对位不准。本人通过自己揣摩,找到了一种高效的笔算除法方法,并给出源码。
说明:1) 通过数学原理,对笔算除法找到了一种最优实现途径。
2) 程序实现过程中对源码未进行任何优化。
3) 程序以函数的方式说明实现过程。
编译环境:vc++6.0
操作系统:windows xp 3
机器性能:AMD Athlon(tm) II X2250
Processor
3.0GHz 2.00G的内存
测试条件:8000位十进制数除以4001位十进制数,给出商和余数,被除数、除数、商和余数都输出到文件,方便第三方软件检验。debug模式。
测试结果:47ms.(不计输出时间。)
附程序代码;(如果使用其它编译器,请确保每个存贮单元为32bite的容量)
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <windows.h>
int main()
{
int dividend={0}; // 被除数 dividend
int Cdiv={0}; // 被除数镜像copy_dividend
int divR={0}; // 除数 divisor
int result={0};// 乘积的结果result
int qut={0}; // 商 quotient
int CTRL={0}; // 控制 control
intt1,t2; // 时间 time
unsigned int seed; // 初始化随机函数的发生器
int temp,f0,i;
void control_neno(int *Cdiv,int *qut,int *CTRL);
void quotient_MUL_divisor(int *result,int *divR,int *CTRL);
void dividend_SUB_result(int *Cdiv,int *result,int *divR,int *CTRL);
void OUT_text(int *dividend,int *divR,int *qut,int *Cdiv,int *CTRL);
void ArraysFormat();
seed=time(0);//=======以下部分用来随机产生两个大数。代替ArraysFormat();
srand(seed);
Cdiv=3141;//------------共产生8000位十进制数,作为被除数。存入数组Cdiv[]中。
dividend=3141;
for(i = 1; i<2000; i++)
{
Cdiv=(rand())%10000;
dividend=Cdiv;
}
divR=27182;//------------共产生4001位十进制数。作为除数。存入数组divR[]中。
for(i = 1; i<1000; i++)
divR=(rand())%10000;
t1=GetTickCount();//时间计时开始;
CTRL=0; //试商由1变为0时的判断依据。CTRL=1时表示试商由1变为0
CTRL=1000; //除数的个数。
CTRL=CTRL-1; //除数数组的最大下标。
//CTRL 未定义。
//CTRL 总的循环控制变量。
//CTRL 余数的符号
//CTRL 每次循环参与计算的被除数起始位下标。
//CTRL 试商的值。
//CTRL 余数从左端起非零第一项的位置。
//CTRL 每次循环参与计算的被除数个数。
CTRL=1001; //余数剩下的位数。
ArraysFormat();
while(CTRL<=999) //-----(CTRL<=len(Cdiv[])-len(divR[])-1)
{
f0=CTRL;
CTRL=1001;
temp=(Cdiv*10000+Cdiv)/divR;// 求试商
if((temp==0)||((temp==1)&&(CTRL==1)))
{
if(CTRL<CTRL+1)
{
qut]=0;
CTRL++;
}
CTRL++;
temp=(Cdiv*100000000+Cdiv*10000+Cdiv)/divR; //试商等于零,增加一项再求商。
}
CTRL=temp;
quotient_MUL_divisor(result,divR,CTRL);////乘法函数
dividend_SUB_result(Cdiv,result,divR,CTRL);////减法函数
if(CTRL>=0)
{
qut]=temp;
CTRL=0;
}
else
{
qut]=temp-1;
if(temp==1)
{
CTRL=1;
}
else
{
CTRL=0;
}
}
CTRL++;
control_neno(Cdiv,qut,CTRL);//商0的函数
}
t2=GetTickCount();//时间计时结束。
OUT_text(dividend,divR,qut,Cdiv,CTRL);//输出函数
printf("被除数已输出到e盘的dividend.txt 文件中。\n");
printf("除数已输出到e盘的divisor.txt 文件中。\n");
printf("商已输出到e盘的quotient.txt 文件中。\n");
printf("余数已输出到e盘的remainder.txt 文件中。\n");
printf("时间%d ms\n",t2-t1);
return 0;
}
void quotient_MUL_divisor(int *result,int *divR,int *CTRL)
{
int i,temp=0,n;
n=CTRL-CTRL;
result=0;
result=0;
for(i=CTRL;i>=0;i--)
result=divR*CTRL;
for(i=CTRL+n;i>=1;i--)
{
temp=result/10000;
result=result+temp;
result=result-temp*10000;
}
return ;
}
void dividend_SUB_result(int *Cdiv,int *result,int *divR,int *CTRL)
{
int i,temp=0,n,j;
int carry={0};
n=CTRL-CTRL;
for(i=CTRL+n;i>=0;i--)
{
carry=Cdiv]-result-temp;
temp=0;
if(carry<0)
{
carry=carry+10000;
temp=1;
}
}
CTRL=1;
if(temp==1)
{
for(i=CTRL;i>=0;i--)
carry=divR+carry;
for(i=CTRL+n;i>=1;i--)
{
temp=carry/10000;
carry=carry+temp;
carry=carry-temp*10000;
}
carry=carry-10000;
CTRL=-1;
}
for(i=0;i<=CTRL+n;i++)
Cdiv]=carry;
j=0;//计算余数从左端起非零第一项的位置。
while((carry==0) && (j<=CTRL+n))
j++;
CTRL=CTRL+j;
CTRL=j;
CTRL=CTRL+n-j;
return ;
}
void control_neno(int *Cdiv,int *qut,int *CTRL)
{
int i,j,m,s;
if(CTRL>0)
{
m=CTRL-CTRL;
for(i=m;i>=1;i--)
{
qut]=0;
CTRL++;
}
}
if(CTRL==0)
{
s=0;//计算j 的个数。
j=CTRL-CTRL+CTRL;
while(Cdiv==0)
{
j++;
s++;
}
CTRL=j;
m=s+CTRL;
for(i=1;i<=m;i++)
{
qut]=0;
CTRL++;
}
}
return ;
}
void OUT_text(int *dividend,int *divR,int *qut,int *Cdiv,int *CTRL)
{
int i;
FILE*fp; // 输出数据到文件
if((fp=fopen("e:\\dividend.txt","w"))==NULL)
{
printf("not open dividend.txt");
exit(0);
}
for(i=0;i<2000;i++)
fprintf(fp,"%04d",dividend);//输出被除数。
if((fp=fopen("e:\\divisor.txt","w"))==NULL)
{
printf("not open divisor.txt");
exit(0);
}
for(i=0;i<1000;i++)
fprintf(fp,"%04d",divR);//输出除数。
if((fp=fopen("e:\\quotient.txt","w"))==NULL)
{
printf("not open quotient.txt");
exit(0);
}
for(i=0;i<1000;i++)
fprintf(fp,"%04d",qut);//输出商。
if((fp=fopen("e:\\remainder.txt","w"))==NULL)
{
printf("not open remainder.txt");
exit(0);
}
for(i=CTRL;i<2000;i++)
fprintf(fp,"%04d",Cdiv);//输出余数。
fclose(fp);
return ;
}
void ArraysFormat()
{
//这个函数将键盘、文件输入的数字字符串转化为数字,存入数组中,
//每个存贮单元中存入四位十进制数。
//除数的第一位(最高位)需确保五位十进制数。
} Line73: Cdiv*100000000
在int下,有整数溢出风险,你可注意到?或者,楼主可对输出结果验证过? Line73: Cdiv*100000000
在int下,有整数溢出风险,你可注意到?或者,楼主可对输出结果验证过?
谢谢郭先生关注。
说明:1)不会溢出,因为试商是取被除数的前两项来做除法,即Cdiv和Cdiv,单看这两项的数学表达式是Cdivx10000+Cdiv。而除数是divR,它是确保的五位十进制数,所以相除的结果要么大于零,这时程序绕开line73行。相除的结果如果等于零,说明Cdivx10000+Cdiv这两项最多只有五位十进制数。Cdiv占了四位十进制数,那么Cdiv只有一位十进制数。这时程序才能进入line73行。这时Cdiv*100000000就是成立的。
2)测试过,用的是笨办法,先运行这个程序一次,再用vb写的除法----------方法是“循环相减”求商,这样很慢,但能保证结果是正确的----------求出商来对照。用眼睛一行一行的扫,还未发现错误。
我的几点建议:
在实际应用中,除法函数的接口的定义应该有2种,第1种是只求商,第2种是求商和余数。
1. 接口,在第一种情况下,传入参数有3个
1). 被除数(只读)
2). 除数(只读)
3). 商(可写)
2. 关于工作空间:
工作空间只需要一个比被除数长度稍大一点的数组,即楼上提到的“被除数的镜像”。可使用栈(当被除数长度较小时)或者动态分配(当被除数长度很大时)。被除数 减去 部分商(每次试出得到的商)乘以除数的积的差可直接完成,不需要中间结果数组result。
3. 代码优化。程序逻辑仍可优化,你的代码稍显复杂。
我的几点建议:
谢谢liangbch的关注:
1)首先接受先生的建议。我会慢慢的优化一下,我只是爱好,实际上没有编程的功力。能不能优化得好,还是未知。
2)我写程序慢,这个程序更是伤脑筋,这个程序基本上是靠调试调出来的。原因是除法的各种可能都要考虑到,脑袋一片模糊,就像先生所说的,程序的逻辑没有理清。
3)因为我写得慢,所以过一段时间,我把这个程序改一改,让它能处理数据。
发现这个程序的一个错误,就是当整除时,不能输出余数“0”,要把输出余数的语句改一改才行。
if(CTRL<2000)
{
for(i=CTRL;i<2000;i++)
fprintf(fp,"%04d",Cdiv);//输出余数。
}
else
{
fprintf(fp,"%d",0);//输出余数。
}
把输出余数的语句改成这样就可以了。 本帖最后由 只是呼吸 于 2015-2-17 00:11 编辑
根据liangbch的建议,我把程序作了修改。修改后的程序能处理任意两个不超过8000位数(十进制数)的整数除法。由于增加了从屏幕输入的语句,所以程序太长,不清晰,只好分成两部分:前一部分把屏幕输入的字符转化为数组,后一部分把数组相除得到结果。程序中给出全部注释。给出笔算除法的实现步骤。
笔算除法的实现步骤:
1) 输入字符串a
2)输入字符串b
3)转化字符串a为被除数数组A,每4个数字为一组,(万进制)
4)转化字符串b为除数数组B,每4个数字为一组,但第一个元素B必须是5位十进制数。
5)除法开始:
6)求试商:n=(A*10000+A)/B
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={0}; //被除数
int ArrayB={0}; //除数
int quotient={0};//商
//int rm={0}; //余数
int LEN_ArrayA,LEN_ArrayB,AddZero;
int *LEN_A,*LEN_B,*Add_Zero;
char a;
char b;
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=dm*1000+dm*100+dm*10+dm-53328;
}
else
{
for (kd=0;kd<=yy-2;kd++)
{
kk+=dm-48;
kk*=10;
}
kk+=dm-48;
for(s=1;s<=ss;s++,yy+=4)
kk=dm*1000+dm*100+dm*10+dm-53328;
}
}
int count_zero(char b[])
{
int j,s;
j=strlen(b);
s=0;
while(b=='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)==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=a;//移动数字,消去前面的0
}
s=strlen(b);//计算输入数组中的数字位数。
if(s>lenB)//说明输入的字符前面有0
{
for(i=0;i<=lenB;i++)
b=b;//移动数字,消去前面的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={0}; // 被除数镜像copy_dividend
//int divR[]; // 除数 divisor
int qut={0}; // 商 quotient
int CTRL={0}; // 控制 control
int temp,f0,i,j,n;
void quotient_MUL_divisor(int *Cdiv,int *divR,int *CTRL);//定义内部函数,函数功能:将试商定为确定商
CTRL=0; //试商由1变为0时的判断依据。CTRL=1时表示试商由1变为0
//CTRL 未定义
CTRL=LENdivR; //除数数组的最大下标
CTRL=0; //每次循环参与计算的被除数起始下标
//CTRL 未定义
//CTRL 临时存贮试商的值
CTRL=LENdivR+1;//每次循环参与计算的被除数终点下标
for(i=0;i<=LENdividend;i++)//为镜像数组赋值。i<=len(dividend[])-1
Cdiv=dividend;
i=0;
while(i<=LENdividend-LENdivR-1)//-----(i<=len(dividend[])-len(divR[])-1) //除法开始
{
f0=CTRL;
temp=(Cdiv*10000+Cdiv)/divR;// 求试商
if((temp==0)||(CTRL==1))
{
i++;//总循环次数增1
CTRL++; //被除数下标加1,被除数增加一项
if(CTRL>LENdividend)//满足条件时程序结束。------------(CTRL>len(dividend[])-1)
{
i++;
continue;
}
temp=(Cdiv*100000000+Cdiv*10000+Cdiv)/divR; //试商等于零,增加一项再求商。
}
CTRL=temp;
quotient_MUL_divisor(Cdiv,divR,CTRL);////内部函数,将试商确定为真实商
if(CTRL==1) continue;
qut=CTRL;
j=CTRL;
while((Cdiv==0)&&(j<=LENdividend))//计算余数从左端起非零第一项的位置下标------j<=len(dividend[])-1)
j++;
if(j>CTRL)//说明本次运算余数是零,
{
i=i+j-CTRL+CTRL+1;//计算主循环下标。//......
CTRL=j;//返回被除数下标
CTRL=CTRL+CTRL+1;//返回被除数下标
}
if(j<=CTRL)//说明本次运算有非零的余数。
{
n=CTRL-j+1;//求余数剩下的位数
if(n<=CTRL+1)
{
temp=CTRL+1-n+1;//求出要补充的新被除数个数。////。。。。
CTRL=j;//返回被除数下标
CTRL=CTRL+temp;//返回被除数下标/////。。。
i=i+temp;//计算主循环下标。
}
else
{
CTRL=j;
}
}
}
//===========================================================
//输出商和余数,这里本来应该从外部函数返回求出的商和余数的,这里偷懒了。
printf("商=%d",qut);
for(i=1;i<LENdividend-LENdivR;i++)
printf("%04d",qut);
printf("\n");
if(CTRL>LENdividend)
{
printf("余数=0");
}
else
{
printf("余数=%d",Cdiv]);
for(i=CTRL+1;i<LENdividend;i++)
printf("%04d",Cdiv);
if(AddZero!=4)
{
for(i=1;i<=AddZero;i++)
Cdiv/=10;
printf("%d",Cdiv);
}
}
printf("\n");
//===========================================================
return ;
}
void quotient_MUL_divisor(int *Cdiv,int *divR,int *CTRL)
{
int i,temp=0,n;
int result={0};//----2003=len(dividend[])+3
n=CTRL-CTRL-CTRL;//对位计算。
for(i=CTRL;i>=0;i--)//CTRL是除数数组的最大下标。
result]=divR*CTRL;//------------------乘法。赋给result[];
for(i=CTRL;i>CTRL;i--) //将result[]按四位一组数字进位
{
temp=result/10000;
result=result+temp;
result=result-temp*10000;
}
temp=0;
for(i=CTRL;i>=CTRL;i--)
{
Cdiv=Cdiv-result-temp;//---------------------减法。减剩的就是余数,直接赋给Cdiv[]
temp=0;
if(Cdiv<0)//把余数数组内的负数变为正的。
{
Cdiv=Cdiv+10000;//////....
temp=1;
}
}
CTRL=0;
if(temp==1) /// temp==1表示余数是负的。
{
for(i=CTRL;i>=0;i--)
Cdiv]=divR+Cdiv];//-------加法,余数为负是时做一次加法
for(i=CTRL+CTRL+n;i>CTRL;i--)//对相加的结果作进位处理
{
temp=Cdiv/10000;
Cdiv=Cdiv+temp;
Cdiv=Cdiv-temp*10000;
}
Cdiv]=Cdiv]-10000;
if(CTRL==1)
{
CTRL=1;
}
else
{
CTRL=0;
}
CTRL=CTRL-1;//余数为负时,试商减去1
}
return ;
}
//这两个程序实际上是一个,由于太长,只好分开,分别编释。如果放在主函数中也行。
好帖啊!顶起来啊啊 啊啊啊啊啊啊啊啊 本帖最后由 只是呼吸 于 2015-8-14 00:13 编辑
在这一段时间里,一直对lianbch在4#所指导的方法潜水学习中,现在终于得到得到了以下的重要进展:
1)找到了vc++6.0支持的64位类型,具体而言就是UInt32x32To64(,)这个函数,这个函数出自本论坛http://bbs.emath.ac.cn/thread-216-1-1.html里6楼。
2)慢慢试着使用malloc()函数开辟空间。因一直害怕它把内存泄漏完,心存疑虑。
在有了以上的两方面知识后,这个笔算除法就可以改进了,最重要的改进是两点:
1)采用\(10^8\)进制,比上面的\(10^4\)进制效率提高了。
2)输入的数组不作特别要求,但在函数内自动将除数首位保持9个十进制数字。
改进后的函数原型:int Big_NumDiv_q(UINT32 *quotient,
const UINT32 * const dividend,
const UINT32 * const divisor,int LEN_dividend,int LEN_divisor);
输入参数:数组 quotient[], 用来存贮求出的商。数组的空间须事先给出。数组排列方式:数组的高位对应大的下标,数组最右边的下标是0。数组的每一位采用\(10^8\)进制。
数组 dividend[],用来传入被除数。数组排列方式:数组的高位对应大的下标,数组最右边的下标是0。数组的每一位采用\(10^8\)进制。
数组 divisor[],用来传入除数。数组排列方式:数组的高位对应大的下标,数组最右边的下标是0。数组的每一位采用\(10^8\)进制。
整数 LEN_dividend,传入被除数的长度。
整数 LEN_divisor,传入除数的长度。
运算关系: quotient[]<-----dividend[]\(div\)divisor[]
quotient[]的实际长度由函数返回。
测试平台: 软件windows XP VC++6.0
硬件AMD Athlon(tm) II X2250 Processor 3.0GHz
2.00G的内存
测试结果: 10000位十进制数除以5000位十进制数。 耗时31毫秒(不计输出时间)。 声明:这个函数本人仅仅是作了初步的测试,暂时没有发现错误。
由于程序较长,分段贴出。
头文件:DIV.h
#ifndef _MUL_H_
#define _MUL_H_
#include <wtypes.h>
#defineBASE 100000000
/*----------------------类型----------------------*/
typedef unsigned int UINT32;
typedef unsigned __int64 UINT64;
typedef union tag_UINT64
{
UINT64 u64Val;
UINT32 u32LH;
} UInt64;
/*----------------------函数----------------------*/
extern int Big_NumDiv_q( UINT32 *quotient,
const UINT32 * const dividend,
const UINT32 * const divisor,int LEN_dividend,int LEN_divisor);////除法的求商函数。
extern void DIV_DigitFomart(const UINT32 * const dividend,int LEN_dividend,const UINT32 * const divisor,
int LEN_divisor,int *Cdiv,int *divR);/////除法之前的格式化
extern void Big_Digit_DIV(UINT32 *qut,int *Work, int *Cdiv,int LENdividend, int *divR,int LENdivR);
extern void quotient_MUL_divisor(int *Work,int *Cdiv,int *divR,int *CTRL);
#endif
原型函数:int Big_NumDiv_q.c
主函数首先调用的函数。
函数原型:int Big_NumDiv_q(UINT32 *quotient,
const UINT32 * const dividend,
const UINT32 * const divisor,int LEN_dividend,int LEN_divisor);
输入参数:数组 quotient[], 用来存贮求出的商。数组的空间须事先给出。数组排列方式:数组的高位对应大的下标,数组最右边的下标是0。数组的每一位采用\(10^8\)进制。
数组 dividend[],用来传入被除数。数组排列方式:数组的高位对应大的下标,数组最右边的下标是0。数组的每一位采用\(10^8\)进制。
数组 divisor[],用来传入除数。数组排列方式:数组的高位对应大的下标,数组最右边的下标是0。数组的每一位采用\(10^8\)进制。
整数 LEN_dividend,传入被除数的长度。
整数 LEN_divisor,传入除数的长度。
运算关系: quotient[]<-----dividend[]\(\div\)divisor[]
quotient[]的实际长度由函数返回。
#include "DIV.h"
#include "stdio.h"
int Big_NumDiv_q( UINT32 *quotient,
const UINT32 * const dividend,
const UINT32 * const divisor,int LEN_dividend,int LEN_divisor)////除法的求余函数。
{
int i,N,M;
int *Cdiv,*divR,*Work;
if((LEN_divisor==1)&&(divisor==0))///若除数为零,
{
printf("err:divisor is zeor\n");///显示出错信息。
return 0;
}
if(LEN_dividend<LEN_divisor)///若被除数小于除数,
{
remainder=0; ///商为零,
return 0;
}
if((LEN_dividend==1)&&(dividend==0))///若被除数为零,
{
remainder=0; ///商为零。
return 0;
}
//-----------------------------------------------以上语句对除法进行预处理。--------------------------//
N=LEN_dividend+4;///--------------------增加长度。为存贮格式化后的新被除数作准备。N-1是数组上限。
M=LEN_divisor+2;///---------------------增加长度,为存贮格式化后的新除数作准备。M-1是数组的上限。
if((Cdiv= (int *)malloc(N * (sizeof(UINT32))))==NULL)//调用库函数,开辟内存,用于存贮格式化了的被除数
{
printf("fail\n");
exit(0);
}
if((divR= (int *)malloc(M * (sizeof(UINT32))))==NULL)//调用库函数,开辟内存,用于存贮格式化了的除数。
{
printf("fail\n");
exit(0);
}/////
if((Work= (int *)malloc(N * (sizeof(UINT32))))==NULL)//调用库函数,开辟内存,工作数组。
{
printf("fail\n");
exit(0);
}
N--;
M--;
for(i=N;i>=0;i--)
{
Cdiv=0;////把生成的数组初始化为0;
Work=0;
}
for(i=M;i>=0;i--)
{
divR=0;////把生成的数组初始化为0;
}
DIV_DigitFomart(dividend,LEN_dividend,divisor,LEN_divisor,Cdiv,divR);////调用除法格式化函数。将被除数和除数格式化。
while((Cdiv==0)&&(N>=0))//寻找被除数最高位下标。
{
N--;
}
while((divR==0)&&(M>=0))//寻找除数最高位下标。
{
M--;
}
Big_Digit_DIV(quotient,Work,Cdiv,N,divR,M);//调用除法函数做除法。
free(Cdiv);////释放内存。
Cdiv=NULL;
free(divR);
divR=NULL;////
free(Work);
Work=NULL;////
i=LEN_dividend-LEN_divisor;
while((quotient==0)&&(i>=0))//寻找求出的商的最高位下标。
{
i--;
}
if(i<0)
{
return 0;
}
return i;
}
页:
[1]
2