大整数加减乘除

用指定位数的数组存储大整数,每一位对应一位,若大整数长度小于数组长度,索引已0开始的称高位,高位补零

即int a[10]存储数值为:123456

a[0]  a[1]  a[2]  a[3] a[4]  a[5]  a[6]  a[7]  a[8] a[9] 

 0       0      0      0     1      2     3       4      5      6

简写:00000123456

这里的分析和实现为10进制当然可以类比为16进制,8进制,2进制

#1 大整数加法

分析:对位相加,若结果大于0,将结果-10,高位增1

实现如下:

/**
 * a,b为大整数的两个加数,c存储大整数加后结果,len为数组长度(即大整数最多位数)
 */
void bignum_add(int a[],int b[],int c[],int len){
	for(int i = 0; i <len; i++) c[i] = 0;
	for(int i = len-1; i >= 0; i--){
		c[i] += a[i]+b[i];
		if( c[i] >= 10){
			c[i]-=10;
			c[i-1] +=1;
		}
	}
}

#2 大整数减法

分析:对位相减后,若结果小于0,高位借一,将结果+10

实现:

void big_subtract(int a[],int b[],int len){
	int j;
	for(j = 0; j < len; j++) if(a[j] != 0) break;
	for(int i = len-1; i >= j; i--){
		a[i] = a[i]-b[i];
		if( a[i] < 0){
			a[i-1]-=1;
			a[i]+=10;
		}
	}
}

#3 大整数乘法

分析:

实现如下:

void bignum_multply(int a[],int b[],int c[],int len){
	for(int z = 0; z < len; z++) c[z] = 0;
	int i,j,k;
	for(i = 0; i <len; i++) if(a[i] != 0) break; //i++得到的高位所有0的个数 len-i即a的位数
	for(j = 0; j <len; j++) if(b[j] != 0) break; //同上 len-j即b的位数
	int x = 0;
	int y = 0;
	for(int m = len-1; m >= i; m--,x++){
		y = 0;
		for(int n = len-1; n >= j; n--,y++){
			c[len-1-(x+y)] += a[m]*b[n];
		}
	}
	for(k = 0; k <len; k++) if(c[k] != 0) break;
	for(; k < len; k++){
		//printf("%d ",c[k]);
		int time = 0;
		while(c[k]>=10) {
			c[k] -= 10;
			time++;
		}
		c[k-1] += time;
	}
	//printf(" \n i=%d j=%d x=%d y=%d \n",i,j,x,y);
}

#4 大整数除法

分析:

例:1000 / 23 

1‘ 我们要思考一个数是不是可以被一个数除

   所以,判断除数是否小于被除数,若小于则不能被除

2’ 4000/23 = 173.91,可以表示为195,R=21

    4000 - 2300*1 = 1700,

    1700 -  230*7 = 90,

    90  -  23*3 = 21 = R

   根据如上步骤我们可以得出规律

 1‘  除数左移n位低位补0 ,最多移位为被除数位数-除数位数(被除数为n位,除数为m位,则商最多整数位为n-m位)

  2’ 将除数左移位数 至 被除数长度时,若能减多少个数,个数对应商整数位,n=1,为个位,n=2为十位,n=3为百位......

  3‘ 直至不能被减得到余数R

实现如下:

// 判断是否可除,即可减
int a_bigger_b(int a[],int b[],int len){
	int i,j; //去除高位所有0后i,j为大数开始下标
	for(i = 0; i < len; i++) if(a[i] != 0) break;
	for(j = 0; j < len; j++) if(b[j] != 0) break;
	// 被除数和除数位数不一样
	if((len-i) != (len-j)) return (len-i) > (len-j);
	for(; i < len; i++){
		if(a[i] < b[i]) return 0;
		else if(a[i] == b[j]) continue;
		else return 1; //最高位大于则可以做减法
	}
	return 1;
}
//低位补领零或加零
//	sub_or_add_zero(1,num1, num_maxlen,4);左移4位,地位补0
//	sub_or_add_zero(0,num1, num_maxlen,3);右移三位,高位补0
void sub_or_add_zero(int flag,int b[],int len,int num){
	int i; //去除高位所有0后i,j为大数开始下标
	for(i = 0; i < len; i++) if(b[i] != 0) break;
	if(flag==1){
		//移位
		for(; i < len; i++){
			b[i-num] = b[i];
		}
		//移位后附0
		for(int j = len -1; j >= (len-num);j--){
			b[j]=0;
		}
	}
	else if(flag==0){
		//移位除零
		for(int j = len - 1; j >= i; j--){
			b[j] = b[j-num];
		}
		while(num){
			b[i+num-1] = 0;
			num--;
		}
	}
}

int bignum_divide(int a[],int b[],int len){
	int i,j; //去除高位所有0后i,j为大数开始下标
	for(i = 0; i < len; i++) if(a[i] != 0) break;
	for(j = 0; j < len; j++) if(b[j] != 0) break;
	int ans = 0;
	sub_or_add_zero(1,b,len,j-i);
	for(int k = 0; k <= (j-i); k++){ //长度相等循环一次
		int time = 0;
		while(a_bigger_b(a, b, len)==1){
			big_subtract(a, b, len);
			time++;
		}
		if(a_bigger_b(a, b, len) == a_bigger_b(b, a, len)) time = 1;
		ans = ans*10 +time;
		sub_or_add_zero(0,b,len,1);
	}
	return ans;
}

测试结果:

int main(void){
	int num_maxlen = 100;
	int num1[num_maxlen];
	printf("-------pow(x,n) x^n--------\n");
	int x = 2;
	int n = 100;
	bignum_pow(x,n,num1,num_maxlen);
	printf("%d^%d result :",x,n);print_bignum(num1, num_maxlen);
	printf("\n---------------\n");
	int num2[num_maxlen];
	bignum_pow(3,1,num2,num_maxlen);
	printf("-------bitnum to add--------\n");
	int num3[num_maxlen];
	printf("the bignums are :[");print_bignum(num1, num_maxlen);printf("] , [");print_bignum(num2, num_maxlen);printf("]");
	bignum_add(num1,num2,num3,num_maxlen);
	//big_subtract(num1,num2,num3,num_maxlen);
	printf("\nresult :");print_bignum(num3, num_maxlen);
	printf("\n---------------\n");
	printf("-------bitnum to multply--------\n");
	int num4[num_maxlen];
	printf("the bignums are :[");print_bignum(num1, num_maxlen);printf("] , [");print_bignum(num2, num_maxlen);printf("]");
	bignum_multply(num1,num2,num4,num_maxlen);
	printf("\nresult :");print_bignum(num4, num_maxlen);
	printf("\n---------------");
	printf("-------biStnum to divide--------\n");
	printf("the bignums are :[");print_bignum(num1, num_maxlen);printf("] , [");print_bignum(num2, num_maxlen);printf("]");
	printf("\nresult : ans = %d R=",bignum_divide(num1, num2, num_maxlen));print_bignum(num1, num_maxlen);
	printf("\n---------------");
	return 0;
}

result:

-------pow(x,n) x^n-------------------------
2^100 result :1267650600228229401496703205376
---------------------------------------------------
-------bitnum to add-------------------------
the bignums are :[1267650600228229401496703205376] , [3]
result :1267650600228229401496703205379
---------------------------------------------------
-------bitnum to multply---------------------
the bignums are :[1267650600228229401496703205376] , [3]
result :3710295180068468820448101096151128
----------------------biStnum to divide--------
the bignums are :[1267650600228229401496703205376] , [3]
result : ans = 1431655765 R=1
-----------------------------------------------------

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值