为什么最大负整数-2147483648的绝对值仍然是-2147483648?

时间:2012-06-28 10:51:11

标签: c libc

abs(-2147483648)的结果是-2147483648,不是吗? 这似乎是不可接受的。

printf("abs(-2147483648): %d\n", abs(-2147483648));

输出:

abs(-2147483648): -2147483648

5 个答案:

答案 0 :(得分:20)

标准说明abs()

  

abslabsllabs函数计算整数j的绝对值。如果无法表示结果,则行为未定义。

结果确实无法表示,因为有符号整数的2的补码表示不对称。考虑一下......如果int中有32位,那么从INT_MININT_MAX可以得到2个 32 个不同的值。这是偶数个值。因此,如果只有一个0,则大于0的值的数量不能与小于0的值的数量相同。因此INT_MIN的值与 - INT_MIN没有正对应关系。

所以,在你的平台上调用abs(INT_MIN)是不可接受的。

答案 1 :(得分:13)

负数通常表示为二进制补码。

要将正转换为负数,请使用逻辑

x -> not(x)+1

对于8位算术

01111111b是127,-127变为
10000000b + 1 = 10000001b

并向相反方向-127 10000001b成为
01111110b + 1 = 01111111b

-128怎么样?

-128是10000000b并且它没有正对应物,因为在8位有符号算术中没有128。

10000000 - > 01111111 + 1 = 10000000和-128再次

同样适用于原始问题

答案 2 :(得分:10)

由于2147483648在您的实施中大于INT_MAX,因此abs(-2147483648)未定义。

答案 3 :(得分:5)

这是GNU glibc源代码中abs.c中的代码。

/* Return the absolute value of I.  */
int
DEFUN(abs, (i), int i)
{
  return(i < 0 ? -i : i);
}

所以,abs(-2147483648)返回 - ( - 2147483648)。在x86中,它是由这两条指令实现的

movl    $-2147483648, %eax
negl    %eax

negl指令通过这种方式实现: NUM = 0-NUM; sbb通过这种方式实现: 从目的地中减去源,如果设置了进位标志,则减去1个额外值。 所以abs(-2147483648)(十六进制是0x80000000) - &gt; - ( - 2147483648) - &gt; 0 - ( - 2147483648)最终成为(0x80000000)。

请忽略指示的细节 访问http://zsmith.co/intel_n.html#neg

sbb指令的详细信息,请访问http://web.itu.edu.tr/kesgin/mul06/intel/instr/sbb.html

答案 4 :(得分:-5)

试试这个

printf("abs(-2147483648): %u\n", abs(-2147483648));