【问题标题】:Two's complement binary form二进制补码形式
【发布时间】:2010-10-13 21:43:39
【问题描述】:

在 TC++ 编译器中,5 的二进制表示为 (00000000000000101)。 我知道负数存储为 2 的补码,因此二进制中的 -5(111111111111011)。最高有效位(符号位)是 1,表示它是负数。

那么编译器怎么知道是-5呢?如果我们将上面给出的二进制值 (111111111111011) 解释为无符号数,结果会完全不同?

另外,为什么5 -6 (1111111111111010)是1的恭维?

【问题讨论】:

    标签: c++ binary twos-complement


    【解决方案1】:

    编译器不知道。如果您将-5 转换为unsigned int,您将得到32763

    【讨论】:

    • 是的,演员表告诉编译器如何解释某个内存位置的位。一般来说,它对什么存在于哪里有自己的想法,但是演员阵容会影响事物。
    • 好吧,你甚至不必进行显式转换。
    • 是的,编译器只是做数学运算。如果你将 -5 转换为无符号整数,结果总是 UINT_MAX+1-5,它是否有符号大小/二补码/一补码是无关紧要的。
    • 等等,这不是说编译器知道吗? cpu 只是做数学运算,编译器将结果解释为有符号或无符号。对吗?
    • 如果我使用signed int a = 2,那么编译器怎么知道它是负数还是正数?
    【解决方案2】:

    编译器知道,因为这是 CPU 原生使用的约定。您的计算机有一个 CPU,它以二进制补码表示法存储负数,因此编译器也会效仿。如果您的 CPU 支持补码表示法,编译器会使用它(顺便说一下,IEEE 浮点数就是这种情况)。

    关于该主题的 Wikipedia 文章解释了 two's complement 表示法的工作原理。

    【讨论】:

    • +1:引用一些有用的文档; +1:它是硬件; +1:编译器对数字一无所知——你声明它有符号或无符号——然后你必须与声明一致地使用它。
    【解决方案3】:

    处理器实现有符号和无符号指令,它们将以不同的方式对二进制数表示进行操作。编译器根据所涉及的操作数的类型(即intunsigned int)知道要发出哪些指令。

    编译器不需要知道一个数字是否为负,它只是为所涉及的类型发出正确的机器或中间语言指令。这些指令的处理器或运行时的实现通常不太关心数字是否为负,因为二进制补码算法的公式对于正数或负数是相同的(事实上,这是主要的补码算法的优势)。 需要知道一个数字是否为负数,例如 printf(),正如 Andrew Jaffe 指出的那样,设置的 MSBit 表示二进制补码中的负数。

    【讨论】:

    • 如果我写 signed int a = -1 ,那么 2 的补码形式中的 `-1` 是 11111111 11111111 11111111 11111111 然后当我使用 %d 解释它时,它会打印 -1 和 %u ,它打印 4294967295 并且当我写 signed int a = 2 时,它在我使用 %d 以及当我使用 %u 时打印 2 。如果 2 在二进制补码中,它将是 11111111 11111111 11111111 11111101,然后这将是一个非常不同的答案,我真正想问的是 2 的补码何时发生是它取决于 - 符号还是它发生在每个整数如果type 是有符号的 int,这里一定不是这种情况。
    【解决方案4】:

    第一位只为负数设置(称为符号位)

    详细信息可here

    【讨论】:

    • 但是对于 unsigned int 可以设置第一位,它仍然是正数。
    【解决方案5】:

    二进制补码的kewl部分是机器语言的加减指令可以忽略所有这些,只做二进制算术就可以了……

    即-3 + 4

    在二进制 2 的补码中,是

       1111 1111 1111 1101   (-3)
    +  0000 0000 0000 0100   ( 4)
       -------------------
       0000 0000 0000 0001   ( 1)
    

    【讨论】:

    • 你知道,我完全忘记了 2 的补码的属性。这可能是它被发明的另一个很好的原因。
    • 如果我写 signed int a = -1 ,那么 -1 在 2 的补码形式是 11111111 11111111 11111111 11111111 然后当我使用 %d 来解释它时,它会打印 -1 和 %u ,它会打印 4294967295当我写 signed int a = 2 时,当我使用 %d 以及当我使用 %u 时,它会打印 2 。如果 2 在二进制补码中,它将是 11111111 11111111 11111111 11111101,然后这将是一个非常不同的答案,我真正想问的是 2 的补码何时发生是取决于 - 符号,或者它发生在每个整数如果类型是有符号的 int,这里一定不是这种情况。
    【解决方案6】:

    让我们举个例子: 我们在二进制的两个字节中有两个数字: A = 10010111 B = 00100110 (注意,本关机器不知道有符号或无符号的概念)

    现在当您说“添加”这两个时,机器是什么?它只是添加:

    R = 10111101(和进位:1)

    现在,我们——作为编译器——需要解释这个操作。我们有两个选择:数字可以有符号或无符号。

    1-无符号情况:在c中,数字是“unsigned char”类型,值是151和38,结果是189。这是微不足道的。

    2 - 带符号的情况:我们,编译器,根据它们的 msb 解释数字,第一个数字是 -105,第二个数字仍然是 38。所以 -105 + 38 = -67。但是 -67 是 10111101。但这就是我们在结果 (R) 中已有的内容!结果是一样的,唯一的区别是编译器如何解释它。

    结论是,无论我们如何考虑数字,机器都会对数字进行相同的操作。但是编译器会依次解释结果。

    请注意,不是机器知道 2 的补码的概念。它只是添加两个数字而不关心内容。然后,编译器查看符号位并决定

    在减法方面,这一次,操作是唯一的:取第二个数的 2 的补码,然后将两个数相加。

    【讨论】:

      【解决方案7】:

      如果数字被声明为有符号数据类型(而不是类型转换为无符号类型),那么编译器将知道,当符号位为 1 时,它是一个负数。至于为什么使用 2 的补码而不是 1 的补码,你不希望能够有 -0 的值,而 1 的补码可以让你这样做,所以他们发明了 2 的补码来解决这个问题。

      【讨论】:

      • 我相信真正的原因是允许机器语言加/减算法忽略操作数的符号并简单地进行按位加法或减法,必要时携带位...
      【解决方案8】:

      这正是最重要的位——如果您知道一个数字是有符号的,那么如果 MSB=1,编译器(和运行时!)知道将其解释为负数。这就是为什么类 c 语言同时具有整数(正数和负数)和无符号整数的原因——在这种情况下,您将它们都解释为正数。因此,有符号字节从 -128 到 127,而无符号字节从 0 到 255。

      【讨论】:

      • 其实一个有符号字节是从-128到127。
      猜你喜欢
      • 1970-01-01
      • 2012-11-23
      • 1970-01-01
      • 1970-01-01
      • 2018-02-19
      • 2015-04-12
      • 1970-01-01
      • 1970-01-01
      • 2014-09-20
      相关资源
      最近更新 更多