【问题标题】:Why the absolute value of the max negative integer -2147483648 is still -2147483648?为什么最大负整数-2147483648的绝对值还是-2147483648?
【发布时间】:2012-06-29 21:02:59
【问题描述】:

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):没有定义试图取最大负整数的绝对值。

标签: c libc


【解决方案1】:

标准说abs()

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

结果确实无法表示,因为有符号整数的 2 的补码表示不是对称的。想一想……如果int 中有 32 位,则从INT_MININT_MAX 为您提供了 232 个不同的值。这是偶数个值。因此,如果只有一个 0,则大于 0 的值的数量不能与小于 0 的值的数量相同。因此,对于值为 -INT_MININT_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 因为它还没有回答这个问题。
        猜你喜欢
        • 2021-02-26
        • 2012-09-19
        • 1970-01-01
        • 2020-08-20
        • 1970-01-01
        • 2017-07-16
        • 1970-01-01
        • 2013-04-28
        相关资源
        最近更新 更多