巨大数——三则运算(+、-、*)
这篇博文,主要讲解了一个思想 —— 将字符串转换为数值,再转换为结构体,以及部分文件操作的复习使用。
那么,回归主题:
据我们所知,int 型变量最大能表示的正数是21亿多,那么,如果我们要处理比21亿大很多的数据,我们要怎么实现呢?因为其他类型也是有极限值的,所以,如果突破了极限,就会出现错误。口说无凭,我们来用vc6.0尝试下:
可以看到,我输入了22亿,但是输出的却不是43亿。所以,由此可以看出,int型变量是有极限的,所以,为了解决这个问题,我们来编写一个程序,来为任何合法数据进行操作并准确输出。
刚开始,我们因为能力不足,无法完成小数操作和除法操作,那么,我们就进行整数操作,再进阶到小数。至于除法,逻辑太复杂,就不进行了。
整数:
本人这里对数据采用了万进制的存储方法(由微易码教主所教授)。
那么,为什么要用万进制呢?这里来进行一些解释:
首先,int型(即整形变量),正数最高存储范围为0~21亿左右,即第9位,而万是第4位,两个几万的数相乘所得的结果,最高也是(4+4)即8位,不会造成错误;
其次,万进制存储“巨大数”,在满足第一条的情况下,所浪费的空间就要稍微少点。
那么,现在,我们开始编写该程序:
一、由于我们是要使用万进制,所以,我们先定义一个万进制的结构体,而我们定义的万进制结构体,结构体所存的每个万进制数,需要知道它的位数,每一位的值,该数的正负号,代码如下:
typedef struct HUGE {
int digit;
int *num;
SIGN sign;
}HUGE;
在这里,我们为了方便,定义了一个新类型SIGN,它的数值只有两种:正、负,代码如下:
typedef unsigned char SIGN;
#define PLUS 0 //定义正为0
#define MINUS 1 //定义负为1
二、那么,现在编写录入巨大数函数,在这里,我来提出几点关于这个函数的要求和实现思想:
我们要存进文件,而且在文件里就可以直接看到所存进的巨大数,而且这个巨大数,排版还很规则、美观,所以我们会用到文件那里的知识,关于这里不懂的同学,可以参考本人以前的博文《文件操作》。关于排版问题,无非是存几个数存一个空格,存几个数存一个回车,这个比较容易实现。还有,最关键的一点就是向文件中存入的有效值,所以对于使用者输入的值我们要进行筛选,代码如下:
void inputFile(char *name) { //这里的参数,是文件名,用于向指定文件中(或生成指定文件)录入“巨大数”
char ch; //用于接收键盘输入的值
int flag=1; //用于判断循环是否继续
int count=0; //用于记录有效数据的位数,用于之后的排版问题
FILE *p; //用于打开和关闭文件
p=fopen(name, "w");
printf("\n请输入要录入的数据:(输入#则停止录入)\n");
ch=getch(); //getch的作用是:接收键盘所输入的字符,若键盘不输入,则等待至输入再进行下一行代码
while(flag) { //这里用flag变量来确定循环是否继续
if(ch == '-') {
printf("-"); //回显录入文件的字符
fputc(ch, p); //fputc的作用是:将以字符形式录入p所指向的文件的指定位置
} else if(ch <= '9' && ch >= '0') {
printf("%c", ch); //回显录入文件的字符
fputc(ch, p); //作用参考上面的解释
count++; //有效位数加一(所谓有效位数,即0~9的个数)
flag=0; //满足条件,跳出循环(这个循环的目的是:处理第一个有效字符)
} else if(ch == '#') { //第一个有效字符如果是#,则录入0,并结束该函数
printf("0");
fputc('0', p);
return;
} else if(ch == '+') { //正号不录入,只回显,这对于接下来读取函数可以稍微减轻点代码量
printf("+");
}
ch=getch(); //若还未输入有效数值,则让用户继续输入
} //这个循环的目的是:处理第一个有效数值(即字符0~9)
while(ch != '#') {
if(ch <= '9' && ch >= '0') {
printf("%c", ch);
fputc(ch, p);
count++;
}
if(0 == count%4) { //这个判断,是为了排版(即使得文件中存储的数据直观)
printf(" ");
fputc(' ', p);
} else if(0 == count%16) {
fputc(13, p);
printf("\n");
}
ch=getch();
}
fclose(p);
}
三、因为有的巨大数要从文件中提出才能够进行操作,所以,我们在这一步,编写将文件中的数提出并放到结构体中去的函数,代码如下:
HUGE getNumFromFile(char *fileName) { //关于返回值:因为要将文件中存储的“数据”提出到结构体中,所以返回值为HUGE类型。 关于参数:参考上一个函数的参数
int i;
int j;
char ch;
HUGE num1={0, NULL, PLUS}; //这里是对定义的要返回的结构体的初始化
FILE *fp;
fp=fopen(fileName, "r");
rewind(fp); //rewind函数的作用是:将fp指向该文件的开头
if(NULL == fp) { //这里的if是用来判断是否文件中有数据,防止传来的文件名是没录入数据的文件
printf("\nERROR!!!\n");
return;
}
ch=fgetc(fp);
if(ch == '-') { //这里的判断,和上文录入就有关了,录入时只录入了负号,没有录入正号,无符号时默认为正数
num1.sign=MINUS;
} else {
num1.sign=PLUS;
}
while((EOF != ch) {
if(ch>='0' && ch<='9') {
num1.digit++;
}
ch=fgetc(fp);
} //这个循环用于判断有效数位数
rewind(fp); //作用类似上文
num1.num=(int *)calloc(sizeof(int), (num1.digit+3)/4+1); //这个函数包含于<malloc.h>库中,用于给结构体中的"万进制数组"申请空间,这里多申请了一个空间,是为了等下加法要用到的方法多定义的
ch=fgetc(fp);
for(j=0; j<(num1.digit%4); j++) { //我们将低位存在数组下标小的单元中。这里是给最后一个单元赋值,因为最后一个单元,也就是最高位,位数不确定,所以这里先确定最后一个单元的数值
if(ch>='0' && ch<='9') {
num1.inum[num1.digit+3)/4-1]=num1.num[num1.digit+3)/4-1]*10+(ch-'0'); //这里解释下“ch-'0'”的意思:因为文件中存入的是字符,看作数值时也就是ASCII码,所以用该字符减去字符0,也就是对应的数值
} else {
j--; //若是空格和回车换行,则不录入,这一步操作可以看作暂停这一次循环
}
ch=fgetc(fp);
}
for(i=(num1.digit+3)/4-2; i>=0; i--) { //除了最后一个单元,其他单元都是四位的
for(j=0; j<4; j++) {
if(ch>='0' && ch<='9') {
num1.num[i]=num1.num[i]*10+(ch-'0');
} else {
j--;
}
ch=fgetc(fp);
}
}
fclose(fp);
return num1;
}
四、我们所得到的结果都要转换为结构体形式,所以,在这里,我们开始编写通过结构体显示巨大数的函数,代码如下:
void showNum(HUGE num1) {
int i;
int count=0;
if(num1.sign == MINUS) {
printf("-");
}
for(i=(num1.digit+3)/4-1; i>=0; i--) {
if(!count) { //这个判断用于区分是否是最高位的输出,最高位的数组单元可能不是四位,而非最高位的数组单元是四位
printf("%d", num1.num[i]);
count++;
} else {
printf("%04d", num1.num[i]);
}
}
}
那么,现在来讲述一下加减乘的基本原理:
Ⅰ.加减法:
(加法和减法其实可以看作同一种,只要将减数的符号改变,就是两个数的加法,所以,这里将加减法放在一起讲)
对于我们用的万进制,加法就有些不一样了,因为每个“单元”是独立的,但是,进位可以通过一个变量实现,只要将这个变量使用后再赋值为0即可。
但是,在这里,本人要讲解一种“很奇特”的加法处理方法——微易码补码:
所谓的“微易码补码”,是由家师微易码教主所总结推到所得,这种方法对于数学功底并不是很好的我来说,还是不能推导出的,
所以,在这里我就不进行推导了,直接来告诉结论:
在我们往常的学习中,可能会了解到关于原码和补码的知识,如果之前没有了解过的同学也不用担心,至于原码和补码的相关内容
本人也会在今后的博文中进行讲解。
我们曾经了解到的原码和补码的关系是:
正数的补码——正数原码本身;
负数的补码——除符号位外,按位取反,末位+1(这个简便算法,由关系可以推出)
那么,所谓”微易码补码“,正是借鉴了这里的知识,很好地处理了 正数加负数 的问题,
使得在加的过程中,不会出现因为符号做减法的问题。
这里来讲解它的用法:
- 正数的补码——正数本身
负数的补码——每一位取9减该位的值(因为原码补码是建立在二进制层面上,而我们的操作,是面向十进制数的)- 每个对应单元相加,若大于9999,则要进位,并将该单元的数和10000取余(或者直接减去10000也行) .之后再根据(符号相等 ?0 :1)^ (最高位进位 ?1 : 0)
若结果为1,个位加一,符号为负号;结果为0,个位不加,符号为正号- 最后若为负号,则各位的值为用9减各位的值(类似于负数的补码转换为原码的过程)
下面是加减法函数的代码:
HUGE addNum(HUGE num1, HUGE num2) {
int count;
int i;
int carry=0;
int *p=NULL;
int temp;
HUGE num3={0, NULL, PLUS};
count=num1.digit>num2.digit ? num1.digit : num2.digit;
num3.num=(int *)calloc(sizeof(int), (count+3)/4+1);
if(MINUS == num1.sign) { //这里就是将负数进行了“微易码补码”的转换
num1.num[(num1.digit+3)/4]=9999; //由于我们多定义了前面一个int型空间,所以,将这个空间先转换
for(i=0; i<(num1.digit+3)/4; i++) {
num1.inum[i]=9999-num1.inum[i];
}
} else {
num1.num[(num1.digit+3)/4]=0;
}
if(MINUS == num2.sign) {
num2.num[(num2.digit+3)/4]=9999;
for(i=0; i<(num2.digit+3)/4; i++) {
num2.num[i]=9999-num2.num[i];
}
} else {
num2.num[(num2.digit+3)/4]=0;
}
for(i=0; i<(num1.idigit<num2.idigit ? (num1.idigit+3)/4+1 : (num2.idigit+3)/4) +1; i++) {
temp=num1.num[i]+num2.num[i]+carry;
num3.num[i]=temp%10000;
carry=(temp>10000 ? 1 : 0);
}
p=(num1.digit>num2.digit ? num1.num : num2.num); //用数组将位数多的数组的数据保存起来,以便下面的操作
for(;i<(num1.digit>num2.digit ? (num1.digit+3)/4 + 1: (num2.digit+3)/4) + 1; i++) {
temp=p[i]+carry;
num3.num[i]=temp%10000;
carry=(temp>10000 ? 1 : 0);
}
if(num1.sign == num2.sign) {
num3.sign=num1.sign;
} else {
num3.sign=1^carry;
}
num3.num[i]%=10000;
}
num3.num[0]+=carry;
for(i=0; i<=(count+3)/4 && num3.num[i]>9999; i++) {
num3.num[i]%=10000;
num3.num[i+1]++;
}
if(MINUS == num3.sign) {
for(i = 0; i <= (num3.digit+3)/4+1; i++) {
num3.num[i] = 9999 - num3.num[i];
}
}
count=((count+3)/4)*4;
for(i=(count+3)/4; i>=0 && !num3.num[i]; i--) {
count-=4;
}
if(!(num3.num[i]/10)) {
count-=3;
} else if(!(num3.num[i]/100)) {
count-=2;
} else if(!(num3.num[i]/100)) {
count-=1;
}
num3.digit=count;
return num3;
}
HUGE subNum(HUGE num1, HUGE num2) {
HUGE num4={PLUS, NULL, 0};
num2.sign = num2.sign==PLUS ? MINUS : PLUS;
num4=addNum(num1, num2);
return num4;
}
Ⅱ.乘法:
对于乘法来说,相对于加法,就要简单得多,因为乘法的本质,可以看作多项式相乘,在万进制下,每个单元的下标,该单元所存的数的单位为该数原本10000的几次方
所以,代码如下:
HUGE multyNum(HUGE num1, HUGE num2) {
int i;
int j;
int count;
HUGE num5={PLUS, NULL, 0};
num5.num=(int *)calloc(sizeof(int), (num1.digit+num2.digit+2)/4+1);
for(i=(num1.digit+3)/4-1; i>=0; i--) {
for(j=(num2.digit+3)/4-1; j>=0; j--) {
num5.num[i+j]+=(num1.num[i]*num2.num[j])%10000;
num5.num[i+j+1]+=(num1.num[i]*num2.num[j])/10000;
}
}
count=(num1.digit+num2.digit+6)/4*4;
for(i=(num1.digit+num2.digit+2)/4; i>=0 && !num5.num[i]; i--) {
count-=4;
}
if(!(num5.num[i]/10)) {
count-=3;
} else if(!(num5.num[i]/100)) {
count-=2;
} else if(!(num5.num[i]/100)) {
count-=1;
}
num5.digit=count;
return num5;
}
主函数:
int main() {
HUGE num1={PLUS, NULL, 0};
HUGE num2={PLUS, NULL, 0};
HUGE num3={PLUS, NULL, 0};
HUGE num4={PLUS, NULL, 0};
HUGE num5={PLUS, NULL, 0};
inputFile("num1.txt");
num1=getNumFromFile("num1.txt");
printf("\nthe num1 is:\n");
showNum(num1);
inputFile("num2.txt");
num2=getNumFromFile("num2.txt");
printf("the num2 is:\n");
showNum(num2);
num3=addNum(num1, num2);
printf("the num3 is:\n");
showNum(num3);
num4=subNum(num1, num2);
printf("the num4 is:\n");
showNum(num4);
num5=muiltyNum(num1, num2);
printf("the num5 is:\n");
showNum(num5);
free(num1.num);
free(num2.num);
free(num3.num);
free(num4.num);
free(num5.num);
return 0;
}
小数:
那么,在整数的基础上,我们再来完成小数就相对而言要简单得多了
首先是结构体的定义:
typedef struct HUGE {
SIGN sign;
int *inum; //保存整数数值
int *dnum; //保存小数数值
int idigit; //整数位数
int ddigit; //小数位数
}HUGE;
因为我们要处理小数部分,所以我们结构体中就多定义一个小数位数和小数数组。关于这个数组,有的人处理方法可能跟我不一样,但是相对而言,我这种算法,要比较直观、简单易懂。
那么,接下来是录入函数,这里的录入函数,相比于整数,无非是小数点只能输入一次,代码段如下:
void inputFile(char *name) {
char ch;
int flag=1;
int dot=0; //保存小数点个数,避免录入多个小数点
int count=0;
FILE *p;
p=fopen(name, "w");
printf("\n请输入要录入的数据:(输入#则停止录入)\n");
ch=getch();
while(flag) {
if(ch == '-') {
printf("-");
fputc(ch, p);
} else if(ch == '.' && dot<1) { //判断小数点是否还未录入
printf("0.");
fputc('0', p);
fputc('.', p);
dot++;
count+=2;
} else if(ch <= '9' && ch >= '0') {
printf("%c", ch);
fputc(ch, p);
count++;
flag=0;
} else if(ch == '#') {
printf("0");
fputc('0', p);
fputc('0', p);
return;
} else if(ch == '+') {
printf("+");
}
ch=getch();
} //这个循环的目的是在用户录入一个有效数值时结束录入
while(ch != '#') {
if(ch == '.' && dot == 0) {
printf(".");
fputc('.', p);
count++;
dot++;
} else if(ch <= '9' && ch >= '0') {
printf("%c", ch);
fputc(ch, p);
count++;
}
if(0 == count%4) {
printf(" ");
fputc(' ', p);
} else if(0 == count%16) {
fputc(13, p);
printf("\n");
}
ch=getch();
}
fclose(p);
}
接下来是从文件中提取巨大数的操作,这个操作其实也无非是判断小数点,并将小数点前的存入整数数组,将小数点后的存入小数数组,代码段如下:
HUGE getNumFromFile(char *fileName) {
int i;
int j;
char ch;
HUGE num1={PLUS, NULL, NULL, 0, 0};
FILE *fp;
fp=fopen(fileName, "r");
rewind(fp);
if(NULL == fp) {
printf("\nERROR!!!\n");
return;
}
ch=fgetc(fp);
if(ch == '-') {
num1.sign=MINUS;
} else {
num1.sign=PLUS;
}
while((EOF != ch) && ('.' != ch)) {
if(ch>='0' && ch<='9') {
num1.idigit++;
}
ch=fgetc(fp);
}
while(EOF != ch) {
if(ch>='0' && ch<='9') {
num1.ddigit++;
}
ch=fgetc(fp);
}
rewind(fp);
num1.inum=(int *)calloc(sizeof(int), (num1.idigit+3)/4+1);
num1.dnum=(int *)calloc(sizeof(int), (num1.ddigit+3)/4);
ch=fgetc(fp);
for(j=0; j<(num1.idigit%4); j++) {
if(ch>='0' && ch<='9') {
num1.inum[(num1.idigit+3)/4-1]=num1.inum[(num1.idigit+3)/4-1]*10+(ch-'0');
} else {
j--;
}
ch=fgetc(fp);
}
for(i=(num1.idigit+3)/4-2; i>=0; i--) {
for(j=0; j<4 && ch!='.'; j++) {
if(ch>='0' && ch<='9') {
num1.inum[i]=num1.inum[i]*10+(ch-'0');
} else {
j--;
}
ch=fgetc(fp);
}
}
for(i=0; i<(num1.ddigit+3)/4; i--) { //将小数高位存储在小数数组下表小的单元中,便于进位
for(j=0; j<4; j++) {
if(ch>='0' && ch<='9') {
num1.dnum[i]=num1.dnum[i]*10+(ch-'0');
ch=fgetc(fp);
} else if (EOF==ch) {
num1.dnum[i]=num1.dnum[i]*10;
} else {
j--;
ch=fgetc(fp);
}
}
}
fclose(fp);
return num1;
}
之后的是显示函数,区别也只是输出完整数,要输出一个小数点,再输出小数部分,代码段如下:
void showNum(HUGE num1) {
int i;
if(num1.sign == MINUS) {
printf("-");
}
i=(num1.idigit+3)/4;
if(i>0 && (!num1.inum[i])) {
i--;
}
for(; i>=0; i--) {
if(!count) {
printf("%d", num1.inum[i]);
} else {
printf("%04d", num1.inum[i]);
}
}
printf(".");
for(i=0; i<(num1.ddigit+3)/4; i++) {
printf("%04d", num1.dnum[i]);
}
}
最后,就是加减乘法:
1.加法:先加小数部分,操作类似于整数部分,判断是否进位整数再加整数部分,代码段如下:
HUGE addNum(HUGE num1, HUGE num2) {
int icount;
int dcount;
int i;
int carry=0;
int *p=NULL;
int temp;
HUGE num3={PLUS, NULL, NULL, 0, 0};
icount=num1.idigit>num2.idigit ? num1.idigit : num2.idigit;
dcount=num1.ddigit>num2.ddigit ? num1.ddigit : num2.ddigit;
num3.inum=(int *)calloc(sizeof(int), (icount+3)/4+1);
num3.dnum=(int *)calloc(sizeof(int), (dcount+3)/4);
if(MINUS == num1.sign) {
num1.inum[(num1.idigit+3)/4]=9999;
for(i=0; i<(num1.idigit+3)/4; i++) {
num1.inum[i]=9999-num1.inum[i];
}
for(i=0; i<(num1.ddigit+3)/4; i++) {
num1.dnum[i]=9999-num1.dnum[i];
}
} else {
num1.inum[(num1.idigit+3)/4]=0;
}
if(MINUS == num2.sign) {
num2.inum[(num2.idigit+3)/4]=9999;
for(i=0; i<(num2.idigit+3)/4; i++) {
num2.inum[i]=9999-num2.inum[i];
}
for(i=0; i<(num2.ddigit+3)/4; i++) {
num2.dnum[i]=9999-num2.dnum[i];
}
} else {
num2.inum[(num2.idigit+3)/4]=0;
}
p=(num1.ddigit>num2.ddigit ? num1.dnum : num2.dnum);
for(i=(dcount+3)/4-1; i>=(num1.ddigit<num2.ddigit ? (num1.ddigit+3)/4 : (num2.ddigit+3)/4); i--) {
num3.dnum[i]=p[i];
}
for(i=(num1.ddigit<num2.ddigit ? (num1.ddigit+3)/4-1 : (num2.ddigit+3)/4-1); i>=0; i--) {
temp=num1.dnum[i]+num2.dnum[i]+carry;
num3.dnum[i]=temp%10000;
carry=(temp>10000 ? 1 : 0);
}
for(i=0; i<(num1.idigit<num2.idigit ? (num1.idigit+3)/4 : (num2.idigit+3)/4); i++) {
temp=num1.inum[i]+num2.inum[i]+carry;
num3.inum[i]=temp%10000;
carry=(temp>10000 ? 1 : 0);
}
p=(num1.idigit>num2.idigit ? num1.inum : num2.inum);
for(;i<(num1.idigit>num2.idigit ? (num1.idigit+3)/4 + 1: (num2.idigit+3)/4) + 1; i++) {
temp=p[i]+carry;
num3.inum[i]=temp%10000;
carry=(temp>10000 ? 1 : 0);
}
if(num1.sign == num2.sign) {
num3.sign=num1.sign;
} else {
num3.sign=1^carry;
}
num3.dnum[(dcount+3)/4-1]+=carry;
for(i=(dcount+3)/4-1; i>0 && num3.dnum[i]>9999; i--) {
num3.dnum[i]%=10000;
num3.dnum[i-1]++;
}
if(num3.dnum[0]>9999) {
num3.dnum[0]%=10000;
for(i=0; i<(icount+3)/4 && num3.inum[i]>9999; i++) {
num3.inum[i]%=10000;
num3.inum[i+1]++;
}
num3.inum[i]%=10000;
}
if(MINUS == num3.sign) {
for(i = 0; i <= (num3.idigit+3)/4; i++) {
num3.inum[i] = 9999 - num3.inum[i];
}
for(i = 0; i < (num3.ddigit+3)/4; i++) {
num3.dnum[i] = 9999 - num3.dnum[i];
}
}
dcount=((icount+3)/4+1)*4;
icount=((dcount+3)/4)*4;
for(i=(num1.idigit+num2.idigit+2)/4; i>=0 && !num3.dnum[i]; i--) {
dcount-=4;
}
if(!(num3.dnum[i]%1000)) {
dcount-=3;
} else if(!(num3.dnum[i]%100)) {
dcount-=2;
} else if(!(num3.dnum[i]%10)) {
dcount-=1;
}
for(i=(num1.ddigit+num2.ddigit+2)/4; i>=0 && !num3.inum[i]; i--) {
icount-=4;
}
if(!(num3.inum[i]/10)) {
icount-=3;
} else if(!(num3.inum[i]/100)) {
icount-=2;
} else if(!(num3.inum[i]/100)) {
icount-=1;
}
num3.idigit=icount;
num3.ddigit=dcount;
return num3;
}
2.减法:该百年减数的符号即可,代码段如下:
HUGE subNum(HUGE num1, HUGE num2) {
HUGE num4={PLUS, NULL, NULL, 0, 0};
num2.sign = num2.sign==PLUS ? MINUS : PLUS;
num4=addNum(num1, num2);
return num4;
}
3.乘法:这里的乘法,就是我说的,相比于一个数组的简单的地方就体现出来了,我们将整数的最低位存在下标为0的整数数组单元中,将小数的最大位存在下标为0的小数数组单元中
然后就是规则,小数和小数,整数和整数是类似于整数操作的,但是整数和小数的乘法,就要进行验证和笔算了(整数下标-小数下标-1)中存想乘结果小于10000的部分,大于等于的存在这个单元的上一个小数单元或者下一个整数单元),具体代码段如下:
HUGE multyNum(HUGE num1, HUGE num2) {
int i;
int j;
int icount;
int dcount;
int count;
HUGE num5={PLUS, NULL, NULL, 0, 0};
num5.inum=(int *)calloc(sizeof(int), (num1.idigit+num2.idigit+2)/4+1);
num5.dnum=(int *)calloc(sizeof(int), (num1.ddigit+num2.ddigit+2)/4+1);
for(i=(num1.ddigit+3)/4-1; i>=0; i--) { //小数和小数相乘
for(j=(num2.ddigit+3)/4-1; j>=0; j--) {
num5.dnum[i+j]+=(num1.dnum[i]*num2.dnum[j])/10000;
num5.dnum[i+j+1]+=(num1.dnum[i]*num2.dnum[j])%10000;
}
for(i=(num1.idigit+3)/4-1; i>=0; i--) { //整数和整数相乘
for(j=(num2.idigit+3)/4-1; j>=0; j--) {
num5.inum[i+j]+=(num1.inum[i]*num2.inum[j])%10000;
num5.inum[i+j+1]+=(num1.inum[i]*num2.inum[j])/10000;
}
}
for(i=(num1.ddigit+3)/4-1; i>=0; i--) { //整数和小数相乘
for(j=(num2.idigit+3)/4; j>=0; j--) {
count=i-j-1;
if(count<-1) {
count=0-count-1;
num5.dnum[count]+=num1.dnum[i]*num2.inum[j]%10000;
num5.dnum[count-1]+=num1.dnum[i]*num2.inum[j]/10000;
} else if(count=-1) {
num5.dnum[0]+=num1.dnum[i]*num2.inum[j]%10000;
num5.inum[0]+=num1.dnum[i]*num2.inum[j]/10000;
} else {
num5.inum[count]+=num1.dnum[i]*num2.inum[j];
}
}
}
for(i=(num2.ddigit+3)/4-1; i>=0; i--) {
for(j=(num1.idigit+3)/4; j>=0; j--) {
count=i-j-1;
if(count<-1) {
count=0-count-1;
num5.dnum[count]+=num2.dnum[i]*num1.inum[j]%10000;
num5.dnum[count-1]+=num2.dnum[i]*num1.inum[j]/10000;
} else if(count=-1) {
num5.dnum[0]+=num2.dnum[i]*num1.inum[j]%10000;
num5.inum[0]+=num2.dnum[i]*num1.inum[j]/10000;
} else {
num5.inum[count]+=num2.dnum[i]*num1.inum[j];
}
}
}
dcount=(num1.ddigit+num2.ddigit+6)/4*4;
icount=(num1.idigit+num2.idigit+6)/4*4;
for(i=(num1.idigit+num2.idigit+2)/4; i>=0 && !(num5.inum[i]);i--) {
dcount-=4;
}
if(!(num5.dnum[i]%1000)) {
dcount-=3;
} else if(!(num5.dnum[i]%100)) {
dcount-=2;
} else if(!(num5.dnum[i]%10)) {
dcount-=1;
}
for(i=(num1.ddigit+num2.ddigit+2)/4; i>=0 && !num5.inum[i]; i--) {
icount-=4;
}
if(!(num5.inum[i]/10)) {
icount-=3;
} else if(!(num5.inum[i]/100)) {
icount-=2;
} else if(!(num5.inum[i]/100)) {
icount-=1;
}
num5.idigit=icount;
num5.ddigit=dcount;
return num5;
}
主函数:
int main() {
HUGE num1={PLUS, NULL, NULL, 0, 0};
HUGE num2={PLUS, NULL, NULL, 0, 0};
HUGE num3={PLUS, NULL, NULL, 0, 0};
HUGE num4={PLUS, NULL, NULL, 0, 0};
HUGE num5={PLUS, NULL, NULL, 0, 0};
inputFile("num1.txt");
num1=getNumFromFile("num1.txt");
printf("\nthe num1 is:\n");
showNum(num1);
inputFile("num2.txt");
num2=getNumFromFile("num2.txt");
printf("the num2 is:\n");
showNum(num2);
num3=addNum(num1, num2);
printf("the num3 is:\n");
showNum(num3);
num4=subNum(num1, num2);
printf("the num4 is:\n");
showNum(num4);
num5=muiltyNum(num1, num2);
printf("the num5 is:\n");
showNum(num5);
free(num1.inum);
free(num1.dnum);
free(num2.inum);
free(num2.dnum);
free(num3.inum);
free(num3.dnum);
free(num4.inum);
free(num4.dnum);
free(num5.inum);
free(num5.dnum);
return 0;
}
这篇博文,写于本人大一暑假,若有任何意见或建议,请积极提出,本人将在尽量短的时间内予以答复!!!