前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >一文读懂原码、反码与补码

一文读懂原码、反码与补码

作者头像
阿宝哥
发布于 2020-01-14 06:55:23
发布于 2020-01-14 06:55:23
2.8K00
代码可运行
举报
文章被收录于专栏:全栈修仙之路全栈修仙之路
运行总次数:0
代码可运行

一、二进制

二进制和十进制一样,也是一种进位计数制,但是它的基数是 2。二进制表达式中 0 和 1 的位置不同,它所代表的数值也不同。例如,二进制数 0000 1010 表示十进制数 10。一个二进制数具有两个基本特点:两个不同的数字符号,即 0 和 1,逢二进一。

十进制与二进制数之间的转换

用计算机处理十进制数时,必须先把它转化为二进制数才能被计算机所接受;同理,计算结果应该将二进制数转换成人们习惯的十进制数。

十进制转换成二进制

把一个十进制转换为二进制的方法是:把被转换的十进制数反复地除以 2,直到商为 0 为止,所得余数(从末位读起)就是这个数的二进制表示,简单地说,就是 “除 2 取余法”

(图片来源 —— wikihow.com)

二进制转十进制

要把二进制转换为十进制数,只要将二进制数按权展开求和即可。

(图片来源 —— wikihow.com)

二、数值型数据的表示

在计算机内数值型数据分成整数和实数两大类。数据都是以二进制的形式存储和运算的。计算机中的数字电路只能直接识别二进制数据,数的正(+)、负(-)号是不能被计算机识别的,为了让计算机能识别正、负号,就必须对符号进行编码,或者说把符号数字化。通常采用二进制数的最高位来表示符号,用 ”0“ 表示正数,”1“ 表示负数。

整数的表示

整数可分为无符号整数和有符号整数。在无符号整数中,所有二进制位全部用来表示数的大小;在有符号整数中,用最高位表示数的正负号,其他位表示数的大小。如果用一个字节表示一个无符号整数,其取值范围是 0 ~255。如果表示一个有符号整数,其取值范围是 -128 ~ 127。计算机中的地址常用无符号整数表示,可以用 8 位、16 位或 64 位来表示。

实数的表示

