添加32位C签名

时间:2015-09-19 15:00:24

标签: c c89

我遇到了这个问题,想在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位寄存器放在一起以某种方式保持正确的结果,以便它可以打印?当结果超过或低于流量时,我应该采取什么行动?

2 个答案:

答案 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);
}

将此转换为已签名的数量留作练习。