zoukankan      html  css  js  c++  java
  • 巨大数——三则运算(+、-、*)

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

    据我们所知,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("
    请输入要录入的数据:(输入#则停止录入)
    "); 
    
    	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("
    ");
    		}
    		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("
    ERROR!!!
    ");
    		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("
    the num1 is:
    ");
    	showNum(num1);
    	inputFile("num2.txt");
    	num2=getNumFromFile("num2.txt");
    	printf("the num2 is:
    ");
    	showNum(num2);
    	num3=addNum(num1, num2);
    	printf("the num3 is:
    ");
    	showNum(num3);
    	num4=subNum(num1, num2);
    	printf("the num4 is:
    ");
    	showNum(num4);
    	num5=muiltyNum(num1, num2);
    	printf("the num5 is:
    ");
    	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("
    请输入要录入的数据:(输入#则停止录入)
    "); 
    
    	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("
    ");
    		}
    		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("
    ERROR!!!
    ");
    		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("
    the num1 is:
    ");
    	showNum(num1);
    	inputFile("num2.txt");
    	num2=getNumFromFile("num2.txt");
    	printf("the num2 is:
    ");
    	showNum(num2);
    	num3=addNum(num1, num2);
    	printf("the num3 is:
    ");
    	showNum(num3);
    	num4=subNum(num1, num2);
    	printf("the num4 is:
    ");
    	showNum(num4);
    	num5=muiltyNum(num1, num2);
    	printf("the num5 is:
    ");
    	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;
    }
    

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

  • 相关阅读:
    Power BI 根据用户权限动态生成导航跳转目标
    Power BI Tooltips 增强功能
    Power BI refresh error “could not load file or assembly…provided impersonation level is invalid”
    SQL 错误代码 18456
    如何使用SQL Server Integration Services从多个Excel文件读取数据
    通过表格编辑器将现有表引入Power BI数据流
    Power BI 中动态增长的柱状图
    ambari2.7.3离线安装hdp3.1.0时,ambari-hdp-1.repo中baseurl无值
    ambari 安装 cannot download file mysql-connector-java from http://8080/resource/mysql-connector-java.jar
    洛谷P4180 [BJWC2010]严格次小生成树
  • 原文地址:https://www.cnblogs.com/codderYouzg/p/12412033.html
Copyright © 2011-2022 走看看