我正在上计算机系统课程,并且在某种程度上一直在努力与Two's Complement交流。我想了解它,但是我读过的所有内容都没有为我带来帮助。我已经阅读了维基百科文章和其他各种文章,包括我的教科书。
因此,我想开始这个社区Wiki帖子,以定义Two's Complement是什么,如何使用它以及它如何在诸如强制类型转换(从有符号到无符号,反之亦然),按位操作和移位操作等操作期间影响数字。
我希望有一个清晰简洁的定义,使程序员容易理解。
我正在上计算机系统课程,并且在某种程度上一直在努力与Two's Complement交流。我想了解它,但是我读过的所有内容都没有为我带来帮助。我已经阅读了维基百科文章和其他各种文章,包括我的教科书。
因此,我想开始这个社区Wiki帖子,以定义Two's Complement是什么,如何使用它以及它如何在诸如强制类型转换(从有符号到无符号,反之亦然),按位操作和移位操作等操作期间影响数字。
我希望有一个清晰简洁的定义,使程序员容易理解。
Answers:
二进制补码是一种存储整数的聪明方法,因此常见的数学问题非常容易实现。
要理解,您必须考虑二进制数。
它基本上说,
让我们尝试使用4位的小字节(我们将其称为半字节-1/2字节)。
0000
-零0001
-一个0010
-两个0011
-三0100
到0111
-四到七这是我们可以肯定的。2 3 -1 = 7。
对于底片:
1111
-负数1110
-负二1101
-负三1100
至1000
-负四至负八请注意,对于负数(1000
= -8),您会得到一个额外的价值,而对于正数,则不会。这是因为0000
用于零。这可以视为计算机的编号行。
区分正数和负数
这样做,第一位具有“符号”位的作用,因为它可用于区分非负十进制值和负十进制值。如果最高有效位是1
,那么二进制可以说是负数,而最高有效位(最左边)是0
,则可以说十进制值是非负数。
“一个补码”负数只是翻转符号位,然后从0开始计数。但是这种方法必须处理解释1000
为“负零”的情况,这令人困惑。通常,您只需要在靠近硬件的情况下担心这一点。
我想知道是否可以比维基百科的文章更好地解释它。
您试图用二进制补码表示法解决的基本问题是存储负整数的问题。
首先考虑存储在4位中的无符号整数。您可以拥有以下内容
0000 = 0
0001 = 1
0010 = 2
...
1111 = 15
这些是未签名的,因为没有迹象表明它们是负数还是正数。
要存储负数,您可以尝试多种方法。首先,您可以使用符号幅度符号,该符号符号将第一位分配为符号位以表示+/-,其余位分配为幅度。因此,再次使用4位并假设1表示-,而0表示+,则
0000 = +0
0001 = +1
0010 = +2
...
1000 = -0
1001 = -1
1111 = -7
那么,您看到那里的问题了吗?我们有正负0。更大的问题是加和减二进制数。使用符号幅度进行加法和减法的电路将非常复杂。
什么是
0010
1001 +
----
?
另一个系统是 多余的符号。您可以存储负数,摆脱了两个零的问题,但是加法和减法仍然很困难。
随之而来的是二进制补码。现在,您可以存储正整数和负整数,并相对轻松地执行算术运算。有很多方法可以将数字转换为二进制补码。这是一个
将数字转换为二进制(现在忽略符号),例如5为0101,-5为0101
如果数字为正数,则说明您已经完成。例如5是二进制补码表示法的0101。
如果数字为负,则
3.1找到补码(将0和1求反),例如-5是0101,所以找到补码是1010
3.2将1加到补码1010 +1 =1011。因此,二进制补码中的-5是1011。
那么,如果您想以二进制形式进行2 +(-3)怎么办?2 +(-3)为-1。如果您使用符号幅度将这些数字相加,该怎么办?0010 + 1101 =?
使用二进制补码考虑一下它会多么容易。
2 = 0010
-3 = 1101 +
-------------
-1 = 1111
将1111转换为十进制:
数字以1开头,因此为负数,因此我们找到了1111的补数,即0000。
将1加到0000,我们得到0001。
将0001转换为十进制数1。
应用符号= -1。
多田!
就像我看到的大多数解释一样,上面的解释很清楚如何使用2的补码,但是并没有真正解释它们的含义。 从数学上。我将尝试这样做,至少对于整数,我将介绍一些可能首先熟悉的背景。
回想一下十进制的工作方式:
2345
是一种写
2 ×10 3 + 3 ×10 2 + 4 ×10 1 + 5 ×10 0的方式。
同样,二进制是遵循相同的一般思想而仅使用0和1写入数字的方式,但是用2s代替了上面的10s。然后以二进制形式,
1111
是一种写
1 ×2 3 + 1 ×2 2 + 1 ×2 1 + 1 ×2 0的方法
,如果计算出来,结果等于15(以10为底)。那是因为它是
8 + 4 + 2 + 1 = 15。
对于正数来说,这一切都很好。如果您愿意在负数前面加上一个减号,那么它甚至适用于负数,就像人类对十进制数所做的那样。这甚至可以在计算机上完成,但自1970年代初以来我还没有见过这样的计算机。我将保留其他讨论的理由。
对于计算机来说,使用补码会更有效对负数表示。这是经常被忽略的东西。补码表示法涉及数字的某种反转,甚至是正常正数之前的隐含零。这很尴尬,因为出现了问题:所有人?这可能是要考虑的无数个数字。
幸运的是,计算机不代表无限。数字被限制为特定的长度(或宽度,如果您愿意)。因此,让我们返回具有特定大小的正二进制数。在这些示例中,我将使用8位数字(“位”)。因此我们的二进制数实际上是
00001111
或
0 ×2 7 + 0 ×2 6 + 0 ×2 5 + 0 ×2 4 + 1 ×2 3 +1×2 2 + 1 ×2 1 + 1 ×2 0
为了形成2的补数负数,我们首先对所有(二进制)数字进行补数以形成
11110000,
然后将1
加成以形成11110001,
但是我们如何理解这意味着-15?
答案是我们更改了高位(最左边的一位)的含义。对于所有负数,该位将为1。的变化将是改变其到它出现在数的值贡献的符号所以现在我们的。11110001应理解为代表
- 1 ×2 7 + 1 ×2 6 + 1 ×2 5 + 1 ×2 4 + 0 ×2 3 + 0×2 2 + 0 ×2 1 + 1 ×2 0
注意表达式前面的“-”吗?这意味着符号位的权重为-2 7,即-128(以10为底)。所有其他位置保持与未签名二进制数字相同的权重。
算出我们的-15,它是
-128 + 64 + 32 + 16 + 1
在您的计算器上尝试一下。是-15。
在我看到负数出现在计算机中的三种主要方式中,2的补码会赢得通用性,以方便使用。不过,这很奇怪。由于它是二进制的,因此必须有偶数个可能的位组合。每个正数可以与它的负数配对,但是只有一个零。否定零将使您零。因此,还有另一种组合,即符号位为1且数字为0的数字其他所有位置均为。相应的正数将不适合所使用的位数。
关于这个数字,更奇怪的是,如果您尝试通过补码和加数来形成它的正数,则会得到相同的负数。零看起来很自然,但这是意料之外的,完全不是我们习惯的行为,因为除了计算机之外,我们通常认为数字的供应不受限制,而不是这种固定长度的算法。
这就像是一堆奇怪的冰山一角。在表面之下还有更多的等待,但这足以进行讨论。如果研究定点算术的“溢出”,可能会发现更多信息。如果您真的想研究它,您可能还会研究“模块化算术”。
2的补码对于查找二进制值非常有用,但是我想到了一种更简洁的方法来解决此类问题(从未见过其他人发表过):
以二进制文件为例:1101 [假设空格“ 1”是符号”等于-3。
使用2的补码,我们将执行此操作...将1101翻转到0010 ...加0001 + 0010 ===>给出我们0011.0011正二进制= 3,因此1101 = -3!
我意识到:
而不是进行所有的翻转和加法运算,您只需做求解正二进制的基本方法即可(假设0101)为(2 3 * 0)+(2 2 * 1)+(2 1 * 0)+(2 0 * 1)= 5。
做一个完全相反的概念!
以1101为例:
对于第一个数字而不是2 3 * 1 = 8,请执行-(2 3 * 1)= -8。
然后照常继续,执行-8 +(2 2 * 1)+(2 1 * 0)+(2 0 * 1)= -3
想象一下,您拥有有限的位数/技巧/数字/其他。您将0定义为所有数字均为0,然后自然向上计数:
00
01
02
..
最终,您将溢出。
98
99
00
我们有两个数字,可以代表0到100之间的所有数字。所有这些数字都是正数!假设我们也要表示负数吗?
我们真正拥有的是一个周期。2之前的数字是1。1之前的数字是0。0之前的数字是... 99。
因此,为简单起见,假设50以上的任何数字均为负。“ 0”到“ 49”代表0到49。“ 99”是-1,“ 98”是-2,...“ 50”是-50。
这个表示是十的补码。计算机通常使用二进制补码,除了使用位代替数字外,其余都是相同的。
十进制补码的优点是加法有效。您无需执行任何特殊操作即可添加正数和负数!
我以里程表为类比,阅读了jng 关于Reddit的精彩解释。
这是一个有用的约定。如果使用约定,则在二进制中加/减正数的相同电路和逻辑运算仍可在正数和负数上工作,这就是为什么它是如此有用且无所不在的原因。
想象一下汽车的里程表,它在(例如)99999处滚动。如果增加00000,则得到00001。如果减小00000,则得到99999(由于滚转)。如果将99999加1,则返回00000。因此确定99999表示-1非常有用。同样,确定99998表示-2非常有用,依此类推。您必须停在某个地方,并且按照惯例,数字的上半部分将被视为负数(50000-99999),而下半部分的正数将代表自己(00000-49999)。结果,高位数字为5-9表示所代表的数字为负数,高位数字为0-4表示所代表的数字为正数-与表示二进制补码二进制数的最高位完全相同。
我也很难理解这一点。一旦获得并返回以重新阅读书籍文章和解释(那时还没有互联网),结果发现很多描述它的人并不真正理解它。在那之后,我确实写了一本教汇编语言的书(这本书卖了十年很好)。
从数学的角度来看两者的补码系统确实很有意义。用十的补语,想法是本质上“隔离”差异。
例如:63-24 = x
我们加上24的补数,实际上是(100-24)。所以说真的,我们要做的是在方程式的两边加100。
现在的等式是:100 + 63-24 = x + 100,这就是为什么我们删除100(或10或1000或其他值)的原因。
由于必须从零位长链中减去一个数字的不便之处,我们使用了“减基数补码”系统,在十进制中使用了9的补码。
当我们看到从九个大数字链中减去的数字时,我们只需要反转数字即可。
例如:99999-03275 = 96724
这就是为什么在9的补码之后加1。您可能从童年数学中就知道,“偷” 1会使9变成10。因此,基本上只是10的补码使差值减为1。
在Binary中,二的补码等于十的补码,而一的补码与九的补码相等。主要区别在于,我们没有尝试将幂乘以10(将10、100等添加到方程式中),而是试图将幂乘以2。
出于这个原因,我们将位反转。就像我们的minuend是十进制的9的链一样,我们的minuend是二进制的1的九的链。
例如:111111-101001 = 010110
因为1的链比1的2的幂小1,所以它们像9的十进制一样从差中“窃取” 1。
当我们使用负二进制数时,我们实际上只是在说:
0000-0101 = x
1111-0101 = 1010
1111 + 0000-0101 = x + 1111
为了“隔离” x,我们需要加1,因为1111与10000相距1,并且我们删除了前导1,因为我们只是将其添加到原始差值中。
1111 + 1 + 0000-0101 = x + 1111 + 1
10000 + 0000-0101 = x + 10000
只需从两边都除去10000即可得到x,这是基本的代数。
到目前为止,许多答案很好地解释了为什么使用二进制补码来表示负数,但没有告诉我们二进制补码是什么,尤其是为什么不添加“ 1”,实际上却常常以错误的方式添加。
混乱来自对补数定义的理解不充分。补码是可以使某些内容完整的缺失部分。
根据定义,基数b中n位数字x的基数补码为b ^ nx。在二进制4中用100表示,它有3个数字(n = 3)和基数2(b = 2)。因此其基数补码为b ^ nx = 2 ^ 3-4 = 8-4 = 4(或二进制为100)。
但是,在二进制运算中,获得基数补码并不像获得其减小的基数补码那样容易,后者的定义为(b ^ n-1)-y,仅比基数补数小1。要减少基数补码,只需翻转所有数字即可。
100-> 011(小数补码)
要获得基数(二进制)补数,我们只需添加1作为定义的定义。
011 +1-> 100(二进制补码)。
现在有了这种新的理解,让我们看一下Vincent Ramdhanie给出的示例(请参见上面的第二个答复)
/ * Vincent的开始
将1111转换为十进制:
数字以1开头,因此为负数,因此我们找到了1111的补数,即0000。将0000加1,得到0001。将0001转换为十进制,即为1。应用符号= -1。多田!
文森特结束* /
应该理解为
数字以1开头,因此为负数。因此,我们知道它是某个值x的二进制补码。要找到以2的补码表示的x,我们首先需要找到其1的补码。
x的补码:1111 x的补码:1111-1-> 1110; x = 0001,(翻转所有数字)
应用符号-,答案= -x = -1。
补语一词源自完整性。在十进制世界中,数字0到9提供数字或数字符号的补码(完整集)来表示所有十进制数字。在二进制世界中,数字0和1提供数字的补码来表示所有二进制数字。实际上,必须使用符号0和1来表示所有内容(文本,图像等)以及正数(0)和负数(1)。在我们的世界中,数字左侧的空白被视为零:
35=035=000000035.
在计算机存储位置中没有空白空间。所有位(二进制数字)必须为0或1。为了有效使用内存,可以将数字存储为8位,16位,32位,64位,128位表示形式。将存储为8位数字的数字传输到16位位置时,符号和大小(绝对值)必须保持相同。1的补码和2的补码表示均有助于此操作。作为一个名词:1的补码和2的补码都是有符号数的二进制表示,其中最高有效位(左侧的一位)是符号位。0代表正,1代表负。 2s补码并不意味着负面。这表示已签名的数量。与小数一样,幅度表示为正数。当升级到具有更多位的寄存器[]时,该结构使用符号扩展来保留数量:
[0101]=[00101]=[00000000000101]=5 (base 10)
[1011]=[11011]=[11111111111011]=-5(base 10)
作为动词:2的补语表示取反。这并不意味着使负面。这意味着如果否定就变成积极;如果为正,则为负。大小是绝对值:
if a >= 0 then |a| = a
if a < 0 then |a| = -a = 2scomplement of a
此功能允许使用取反然后加法进行有效的二进制减法。a-b = a +(-b)
取1的补码的正式方法是为每个数字减去1的值。
1'scomp(0101) = 1010.
这与分别翻转或反转每个位相同。这将导致负零,这个负零不受欢迎,因此在te 1的补码上加1可以解决该问题。要取反或取2s补码,请先取1s补码,然后加1。
Example 1 Example 2
0101 --original number 1101
1's comp 1010 0010
add 1 0001 0001
2's comp 1011 --negated number 0011
在示例中,否定符也适用于符号扩展号。
加法:1110进位111110进位0110与000110 1111 111111总和0101总和000101相同
减去:
1110 Carry 00000 Carry
0110 is the same as 00110
-0111 +11001
---------- ----------
sum 0101 sum 11111
请注意,在使用2的补数时,数字左侧的空白表示正数为零,而负数表示为1。进位总是加进,必须为1或0。
干杯
2的补码本质上是提出二进制数的加法逆的一种方法。问问自己:给定二进制格式的数字,当将哪种位模式添加到原始数字后,结果将为零?如果可以提出该位模式,则该位模式为原始数字的-ve表示(加反)。因为按照定义,在其加和逆数上加一个数字应始终为零。示例:以101(十进制为5)为例。现在的任务是提出一个位模式,当将其添加到给定的位模式(101)时将得出零。为此,请从101的最右边开始,并针对每个单独的位,再次询问相同的问题:我应在“此”位上加上哪一位以使结果为零?考虑到通常的结转,继续这样做。在完成最右边的3个位置(定义原始数字的数字而不考虑前导零)之后,最后一个进位进入加法逆的位模式。此外,由于我们可以将原始数字保持为单个字节,因此加法逆的所有其他前导位也应为1,这样当计算机使用“ that”存储类型(字符)将数字及其加法逆相加时该char中的结果将全部为零。
1 1 1
----------
1 0 1
1 0 1 1 ---> additive inverse
---------
0 0 0
参考:https : //www.cs.cornell.edu/~tomf/notes/cps104/twoscomp.html
我将所有位取反并加1。
// in C++11
int _powers[] = {
1,
2,
4,
8,
16,
32,
64,
128
};
int value=3;
int n_bits=4;
int twos_complement = (value ^ ( _powers[n_bits]-1)) + 1;
给定数字的2的补码为no。将1与1的补码相加得到。假设我们有一个二进制数:10111001101它的1的补码是:01000110010它的2的补码是:01000110011
按位补码是对数字中的所有位进行翻转。为了补全它,我们翻转所有位并加一个。
对有符号整数使用2的补码表示形式,我们应用2的补码运算将正数转换为负数,反之亦然。因此,以半字节为例,0001
(1)变为1111
(-1)并再次应用op,返回到0001
。
零操作的行为有利于给出零的单一表示,而无需对正零和负零进行特殊处理。0000
与互补1111
,当加1时。溢出到0000
,给我们一个零,而不是一个正数和一个负数。
这种表示的主要优点是,无符号整数的标准加法电路在应用于它们时会产生正确的结果。例如,在半字节中加1和-1:,0001 + 1111
这些位溢出寄存器,而留下0000
。
简而言之,2's Complement
是一种在计算机内存中存储负数的方法。而正数存储为普通二进制数。
让我们考虑这个例子,
计算机Binary Number System
用来表示任何数字。
x = 5;
表示为0101
。
x = -5;
当计算机encouters -
签名时,它将计算为2的补码并将其存储。
i.e
5 = 0101,它的2的补码是1011
。
计算机用来处理数字的重要规则是,
1
则必须为negative
数字。0
正数,因为没有-0
数字系统(1000 is not -0
而是正数8
)。0
为0
。positive number
。您还可以使用在线计算器来计算十进制数字的二进制补码二进制表示形式:http : //www.convertforfree.com/twos-complement-calculator/
最简单的答案:
1111 + 1 =(1)0000。因此1111必须为-1。然后-1 + 1 = 0。
完全了解这些对我来说是完美的。