Language agnostic 把我的头绕在数字的硬件表示上:一个假设的2';s补语问题

Language agnostic 把我的头绕在数字的硬件表示上:一个假设的2';s补语问题,language-agnostic,hardware,math,twos-complement,instruction-set,Language Agnostic,Hardware,Math,Twos Complement,Instruction Set,这是一个非常幼稚的问题(我知道),但我认为这将是考虑CPU基本指令集实际如何执行的一个很好的起点: 在2的补码系统中,您不能反转实现所能表示的最负数的符号。这种情况的理论原因很明显,因为最负数的否定将超出实现的范围(范围总是类似于 -128至127) 然而,当你尝试对最负的数字进行求反运算时,实际发生的情况是非常奇怪的。例如,在8位表示法中,最大负数为-128,或二进制中的1000 0000。通常,要对一个数字求反,你需要翻转所有的位,然后加一。但是,如果您尝试使用-128执行此操作,您将得到:

这是一个非常幼稚的问题(我知道),但我认为这将是考虑CPU基本指令集实际如何执行的一个很好的起点:

在2的补码系统中,您不能反转实现所能表示的最负数的符号。这种情况的理论原因很明显,因为最负数的否定将超出实现的范围(范围总是类似于
-128至127)

然而,当你尝试对最负的数字进行求反运算时,实际发生的情况是非常奇怪的。例如,在8位表示法中,最大负数为-128,或二进制中的1000 0000。通常,要对一个数字求反,你需要翻转所有的位,然后加一。但是,如果您尝试使用-128执行此操作,您将得到:

1000 0000 ->
0111 1111 ->
1000 0000
和你开始时的号码一样。出于这个原因,我们称之为“奇怪的数字”

在同一篇文章中,上面的否定

被检测为溢出情况,因为最高有效位有进位,但没有进位

所以我的问题是:
A) 这到底是什么意思?和

B) 似乎CPU每次执行基本算术运算时都需要执行额外的错误检查步骤,以避免与此求反相关的事故,从而产生显著的开销。如果是这样的话,为什么不直接截断可以表示的数字范围,将奇怪的数字去掉(即-127到127表示8位)?如果不是这样的话,如何在不产生额外开销的情况下实现这种错误检查?

这不是CPU进行另一次检查,而是晶体管被安排在发生这种情况时注意到。它们是这样建造的,因为工程师们在开始设计之前选择了两个补充

结果是,它发生在与返回非溢出结果相同的时钟周期内


它是如何工作的

“添加1”阶段实现级联逻辑:从LSB开始,每个位依次接受真值表

old-bit  carry-in  new-bit  carry-out
-------------------------------------
   0        0        0         0
   0        1        1         0
   1        0        1         0
   1        1        0         1
(即
新位=旧位异或进位
进位=旧位和进位
)。LSB的“进位”是我们正在添加的1,其余的位是前一位的“进位”(这就是为什么必须级联完成)


最后一个电路只是为
有符号溢出=(进位和不进位)
添加一个电路。MSB的进位用作标志,指示 需要更多的位子。如果没有它,我们将有一个1的系统,当我们绕过去时,没有任何检测方法

在模运算中,您不处理数字,而是处理 具有相同余数的数的集合。这样 一个系统,在把1加到127之后,你会得到−128,你会的 得出+128和+128的结论−128属于同一等价类

如果你把自己限制在这个范围内−127到+127,你呢 必须重新定义加法,因为127+1=−这是胡说八道

当计算机呈现给您时,二的补码算法是 基本上是模块运算,能够检测溢出

这就是将
0001
添加到
0111
。您可以看到,在MSB中,进位和进位是 不同的:

     0        0        0        1
     | 0      | 1      | 1      | 1
     | |      | |      | |      | |
     v v      v v      v v      v v
0 <- ADD <-1- ADD <-1- ADD <-1- ADD <- 0
^     |    ^   |        |        |
      v        v        v        v
      1        0        0        0
01
| 0      | 1      | 1      | 1
| |      | |      | |      | |
v v v v v v v

0首先,wikipedia文章指出,它不能从负号否定为有符号数。它们的意思是,它需要9位来表示正128,这是8位寄存器无法做到的。如果将负符号转换为正无符号,那么就有足够的位。当你否定0x80时,硬件应该给你0x80,因为这是正确的答案

对于加法、减法、乘法等,二进位的加法和小学的十进制数学没有什么不同。您将二进制数排成一行,添加列,该列的结果是最低有效位,其余的则转入下一列。例如,将0b001添加到0b001

1 001 001 === 010 1. 001 001 === 010 将最右边一列中的两个1相加,结果为0b10(2个十进制数),写入0,然后进行1运算,1加0加0等于1,无需进行任何运算,0加0等于0,结果为0b010

最右边的一列,其中1加1是0b10,我们写0,携带1,携带1的同时是最右边一列的进位,也是第二列的进位。同样,在纸笔数学中,我们通常只讨论非零时的进位,但如果你想一想,你总是携带一个数字,比如我们的第二列,一加零就是一进位

你可以把两个补数的否定看作是倒过来加上一,或者把位倒过来,然后不倒过来,或者取零减去数字的结果

你们们可以用铅笔和纸在二进制中进行减法运算,这会使你们们的头在借用十进制时受伤,但还是有效的。对于你要问的问题,想一想倒过来加一个

如果你把它降到比8更少的位,你就更容易理解它,3是一个可管理的数字,它从那里开始扩展

因此,下面的第一列是输入,第二列是反转版本,第三列是第二列加一。第四列是msbit的进位,第五列是msbit的进位

000 111 000 1 1 001 110 111 0 0 010 101 110 0 0 011 100 101 0 0 100 011 100 1 0 101 010 011 0 0 110 001 010 0 0 111 000 001 0 0 000 111 000 1 1 001 110 1 00+1 = 001 01+1 = 010 10+1 = 011 11+1 = 100
OverflowFrom
     Returns 1 if the addition or subtraction specified as its parameter 
     caused a 32-bit signed overflow. [...]
     Subtraction causes an overflow if the operands have different signs,
     and the first operand and the result have different signs.

NEG
     [...]
     V Flag = OverflowFrom(0 - Rm)