通常的加减法是用元素本身进行加减,加法直接相加,找进位。减法先判断两个数大小,用大数减小数再判断是否加负号。
而这次加减法利用的是微易码补码。
因为计算机利用补码来通过加法完成不带借位的减法,教主利用这种思想研究出了微易码补码。
微易码补码:
①若数据为整数,则补码为其本身
②若数据为负数,则每个元素的补码为9999 - 该元素
加减计算总共三种:
①正+正
②正+负
③负+负
重点需要考虑进位的问题
列出各种情况和中心问题后,下面举一些例子深入理解一下:
综上得出先把计算数转成补码再从低位开始计算,故翻转函数是必要的。
转换补码中因为有进位的问题,需要额外补一个元素,正负补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开头的显示,对计算结果需要进行一次操作。