【问题标题】:Representation of negative numbers in C?C中负数的表示?
【发布时间】:2011-04-26 12:17:15
【问题描述】:

C如何表示负整数?

是通过二进制补码表示还是使用 MSB(最高有效位)?

十六进制的-1ffffffff

所以请为我澄清这一点。

【问题讨论】:

  • 当然取决于机器,尽管参考列出了 - 我相信 - 三个变体。字节顺序与数字的内存布局有关:对于 4 字节 ABCD、DCBA、BADC:(uint8_t*)intptr

标签: c language-lawyer negative-number twos-complement


【解决方案1】:

ISO C(在这种情况下为C99 section 6.2.6.2/2,但它延续到标准的后续迭代(a))声明实现必须为整数数据类型选择三种不同的表示形式之一,两个补码,一个的补码或符号/大小(尽管两者的补码实现很可能远远超过其他)。

在所有这些表示中,正数是相同的,唯一的区别是负数。

要获得正数的负表示,您:

  • 将所有位取反,然后为二进制补码加一。
  • 将所有位反转为反码。
  • 仅反转符号/大小的符号位。

您可以在下表中看到这一点:

号码 |二进制补码|补码|符号/大小 =======|======================|==================== =|===================== 5 | 0000 0000 0000 0101 | 0000 0000 0000 0101 | 0000 0000 0000 0101 -5 | 1111 1111 1111 1011 | 1111 1111 1111 1010 | 1000 0000 0000 0101

请记住,ISO 并不要求在表示中使用所有位。他们介绍了符号位、值位和填充位的概念。现在我从未真正看到使用填充位的实现,但是,从 C99 基本原理文档中,他们有这个解释:

假设一台机器使用一对 16 位的 short(每个都有自己的符号位)来组成一个 32 位的 int,并且在这个 32 位的 int 中使用时忽略低位 short 的符号位。然后,作为 32 位有符号整数,有一个填充位(在 32 位中间)在确定 32 位有符号整数的值时会被忽略。但是,如果这个 32 位项被视为 32 位无符号整数,则该填充位对用户程序是可见的。 C 委员会被告知有一台机器可以以这种方式工作,这就是在 C99 中添加填充位的原因之一。

我相信他们所指的机器可能是 Datacraft 6024(它是 Harris Corp 的继任者)。在那些机器中,您有一个 24 位字用于有符号整数,但是,如果您想要更宽的类型,它将其中两个作为 47 位值串在一起,其中一个字的符号位被忽略:

+---------+-----------+--------+-----------+
| sign(1) | value(23) | pad(1) | value(23) |
+---------+-----------+--------+-----------+
\____________________/ \___________________/
      upper word            lower word

(a) 有趣的是,考虑到真正使用其他两种方法的现代实现的稀缺性,人们一直在推动将二进制补码作为一种真正的方法来接受.这已在 C++ 标准中采用 quite a long way(WG21 是负责此的工作组),现在显然也在考虑用于 C(由 WG14)。

【讨论】:

  • 让我想知道为什么(看似)最复杂的变体二进制补码是最受欢迎的。翻转单个位(符号/幅度)或仅翻转所有位(补码)似乎更简单。我想二进制补码的流行与它的工作原理无关,而是与机器实现的流行程度有关(出于其他技术或营销原因)?
  • @FrerichRaabe 直接来自维基百科“二进制算术不起作用。”本质上,加法器如何知道它的负数和正数。 simple.wikipedia.org/wiki/Signed_number_representations
  • @JRSmith 页面有点弱;过去肯定有 1 的补码和符号大小。事实上,IEC60559 浮点使用符号幅度和算术工作得很好。
  • @FrerichRaabe:如果您认识到对于任何整数 x 和 y 以及整数 N,在使用理智的编译器时,x+y、xy、或 x*y 将不依赖于 x 和 y 的底部 N 位以外的任何内容。
  • 20 是来自 C99 基本原理的复制粘贴错误。我发现允许填充位位于值位的中间很有趣。引用的文本有点自相矛盾,填充位对于有符号是不可见的,但对于无符号是可见的。那有什么意思。就 C 标准而言,它仍然是一个填充位,对值没有贡献。想法?
【解决方案2】:

C 允许有符号整数的符号/大小、一个补码和二进制补码表示。大多数典型的硬件对整数使用二进制补码,对浮点使用符号/幅度(还有另一种可能性——浮点指数的“偏差”表示)。

【讨论】:

    【解决方案3】:

    -1 十六进制是 ffffffff。所以请在这方面澄清一下。

    在二进制补码(迄今为止最常用的表示)中,除最高有效位 (MSB) 之外的每一位从右到左(数量级递增)的值为 2n,其中n 从零增加一。 MSB 的值为 -2n

    例如在一个 8 位二进制补码整数中,MSB 的位值为 -27 (-128),因此二进制数:1111 11112等于 -128 + 0111 11112 = -128 + 127 = -1

    二进制补码的一个有用特性是处理器的 ALU 只需要一个加法器块即可通过形成右手操作数的二进制补码来执行减法。例如 10 - 6 等价于 10 + (-6);在 8 位二进制中(为了解释简单),这看起来像:

       0000 1010
      +1111 1010
       ---------
    [1]0000 0100  = 4 (decimal)
    

    其中 [1] 是丢弃的进位位。另一个例子; 10 - 11 == 10 + (-11):

       0000 1010
      +1111 0101
       ---------
       1111 1111  = -1 (decimal)
    

    二进制补码的另一个特点是它有一个表示零的值,而符号幅度和一个补码各有两个; +0 和 -0。

    【讨论】:

      【解决方案4】:

      对于整数类型,它通常是二进制补码(特定于实现)。对于浮点,有一个符号位。

      【讨论】:

        猜你喜欢
        • 2016-02-20
        • 2023-04-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-04-10
        • 2015-08-10
        • 1970-01-01
        相关资源
        最近更新 更多