巨大数加减法(微易码补码)

通常的加减法是用元素本身进行加减,加法直接相加,找进位。减法先判断两个数大小,用大数减小数再判断是否加负号。
而这次加减法利用的是微易码补码。
因为计算机利用补码来通过加法完成不带借位的减法,教主利用这种思想研究出了微易码补码。
微易码补码:
①若数据为整数,则补码为其本身
②若数据为负数,则每个元素的补码为9999 - 该元素

加减计算总共三种:
①正+正
②正+负
③负+负

重点需要考虑进位的问题
列出各种情况和中心问题后,下面举一些例子深入理解一下:
巨大数加减法(微易码补码)_第1张图片
巨大数加减法(微易码补码)_第2张图片
综上得出先把计算数转成补码再从低位开始计算,故翻转函数是必要的。
转换补码中因为有进位的问题,需要额外补一个元素,正负补0、负数补9999。
符号由两个计算数符号与“逻辑进位”异或运算得出。
对于含有负数的计算结果还需加上“逻辑进位”才是正确答案。
若结果为负数,还需要进行解码得出答案。

转换补码函数:
首先对于位数不同的数,补码及结果需要按最长的哪个长度计算。

int getComSize(HUGE huge1, HUGE huge2) {
     
	return huge1.size >= huge2.size ? huge1.size : huge2.size;
}

得出长度后就可以进行补码转换了:

boolean makeComplement(HUGE huge, HUGE *com, int size) {
     
	int count;
	int i;
	int j;
	int sign;
	int head;
	sign = huge.sign;
	head = (huge.size + 3) / 4 + 1;
	count = (size + 3) / 4 + 1;
	com->sign = sign;
	com->size = count * 4 - 3;
	com->data = (int *) calloc(sizeof(int), count);

	if (1 == sign) {
     
		for (i = 0; i < count - head; i++) {
     
			com->data[i] = 9999;
		}
		for (i = count - head, j = 0; i < count; i++, j++) {
     
			com->data[i] = 9999 - huge.data[j];
		}
	} else {
     
		for (i = 0; i < count - head; i++) {
     
			com->data[i] = 0;
		}
		for (i = count - head, j = 0; i < count; i++, j++) {
     
			com->data[i] = huge.data[j];
		}
	}

	reverse(com);
}

注:对于差位的数,正数补0,负数补9999

对应的解码函数:

boolean decode(HUGE *com) {
     
	int i;
	int count;
	count = (com->size + 3) / 4;
	if (1 == com->sign) {
     
		for (i = 0; i < count; i++) {
     
			com->data[i] = 9999 - com->data[i];
		}
	}
	reverse(com);

	return TRUE;
}

解码补码写完就开始着手具体加减法:

boolean addorsub(HUGE huge1, HUGE huge2, HUGE *result) {
     
	HUGE com1;
	HUGE com2;
	int i;
	int size;
	int count;
	int tmp = 0;
	int data;
	int sign;
	int first = 1;

	size = getComSize(huge1, huge2);
	makeComplement(huge1, &com1, size);
	makeComplement(huge2, &com2, size);
	count = (size + 3) / 4 + 1;
	result->size = size;
	result->data = (int *) calloc(sizeof(int), count);

	for (i = 0; i < count; i++) {
     
		data = com1.data[i] + com2.data[i] + tmp;
		tmp = data / 10000;
		data %= 10000;
		result->data[i] = data;
	}
	sign = tmp;
	if (1 == com1.sign || 1 == com2.sign) {
     
		for (i = 0; i < count; i++) {
     
			data = result->data[i] + tmp;
			tmp = data / 10000;
			data %= 10000;
			result->data[i] = data;
		}
	}

	result->sign = com1.sign ^ com2.sign ^ sign;
	tmp = count;

	if (0 == result->data[0] || 9999 == result->data[0]) {
     
		for (i = 0; i < count; i++) {
     
			result->data[i] = result->data[i + 1];
		}
		tmp--;
	}
		
	result->size = tmp * 4 - 3;
	decode(result);

	destoryData(com1);
	destoryData(com2);
}

对于加减法的进位由data / 10000得出,本位数据由data % 10000得出。
对于防止出现0 1234这种0开头的显示,对计算结果需要进行一次操作。

你可能感兴趣的:(巨大数加减法(微易码补码))