关于二进制补码

转:http://www.ruanyifeng.com/blog/2009/08/twos_complement.html

问一个主要的问题。

负数在计算机中怎样表示?

举例来说,+8在计算机中表示为二进制的1000,那么-8怎么表示呢?

非常easy想到,能够将一个二进制位(bit)专门规定为符号位,它等于0时就表示正数,等于1时就表示负数。比方,在8位机中,规定每一个字节的最高位为符号位。那么,+8就是00001000,而-8则是10001000。

可是,随便找一本《计算机原理》,都会告诉你,实际上,计算机内部採用补码(Two‘s Complement)表示负数。

什么是补码?

它是一种数值的转换方法,要分二步完毕:

第一步,每个二进制位都取相反值,0变成1,1变成0。比方,00001000的相反值就是11110111。

第二步,将上一步得到的值加1。11110111就变成11111000。

所以,00001000的补码就是11111000。也就是说,-8在计算机(8位机)中就是用11111000表示。

不知道你怎么看,反正我认为非常奇怪,为什么要採用这么麻烦的方式表示负数,更直觉的方式难道不好吗?

昨天,我在一本书里又看到了这个问题,然后就花了一点时间到网上找资料,如今总算彻底搞明确了。

补码的优点

首先,要明白一点。计算机内部用什么方式表示负数,事实上是无所谓的。仅仅要能够保持一一相应的关系,就能够用随意方式表示负数。所以,既然能够随意选择,那么理应选择一种最方便的方式。

补码就是最方便的方式。它的便利体如今,全部的加法运算能够使用同一种电路完毕。

还是以-8作为样例。

假定有两种表示方法。一种是直觉表示法,即10001000;还有一种是补码表示法,即11111000。请问哪一种表示法在加法运算中更方便?

随便写一个计算式,16 + (-8) = ?

16的二进制表示是 00010000,所以用直觉表示法,加法就要写成:

 00010000
+10001000
---------
 10011000

能够看到,假设依照正常的加法规则,就会得到10011000的结果,转成十进制就是-24。显然,这是错误的答案。也就是说,在这样的情况下,正常的加法规则不适用于正数与负数的加法,因此必须制定两套运算规则,一套用于正数加正数,另一套用于正数加负数。从电路上说,就是必须为加法运算做两种电路。

如今,再来看补码表示法。

 00010000
+11111000
---------
100001000

能够看到,依照正常的加法规则,得到的结果是100001000。注意,这是一个9位的二进制数。我们已经假定这是一台8位机,因此最高的第9位是一个溢出位,会被自己主动舍去。所以,结果就变成了00001000,转成十进制正好是8,也就是16 + (-8) 的正确答案。这说明了,补码表示法能够将加法运算规则,扩展到整个整数集,从而用一套电路就能够实现所有整数的加法。

补码的本质

在回答补码为什么能正确实现加法运算之前,我们先看看它的本质,也就是那两个步骤的转换方法是怎么来的。

要将正数转成相应的负数,事实上仅仅要用0减去这个数就能够了。比方,-8事实上就是0-8。

已知8的二进制是00001000,-8就能够用以下的式子求出:

 00000000
-00001000
---------

由于00000000(被减数)小于0000100(减数),所以不够减。请回顾一下小学算术,假设被减数的某一位小于减数,我们怎么办?非常easy,问上一位借1就能够了。

所以,0000000也问上一位借了1,也就是说,被减数事实上是100000000,算式也就改写成:

100000000
-00001000
---------
 11111000

进一步观察,能够发现100000000 = 11111111 + 1,所以上面的式子能够拆成两个:

 11111111
-00001000
---------
 11110111
+00000001
---------
 11111000

补码的两个转换步骤就是这么来的。

为什么正数加法适用于补码?

实际上,我们要证明的是,X-Y或X+(-Y)能够用X加上Y的补码完毕。

Y的补码等于(11111111-Y)+1。所以,X加上Y的补码,就等于:

X + (11111111-Y) + 1

我们假定这个算式的结果等于Z,即 Z = X + (11111111-Y) + 1

接下来,分成两种情况讨论。

第一种情况,假设X小于Y,那么Z是一个负数。这时,我们就对Z採用补码的逆运算,求出它相应的正数绝对值,再在前面加上负号即可了。所以,

Z = -[11111111-(Z-1)] = -[11111111-(X + (11111111-Y) + 1-1)] = X - Y

另外一种情况,假设X大于Y,这意味着Z肯定大于11111111,可是我们规定了这是8位机,最高的第9位是溢出位,必须被舍去,这相当于减去100000000。所以,

Z = Z - 100000000 = X + (11111111-Y) + 1 - 100000000 = X - Y

这就证明了,在正常的加法规则下,能够利用补码得到正数与负数相加的正确结果。换言之,计算机仅仅要部署加法电路和补码电路,就能够完毕全部整数的加法。

(完)

精彩评论:

Z = X + (11111111-Y) + 1式子能够写为Z = X - Y +100000000,这在硬件上能够理解为两部分电路来实现,第一部分是前面的X - Y(这里姑且无论计算的结果是正还是负),第二部分是X - Y计算的结果再和100000000相加,终于得到计算的结果Z, 而在8位的计算机上100000000是不能出现的,事实上这时100000000就相当于00000000(舍去了最高位),然后我们再看一些计算的过程:
Z = X + (11111111 - Y) + 1
= X - Y + 100000000
= X - Y + 00000000
= X - Y
证毕。
这样我们就证明了X-Y或X+(-Y)能够用X加上Y的2的补码完毕,而不必分两种情况来证明。

时间: 2024-10-08 20:50:35

