我遇到了这个问题,想在C中解决它:
假设您有一个32位处理器,并且C编译器不支持long long(或long int)。写一个函数add(a,b),它返回c = a + b,其中a和b是32位整数。
我写了这段能够检测溢出和下溢的代码
#define INT_MIN (-2147483647 - 1) /* minimum (signed) int value */
#define INT_MAX 2147483647 /* maximum (signed) int value */
int add(int a, int b)
{
if (a > 0 && b > INT_MAX - a)
{
/* handle overflow */
printf("Handle over flow\n");
}
else if (a < 0 && b < INT_MIN - a)
{
/* handle underflow */
printf("Handle under flow\n");
}
return a + b;
}
我不确定如何使用32位寄存器实现长时间,以便我可以正确打印该值。有人可以帮助我如何使用下溢和溢出信息,以便我可以正确地将结果存储在c变量中,我认为应该是2个32位的位置。我认为这就是问题在暗示长期不受支持的时候所说的。变量c是2个32位寄存器放在一起以某种方式保持正确的结果,以便它可以打印?当结果超过或低于流量时,我应该采取什么行动?
答案 0 :(得分:2)
由于这是一个家庭作业问题,我不会完全破坏它。
这里有一个恼人的方面,结果比你允许使用的任何内容都要大(我将long long
的禁令解释为还包括int64_t
,否则确实存在没有意义)。可能很想去&#34;两个整体&#34;对于结果值,但解释值的奇怪之处。所以我选择两个uint32_t
并将它们解释为64位二进制补码整数的两半。
无符号多字添加很容易,已被多次覆盖(只搜索)。如果输入是符号扩展的,则签名的变体实际上是相同的:(未测试)
uint32_t a_l = a;
uint32_t a_h = -(a_l >> 31); // sign-extend a
uint32_t b_l = b;
uint32_t b_h = -(b_l >> 31); // sign-extend b
// todo: implement the addition
return some struct containing c_l and c_h
显然,当解释签名时,它不会溢出64位结果。 可以(有时候应该)。
要打印那件事,如果是作业的一部分,首先要了解哪些值c_h
可以有。没有多少可能性。使用现有的整数打印功能打印应该很容易(也就是说,你不必编写一个完整的多字 - itoa,只需处理几个案例)。
作为补充的提示:当你添加两个十进制数字并且结果大于9时会发生什么?为什么7 + 6 = 13的低位数为3?仅给出7,6和3,如何确定结果的第二位?您应该能够将所有这些应用于基础2 32 。
答案 1 :(得分:0)
首先,满足所述问题的最简单的解决方案:
double add(int a, int b)
{
// this will not lose precision, as a double-precision float
// will have more than 33 bits in the mantissa
return (double) a + b;
}
更严重的是,教授可能预计这个数字会被分解成一个整数组合。保持两个32位整数之和需要33位,可以用进位标志的int和位表示。为简单起见假设无符号整数,添加将如下实现:
struct add_result {
unsigned int sum;
unsigned int carry:1;
};
struct add_result add(unsigned int a, unsigned int b)
{
struct add_result ret;
ret.sum = a + b;
ret.carry = b > UINT_MAX - a;
return ret;
}
更难的部分是对结果做一些有用的事情,比如打印它。正如harold所提出的,打印功能不需要进行完全分割,它可以简单地覆盖可能的大33位值并对这些范围的第一个数字进行硬编码。这是一个实现,再次限于无符号整数:
void print_result(struct add_result n)
{
if (!n.carry) {
// no carry flag - just print the number
printf("%d\n", n.sum);
return;
}
if (n.sum < 705032704u)
printf("4%09u\n", n.sum + 294967296u);
else if (n.sum < 1705032704u)
printf("5%09u\n", n.sum - 705032704u);
else if (n.sum < 2705032704u)
printf("6%09u\n", n.sum - 1705032704u);
else if (n.sum < 3705032704u)
printf("7%09u\n", n.sum - 2705032704u);
else
printf("8%09u\n", n.sum - 3705032704u);
}
将此转换为已签名的数量留作练习。