为啥最大负整数-2147483648的绝对值还是-2147483648?
Posted
技术标签:
【中文标题】为啥最大负整数-2147483648的绝对值还是-2147483648?【英文标题】:Why the absolute value of the max negative integer -2147483648 is still -2147483648?为什么最大负整数-2147483648的绝对值还是-2147483648? 【发布时间】:2012-06-28 10:51:10 【问题描述】:abs(-2147483648) 的结果是-2147483648,不是吗? 这似乎是不可接受的。
printf("abs(-2147483648): %d\n", abs(-2147483648));
输出:
abs(-2147483648): -2147483648
【问题讨论】:
我相信这是未定义的行为。我手边没有 C 标准,所以无法备份。 鉴于abs(int)
返回int
,您期望它是什么?
C11 的最新草案说(7.21.6.1,关于abs 和朋友)“如果结果无法表示,则行为未定义”
@PhilipKendall 绝对值可以是负值吗?
linux 手册页说(man 3 abs):没有定义试图取最大负整数的绝对值。
【参考方案1】:
标准说abs()
:
abs
、labs
和llabs
函数计算整数j
的绝对值。如果结果无法表示,则行为未定义。
结果确实无法表示,因为有符号整数的 2 的补码表示不是对称的。想想看……如果你在 int
中有 32 位,这会给你从 INT_MIN
到 INT_MAX
的 232 个不同的值。这是偶数个值。因此,如果只有一个 0,则大于 0 的值的数量不能与小于 0 的值的数量相同。因此,对于值为 -INT_MIN
的 INT_MIN
没有正对应项。
所以,在您的平台上调用abs(INT_MIN)
是不可接受的。
【讨论】:
【参考方案2】:负数通常用二进制补码表示。
要将正数转换为负数,使用逻辑
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 再次
同样适用于原始问题
【讨论】:
这就是为什么0和最小值在二进制补码中取反后总是相同的原因【参考方案3】:由于在您的实现中 2147483648 大于 INT_MAX
,因此 abs(-2147483648)
未定义。
【讨论】:
【参考方案4】:这是 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 指令是这样实现的: 数=0-数; sbb是这样实现的: 从目标中减去源,如果设置了进位标志,则额外减去 1。 所以 abs(-2147483648) (hex is 0x80000000 ) --> -(-2147483648) --> 0-(-2147483648) 最后变成了 (0x80000000)。
negl指令的详细信息,请 访问http://zsmith.co/intel_n.html#neg
sbb指令详情,请访问http://web.itu.edu.tr/kesgin/mul06/intel/instr/sbb.html
【讨论】:
【参考方案5】:试试这个
printf("abs(-2147483648): %u\n", abs(-2147483648));
【讨论】:
我的朋友,这有未定义的行为。您正在使用无符号格式化程序打印一个有符号整数。我 -1 因为它还没有回答问题。以上是关于为啥最大负整数-2147483648的绝对值还是-2147483648?的主要内容,如果未能解决你的问题,请参考以下文章