[英]Adding 32 bit signed in C
我已经得到了这个问题,并想用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位寄存器实现long类型,以便我可以正确打印该值。 有人可以帮助我如何使用下溢和上溢信息,以便我可以将结果正确存储在c变量中,我认为应该是2个32位位置。 我认为问题所在就是暗示不支持该长度。 变量c是否将2个32位寄存器组合在一起以保持正确的结果以便可以打印? 当结果过大或过少时,我应该执行什么操作?
由于这是一个家庭作业问题,因此我将尽量避免完全破坏它。
这里一个令人讨厌的方面是,结果比您所允许使用的任何结果都要大(我解释说禁止long long
时间也包括int64_t
,否则实际上没有意义)。 可能很想为结果值使用“两个整数”,但这对解释它的值很奇怪。 因此,我将使用两个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上 。
首先,满足上述要求的最简单解决方案:
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);
}
剩下的工作是将其转换为带符号的数量。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.