K&R 练习 3-4:用二进制表示的负数

K&R Exercise 3-4: Negative Numbers Represented In Binary

我很难理解这个练习:

In a two's complement number representation, our version of itoa does not handle the largest negative number, that is, the value of n equal to -(2^(wordsize-1)). Explain why not. Modify it to print that value correctly, regardless of the machine on which it runs.

这是 itoa 的原始样子:

void reverse(char s[], int n)
{
  int toSwap;
  int end = n-1;
  int begin = 0;

  while(begin <= end) // Swap the array in place starting from both ends.
    {
      toSwap = s[begin];
      s[begin] = s[end];
      s[end] = toSwap;

      --end;
      ++begin;
    }
}

// Converts an integer to a character string.
void itoa(int n, char s[])
{
  int i, sign;
  if ((sign = n) < 0)
    n = -n;
  i = 0;
  do
    {
      s[i++] = n % 10 + '0';
    } while ((n /= 10) > 0);

  if (sign < 0)
    s[i++] = '-';
  s[i] = '[=10=]';
  reverse(s, i);
}

我找到了这个答案,但我不明白解释: http://www.stevenscs.com/programs/KR/$progs/KR-EX3-04.html

Because the absolute value of the largest negative number a word can hold is greater than that of the largest positive number, the statement early in iota that sets positive a negative number corrupts its value.

他们是说负数因为有符号比没有符号的正数包含更多的位数吗?为什么乘以 -1 会影响大负数的存储方式?

问题是,如果 n 是最大的负数,当你执行 n=-n 时你得到 0,因为你不能表示那么大的正数。

一个解决方案是将正数保存在一个长整数中。

在补码表示中,你可以表示的取值范围是-2<sup>n-1</sup>2 <sup>n-1</sup>-1。因此,使用 8 位,您可以表示 -128 到 127 范围内的值。这就是短语 "the largest negative number a word can hold is greater than that of the largest positive number."

的含义

仅用 3 位进行说明以使其更清晰:

Value    Bits
-----    ----
    0    000
    1    001
    2    010
    3    011
   -4    100
   -3    101
   -2    110
   -1    111

用 3 位,我们无法用二进制补码表示 正数 4,所以 n = -n; 不会给我们结果期待1。这就是为什么上面的原始 atoi 实现无法处理 INT_MIN.


  1. 有符号整数溢出的行为是未定义,这意味着没有固定的结果。