实数一般用浮点数表示,因为它的小数点位置不固定,所以称为浮点数。它是既有整数又有小数的数,纯小数可以看做实数的特例,例如,76.625,0.00345 都是实数,又可以表示为:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
76.625=10^2 ×(0.766250.00345=10^-2 × (0.345)

其中,指数部分用来指出实数中小数点的位置,括号内的一个纯小数。在计算机中一个浮点数由指数(阶码)和尾数两部分组成,阶码部分由阶符和阶码组成,尾数部分由尾符和尾数组成。其机内表示形式如下:

阶码用来指示尾数中的小数点应当向左或向右移动的位数;尾数表示数值的有效数字,其小数点约定在数符和尾数之间,在浮点数中数符和阶符各占 1 位,阶码的值随浮点数数值的大小而定,尾数的位数则依浮点数数值的精度要求而定。

三、原码、反码和补码

为运算方便,机器数有 3 种表示法,即原码、反码和补码。

原码

原码是一种计算机中对数字的二进制定点表示法。原码表示法在数值前面增加了一位符号位(即最高位为符号位):正数该位为 0,负数该位为 1(0 有两种表示:+0 和 -0),其余位表示数值的大小。举个例子,我们用 8 位二进制表示一个数,+12 的原码为 00001100,-12 的原码就是 10001100。

反码

一个数字用原码表示是容易理解的,但是需要单独一个位来表示符号位,并且在进行加法时,计算机需要先识别某个二进制原码是正数还是负数,识别出来之后再进行相应的运算。这样效率不高,能不能让计算机在进行运算时不用去管符号位,也就是让符号位参与运算。要实现这个功能,我们就要用到反码。

反码是一种在计算机中数的机器码表示。对于单个数值(二进制的 0 和 1)而言,对其进行取反操作就是将 0 变为 1,1 变为 0。正数的反码和原码一样,负数的反码就是在原码的基础上符号位保持不变,其他位取反。

十进制

原码

反码

6

0000 0110

0000 0110

-3

1000 0011

1111 1100

下面我们来看一下,用反码直接运算会是什么情况,我们以 6 - 3 为例,6 - 3 等价于 6 + (-3)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
6 - 3 ==> 6 + (-3)
  0000 0110 // 6(反码)
+ 1111 1100 // -3(反码)
----------------------
  0000 0010 // (反码)
  0000 0010 // 2(原码)

很明显通过反码进行 6 + (-3) 加法运算时,输出值比预期值差了一个 1。接着我们再来看下 1 + (-1) 的运算结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1 - 1 ==> 1 + (-1)
  0000 0001 // 1(反码)
+ 1111 1110 // -1(反码)
----------------------
  1111 1111 // (反码)
  1000 0000 // -0(原码)

由上可知 1 + (-1) 的运算结果为 -0,而我们预期的值是 +0。我们继续看个示例 0 + 0

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
0 + 0 ==> 0 + 0
  0000 0000 // 0(反码)
+ 0000 0000 // 0(反码)
----------------------
  0000 0000 // (反码)
  0000 0000 // 0(原码)

这里我们可以知道 -0 对应的原码是 1000 0000,而 +0 对应的原码是 0000 0000。虽然 -0 和 +0 代表的数值是一样的,但是在用原码和反码表示时它们是不同的。通过以上的多个示例,我们发现使用反码进行加法运算并不能保证得出正确的结果。原因是用一个字节表示数字的取值范围时,这些数字中多了一个 -0。为了解决反码出现的问题,就出现了补码。

补码

补码是一种用二进制表示有符号数的方法。正数和 0 的补码就是该数字本身。负数的补码则是将其对应正数按位取反再加 1。补码系统的最大优点是可以在加法或减法处理中,不需因为数字的正负而使用不同的计算方式。只要一种加法电路就可以处理各种有符号数加法,而且减法可以用一个数加上另一个数的补码来表示,因此只要有加法电路和补码电路即可以完成各种有符号数加法和减法,在电路设计上相当方便。

另外,补码系统的 0 就只有一个表示方式,这和反码系统不同(在反码系统中,0 有两种表示方式),因此在判断数字是否为 0 时,只要比较一次即可。下图是一些 8 位补码系统的整数,它可表示的范围包括 -128 到 127,总共 256 个整数。

既然说补码可以解决反码在运算中遇到的问题,我们继续以 6 + (-3) 为例来验证一下这个结论。

十进制

原码

反码

补码

6

0000 0110

0000 0110

0000 0110

-3

1000 0011

1111 1100

1111 1101

6 + (-3) 以补码形式的计算过程如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
6 - 3 ==> 6 + (-3)
  0000 0110 // 6(补码)
+ 1111 1101 // -3(补码)
----------------------
  0000 0011 // 3(补码)

很明显这时我们得到了正确的结果,那么我们再来看一下以补码形式计算 1 - 1 的计算过程:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1 - 1 ==> 1 + (-1)
  0000 0001 // 1(补码)
+ 1111 1111 // -1(补码)
----------------------
  0000 0000 // 0(补码)

可以发现,补码完美解决了反码的问题,最后我们来介绍一下位移运算。

四、位移运算

位移运算需要使用按位移动操作符,它有两个操作数:第一个是要被移动的数字,而第二个是要移动的长度。移动的方向根据操作符的不同而不同。

按位移动会先将操作数转换为大端字节序顺序(big-endian order)的 32 位整数,并返回与左操作数相同类型的结果。右操作数应小于 32 位,否则只有最低 5 个字节会被使用。

左移(<<)

该操作符会将第一个操作数向左移动指定的位数。向左被移出的位被丢弃,右侧用 0 补充。以 9 << 2 为例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
     9 (base 10): 00000000000000000000000000001001 (base 2)
                  --------------------------------
9 << 2 (base 10): 00000000000000000000000000100100 (base 2) = 36 (base 10)

在数字 x 上左移 y 位时,得出的结果是 x 2^y,即 `9 << 2 = 9 2^2`。

有符号右移(>>)

该操作符会将第一个操作数向右移动指定的位数。向右被移出的位被丢弃,拷贝最左侧的位以填充左侧。由于新的最左侧的位总是和以前相同,符号位没有被改变。所以被称作 “符号传播”。

例如, 9 >> 2 得到 2:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
     9 (base 10): 00000000000000000000000000001001 (base 2)
                  --------------------------------
9 >> 2 (base 10): 00000000000000000000000000000010 (base 2) = 2 (base 10)

相比之下, -9 >> 2 得到 -3,因为符号被保留了。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
     -9 (base 10): 11111111111111111111111111110111 (base 2)
                   --------------------------------
-9 >> 2 (base 10): 11111111111111111111111111111101 (base 2) = -3 (base 10)
无符号右移(>>>)

该操作符会将第一个操作数向右移动指定的位数。向右被移出的位被丢弃,左侧用 0 填充。因为符号位变成了 0,所以结果总是非负的。

对于非负数,有符号右移和无符号右移总是返回相同的结果。例如 9 >>> 29 >> 2 一样返回 2:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
      9 (base 10): 00000000000000000000000000001001 (base 2)
                   --------------------------------
9 >>> 2 (base 10): 00000000000000000000000000000010 (base 2) = 2 (base 10)

但是对于负数却不尽相同。 -9 >>> 2 产生 1073741821 这和 -9 >> 2 不同:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
      -9 (base 10): 11111111111111111111111111110111 (base 2)
                    --------------------------------
-9 >>> 2 (base 10): 00111111111111111111111111111101 (base 2) = 1073741821 (base 10)
 -9 >> 2 (base 10): 11111111111111111111111111111101 (base 2) = -3 (base 10)

五、参考资源

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020/01/06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
【C#学习笔记03】进制转换与反码、补码、原码
计算机中的数据通常以二进制形式存储,但在编程和调试过程中,我们经常需要与十进制、八进制和十六进制打交道。因此,掌握进制转换是C语言学习中的重要一环。
一条晒干的咸鱼
2025/03/12
1070
【C#学习笔记03】进制转换与反码、补码、原码
【C语言】中的位操作符和移位操作符,原码反码补码以及进制之间的转换
同样都是数字1111,不同进制下数字的大小不同,第二行代表的是其各位数字十进制下的大小,将各位数字的十进制大小相加即1111在这个进制下转化为十进制的大小,从图中我们可以看出来进制的定义:从右往左一次用各位上的数字乘以这个进制的n次方(n为从右往左以0为首依次++的数字)
s-little-monster
2024/06/06
1290
【C语言】中的位操作符和移位操作符,原码反码补码以及进制之间的转换
C语言:进制转换以及原码、反码、补码
         其实我们经常能听到2进制、8进制、10进制、16进制这样的讲法,那是什么意思呢?其实2进制、8进制、10进制、16进制是数值的不同表⽰形式⽽已。
小陈在拼命
2024/02/17
6770
C语言:进制转换以及原码、反码、补码
「硬核JS」数字之美
一直都在佛系更新,这次佛系时间有点长,很久没发文了,有很多小伙伴滴我,其实由于换工作以及搬家的原因,节奏以及时间上都在调整,甚至还有那么一小段时间有点焦虑,你懂的,现已逐渐稳定,接下来频率应该就会高了,奥利给~
isboyjc
2022/03/28
5.6K0
「硬核JS」数字之美
数据的表示:原码、反码、补码、移码以及浮点数的运算
最近在备战软考,复习到数据表示方面相关的知识,所以在这里做一下记录,也方便大家参考。
村雨遥
2021/10/11
2.5K0
数据的表示:原码、反码、补码、移码以及浮点数的运算
三分钟基础:举个例子读懂原码、反码与补码
在 Go 语言中,int8 代表有符号 8 位整数。你觉得输出结果是什么呢?我们在文末再公布答案,在此之前,我们先来回顾一下有符号整数是什么。
帅地
2019/12/06
1.7K0
三分钟基础:举个例子读懂原码、反码与补码
一个案例搞懂原码、反码、补码,不懂得请看过来
根据冯~诺依曼提出的经典计算机体系结构框架。一台计算机由运算器,控制器,存储器,输入和输出设备组成。其中运算器,只有加法运算器,没有减法运算器(据说一开始是有的,后来由于减法器硬件开销太大,被废了 )
用户7656790
2020/08/13
1.1K0
一个案例搞懂原码、反码、补码,不懂得请看过来
学弟不懂原码反码补码,气的我给女朋友讲了一夜
故事是一个真实的故事,前两天要被一位小学弟折磨死,原码、反码、补码不懂就算了,讲了一遍还不懂。
bigsai
2020/08/04
5070
学弟不懂原码反码补码,气的我给女朋友讲了一夜
数字逻辑基础:原码、反码、补码
以3为例,+3对应的二进制数是00000011,-3对应的二进制数是10000011。
WuShF
2023/03/01
6670
数字逻辑基础:原码、反码、补码
反码补码和位运算
三者是计算机存储数据的不同形式,计算机用补码存储数据。而且计算机利用这三者可以用加法实现减法
晚上没宵夜
2020/04/24
6620
深度理解 原码, 反码, 补码
本篇文章讲解了计算机的原码, 反码和补码. 并且进行了深入探求了为何要使用反码和补码, 以及更进一步的论证了为何可以用反码, 补码的加法计算原码的减法. 论证部分如有不对的地方请各位牛人帮忙指正! 希望本文对大家学习计算机基础有所帮助! 一. 机器数和真值 在学习原码, 反码和补码之前, 需要先了解机器数和真值的概念. 1、机器数 一个数在计算机中的二进制表示形式,  叫做这个数的机器数。机器数是带符号的,在计算机用一个数的最高位存放符号, 正数为0, 负数为1. 比如,十进制中的数 +3 ,计算机字长为8
互联网金融打杂
2018/04/03
1.1K0
深度理解 原码, 反码, 补码
一文读懂原码、反码、补码
本文转载自: https://blog.csdn.net/u011488256/article/details/52204074 作者:僵尸男孩
我的小碗汤
2018/10/18
5160
计算机原码反码补码怎么算_-35的原码反码补码
最近花了点时间对计算机的原码,反码和补码进行了研究,对为什么要有反码和补码以及他们这么设计的原因有了一定的理解
全栈程序员站长
2022/08/03
9090
计算机原码反码补码怎么算_-35的原码反码补码
原码、反码、补码详解
一个数在计算机中的二进制表示形式,叫做这个数的机器数。机器数是带符号的,在计算机用一个数的最高位存放符号,正数为 0,负数为 1。
马修
2021/01/21
1K0
原码,反码,补码的深入理解与原理答案_原码反码补码例题详解
本文从原码讲起。通过简述原码,反码和补码存在的作用,加深对补码的认识。力争让你对补码的概念不再局限于:负数的补码等于反码加一。
全栈程序员站长
2022/09/29
7980
原码,反码,补码的深入理解与原理答案_原码反码补码例题详解
世界上有10种人,一种是懂二进制的人,一种是不懂二进制的人。
看到这个问题,我想到了之前的一个场景是要获取近30天的日期列表,我的思路是通过System.currentTimeMillis()获取当前时间戳,然后依次减去对应的毫秒数(24 * 60 * 60 * 1000),后来发现问题:30 * 24 * 60 * 60 * 1000因为超过了int的上限值而变为了一个负数。于是我回复他:
敲得码黛
2021/02/22
1.4K0
世界上有10种人,一种是懂二进制的人,一种是不懂二进制的人。
计算机基础(4)——原码、补码、反码
计算机为了区分数值的正负提出了符号位的设定,计算机用最高位存放符号,这个被称为符号位。正数的符号位为0, 负数的符号位为1。
绿水长流z
2025/01/03
1910
计算机基础(4)——原码、补码、反码
原码、反码、补码的正(nao)确(can)打开方式
IT可乐
2018/01/04
1.2K0
原码、反码、补码的正(nao)确(can)打开方式
数值信息的机器级存储
计算机中使用八位的块,或者说是「字节」,作为最小的寻址单元。你可以将整个存储器视作一个超大的「字节数组」,每个字节都有一个唯一的数字编号,这个编号就是所谓的地址,通过这个地址,我们可以唯一的确定一块数据。但是我们代码中定义的各种数值又是如何转换为二进制串存储在这些「字节」里面的呢?为什么两个整数相加之后的结果会变成负数?
Single
2018/03/14
1.3K0
数值信息的机器级存储
计算机原理-原码、补码、反码
原码就是原来的编码,就是字面意思,而补码和反码比较奇怪,为什么需要这两种编码,意义是什么?
潇洒
2023/10/20
2360
推荐阅读
相关推荐
【C#学习笔记03】进制转换与反码、补码、原码
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验