巨大数——三则运算(+、-、*)

这篇博文,主要讲解了一个思想 —— 将字符串转换为数值,再转换为结构体,以及部分文件操作的复习使用。
那么,回归主题:

据我们所知,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(这个简便算法,由关系可以推出)

那么,所谓”微易码补码“,正是借鉴了这里的知识,很好地处理了 正数加负数 的问题,
使得在加的过程中,不会出现因为符号做减法的问题。
这里来讲解它的用法:

  1. 正数的补码——正数本身
    负数的补码——每一位取9减该位的值(因为原码补码是建立在二进制层面上,而我们的操作,是面向十进制数的)
  2. 每个对应单元相加,若大于9999,则要进位,并将该单元的数和10000取余(或者直接减去10000也行) .之后再根据(符号相等 ?0 :1)^ (最高位进位 ?1 : 0)
    若结果为1,个位加一,符号为负号;结果为0,个位不加,符号为正号
  3. 最后若为负号,则各位的值为用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;
}

这篇博文,写于本人大一暑假,若有任何意见或建议,请积极提出,本人将在尽量短的时间内予以答复!!!

posted @ 2020-03-04 20:40  在下右转,有何贵干  阅读(983)  评论(0编辑  收藏  举报