Fra*_*k V 410 binary computer-science bit-manipulation twos-complement data-representation
我在计算机系统课程中,并且一直在与Two's Complement一起挣扎.我想了解它,但我读过的所有内容并没有为我提供图片.我已经阅读了维基百科文章和其他各种文章,包括我的教科书.
因此,我想开始这个社区wiki帖子来定义Two's Complement是什么,如何使用它以及它如何在诸如强制转换(从有符号到无符号,反之亦然)等操作中影响数字,逐位操作和位移操作.
我所希望的是一个清晰简洁的定义,程序员很容易理解.
lav*_*nio 596
两个补码是一种存储整数的聪明方法,因此常见的数学问题很容易实现.
要理解,您必须考虑二进制数字.
它基本上说,
让我们尝试一个4位的小字节(我们称之为半字节 - 1/2个字节).
0000
- 零0001
- 一个0010
- 两个0011
- 三0100
到0111
- 四到七这就是我们可以采取积极的态度.2 3 -1 = 7.
对于否定:
1111
- 消极的1110
- 否定两个1101
- 否定三1100
到1000
-负四,负8请注意,您为负数(1000
= -8)获得了一个额外的值,而不是肯定的.这是因为0000
用于零.这可以视为计算机的数字行.
区分正数和负数
这样做,第一位获得"符号"位的作用,因为它可用于区分正十进制值和负十进制值.如果最高有效位是1
,那么二进制可以说是负数,其中就好像最高有效位(最左边)是0
,你可以说识别十进制值是正数.
"一个人的称赞"负数只是翻转符号位,然后从0开始计算.但这种方法必须将解释1000
称为"负零",这令人困惑.在靠近硬件工作时,通常只需要担心这一点.
Vin*_*nie 327
我想知道它是否可以比维基百科文章更好地解释.
您尝试使用二进制补码表示的基本问题是存储负整数的问题.
首先考虑以4位存储的无符号整数.您可以拥有以下内容
0000 = 0
0001 = 1
0010 = 2
...
1111 = 15
Run Code Online (Sandbox Code Playgroud)
这些是未签名的,因为没有迹象表明它们是否定为正面.
要存储负数,您可以尝试许多事情.首先,您可以使用符号幅度表示法,将第一位指定为符号位以表示+/-,将剩余位指定为幅度.所以再次使用4位并假设1意味着 - 而0意味着+那么你就拥有了
0000 = +0
0001 = +1
0010 = +2
...
1000 = -0
1001 = -1
1111 = -7
Run Code Online (Sandbox Code Playgroud)
那么,你看到那里的问题了吗?我们有正负0.更大的问题是加和减二进制数.使用符号幅度进行加减的电路将非常复杂.
什么是
0010
1001 +
----
Run Code Online (Sandbox Code Playgroud)
?
另一个系统是多余的表示法.你可以存储负数,你摆脱了两个零问题,但加法和减法仍然很困难.
所以随之而来的是两个补充.现在,您可以存储正负整数并相对轻松地执行算术运算.有许多方法可以将数字转换为二进制补码.这是一个.
将数字转换为二进制(暂时忽略符号),例如5为0101,-5为0101
如果数字是正数,那么你就完成了.例如,5是使用二进制补码表示法的二进制0101.
如果数字是负数那么
3.1找到补码(反转0和1),例如-5是0101,所以找到补码是1010
3.2在补码1010 + 1 = 1011中加1.因此,2的补码中的-5是1011.
那么,如果你想在二进制中做2 +( - 3)怎么办?2 +( - 3)为-1.如果您使用符号幅度来添加这些数字,您需要做什么?0010 + 1101 =?
使用两个补码考虑它是多么容易.
2 = 0010
-3 = 1101 +
-------------
-1 = 1111
Run Code Online (Sandbox Code Playgroud)
将1111转换为十进制:
数字从1开始,所以它是负数,所以我们找到1111的补码,即0000.
加1到0000,我们获得0001.
将0001转换为十进制,即1.
应用sign = -1.
田田!
小智 112
像我看到的大多数解释一样,上面的解释清楚如何使用2的补码,但是没有真正解释它们在数学上是什么.我会尝试这样做,至少对整数而言,我会介绍一些可能先熟悉的背景.
回想一下小数是如何工作的:
2345
是一种写
2 ×10 3 + 3 ×10 2 + 4 ×10 1 + 5 ×10 0的方法.
以同样的方式,二进制是一种使用0和1编写数字的方法,遵循相同的一般想法,但用2替换上面的10.然后在二进制中,
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.相应的正数不符合正在使用的位数.
对于这个数字更奇怪的是,如果你试图通过补充和添加一个来形成积极的,那么你会得到相同的负数.看起来很自然零会这样做,但这是出乎意料的并且根本不是我们习惯的行为,因为除了计算机之外,我们通常会想到无限制的数字,而不是这种固定长度的算术.
这就像是一个奇怪的冰山一角.在表面之下还有更多的等待,但这对于这次讨论来说已经足够了.如果研究定点算术的"溢出",你可能会找到更多.如果你真的想进入它,你也可以研究"模运算".
小智 18
2的补码对于找到二进制的值非常有用,但是我想到了解决这个问题的更简洁的方法(从未见过其他人发布它):
取二进制,例如:1101 [假设空格"1"是符号]等于-3.
使用2的补码我们会这样做...翻转1101到0010 ...添加0001 + 0010 ===>给我们0011. 0011 in positive binary = 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
Cap*_*ult 14
想象一下,你有一个有限数量的位/ trits/digits /无论如何.您将0定义为所有数字为0,并自然向上计数:
00
01
02
..
Run Code Online (Sandbox Code Playgroud)
最终你会溢出.
98
99
00
Run Code Online (Sandbox Code Playgroud)
我们有两位数字,可以代表从0到100的所有数字.所有这些数字都是正数!假设我们也想表示负数?
我们真正拥有的是一个循环.2之前的数字是1. 1之前的数字是0. 0之前的数字是...... 99.
因此,为简单起见,我们可以说任何超过50的数字都是负数."0"到"49"代表0到49."99"是-1,"98"是-2,......"50"是-50.
这种表示是十的补充.计算机通常使用二进制补码,除了使用位而不是数字之外,它们是相同的.
关于十个补充的好处是加法才有效.您不需要做任何特殊的事情来添加正数和负数!
小智 5
通过添加给定数字的第1至第1个补码找出两个补码.让我们说我们必须找出两个补码,10101
然后找到它的补码,也就是说,01010
添加1
到这个结果,也就是说01010+1=01011
,这是最终的答案.
我以里程表为类比,阅读了jng 关于Reddit的精彩解释。
这是一个有用的约定。如果使用约定,则在二进制中加/减正数的相同电路和逻辑运算仍然可以在正数和负数上工作,这就是为什么它是如此有用且无所不在的原因。
想象一下汽车的里程表在(例如)99999处滚动。如果增加00000,则得到00001。如果减小00000,则得到99999(由于滚转)。如果将99999加1,它将回到00000。因此确定99999表示-1非常有用。同样,确定99998表示-2非常有用,依此类推。您必须停在某个地方,并且按照惯例,数字的上半部分将被视为负数(50000-99999),而下半部分的正数将代表自己(00000-49999)。结果,高位数字为5-9表示所代表的数字为负数,高位数字为0-4表示所代表的数字为正数-与表示二进制补码二进制数符号的最高位完全相同。
我也很难理解这一点。一旦获得并返回以重新阅读书籍文章和解释(那时还没有互联网),结果发现很多描述它的人并不真正理解它。在那之后,我确实写了一本教汇编语言的书(这本书卖了十年很不错)。