关于二进制补码的相关文章

二进制补码

一.概述     1.计算机系统的内部以二进制形式存储数据. 2.在Java程序中输入的十进制的数据都会被自动转换为二进制,Java内部也是以二进制来进行数值运算,但返回的结果是十进制. 二.补码规则     1.在计算机系统中,数值一律用二进制的补码来存储 2.二进制的最高位是符号位,0表示正数,1表示负数 3.正数的值是其本身,负数的值是最高位(符号位)不变,其它位逐位取反加一 4.两数相加,若最高位(符号位)有进位,则进位被舍弃. 三.为什么使用补码     1.可以将符号位和其他位统一处

35:输出二进制补码

35:输出二进制补码 查看 提交 统计 提问 总时间限制:  1000ms 内存限制:  65536kB 描述 输入一个整型(int)的整数,输出它的32位二进制补码. 输入 一个整型整数. 输出 输出一行,即该整数的补码表示. 样例输入 7 样例输出 00000000000000000000000000000111‘ 1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 int a[10001]; 5 i

补码的求法以及八位二进制补码所能表示的数的范围

补码用来解决整数的存储问题,整数在计算机中是以二进制的补码形式进行存储的, 求十进制对应的二进制补码 1求正整数的二进制补码:正整数的二进制补码与其二进制原码相同, 2:求负整数的二进制补码:先求与该负数相对应的正整数的二进制代码,然后所有位取反加1,不够位数时左边补1,例如,求-3的二进制补码,先求3的二进制补码,3=11,取反之后为00,加1之后为01,假设用八位二进制表示,那么左边补6个1,也就是1111 1101. 3:0的二进制补码是0:关于0的补码你有一个误区,你觉得首先把0看做是+

深入理解二进制补码

文章来源 背景 大家都知道计算机内部采用补码表示整数的,但是具体到补码的内在含义,很多人不能理解,故我们分享自己的理解. 首先说下补码的定义以及基本性质: 1) 正数的补码和原码相同: 2) 负数的补码等于取反后加1: 3) 0的正负两种补码相同: 4) 对一个补码再求补码等于自己: 5) 一个正数的原码和其对应的负数的补码相加等于模: 针对本文,我们其实只关心规则1)和2)即可. 实例 为方便说明现有的补码定义(即正数的补码等于原码:负数的补码等于取反加1),本文均以八进制为例. 5 – 3

java基础 二进制补码

二进制补码: 1.计算机系统的内部以二进制形式存储数据. 2.在Java程序中输入的十进制的数据都会被自动转换为二进制,Java内部也以二进制来进行数值运算,但返回的结果是十进制. 二进制补码的原理: 正数+负数=模. 模:某种类型数据的总数,例如: 4位二进制数的模是2^4=16 8位二进制数的模是2^8=256 负数=模-正数,这就是逐位取反加1的原因. 1.在计算机系统中,数值一律用二进制的补码来存储. 2.二进制的最高位是符号位,0表示正数,1表示负数. 3.正数的值是其本身,负数的值是

0.1.2 二进制补码

<编程导论(Java)·0.1.2 二进制补码> p6:[冯?诺伊曼体系结构计算机使用二进制.人类之所以习惯十进制,据说是因为用手指头来计算比较方便,而人正好有10个指头.] 本节就2面(page6和p7)纸.虽然二进制补码属于每个程序员都应该熟练掌握的内容,但通常安排同学们自学. 重点要理解:为什么要采用补码? [ 将10进制数转换为二进制数时,负数如何在二进制中表达呢?为了讲解的方便,这里使用半个字节(Nibble)即4位为数据长度. 将最高位作为符号位是自然的想法.通常以0表示正.1表示

输出二进制补码

题目链接:http://ica.openjudge.cn/dg2/2/ 总时间限制: 1000ms   内存限制: 65536kB 描述 输入若干int型整数,输出每个整数的二进制补码. 输入 输入有若干行,除最后一行外,每行包含一个int型整数.最后一行仅包含一个不定的字母,标志着输入结束.我们保证输入的整数不超出int型变量的表示范围 输出 个输入的整数,输出一行,即该整数的补码表示. 样例输入 1 7 200 -45 h 样例输出 00000000000000000000000000000

利用ZYNQ SOC快速打开算法验证通路(1)——MATLAB浮点数与定点二进制补码互转

最近本人一直在学习ZYNQ SOC的使用,目的是应对科研需要,做出通用的算法验证平台.大概思想是:ZYNQ PS端负责与MATLAB等上位机数据分析与可视化软件交互:既可传输数据,也能通过上位机配置更新硬件算法模块配置寄存器内容,同时可计算分析PL端算法实现性能指标.PL端的FPGA逻辑则负责算法的硬件实现,以探索高效并行硬件架构.为此本人后续会持续编写<利用ZYNQ SOC快速打开算法验证通路>系列专题博文,在各个阶段进行些基础性总结. MATLAB中数据为双精度浮点型,因此打开算法验证通路

任意N位二进制的补码实现——队列存放

正在学习计算机组织与结构,为了写一些底层的算术操作模拟,比如一个二进制补码数的加减乘除,发现这很麻烦,因为不管是什么语言,都只提供了8位.32.64位等部分位数的补码形式,那么怎么实现任意任意位的补码整数呢,由于我们不能利用现有的如Byte.Integer类,所以我们需要一个容器来存储我们自己编写的任意位的补码整数. 数组可以实现,但是数组移位可能比较麻烦,比如如果要实现二进制数的算术右移,必须要移动大部分元素.可以使用链表,虽然获取二进制数某一位的值比较麻烦,但是还是比数组可能更好一点.于是,