「原码 反码 补码 移码」一探究竟(中)

「原码 反码 补码 移码」一探究竟(中)

原文链接

上文「原码 反码 补码 移码」一探究竟(一)说了基本定义和原码,对于补码,我们只知道是对原码符号位不变,其他位置取反,最后再加 1 得来的,为何如此呢?接下来咱们来揭下「补码」的面具,看看它到底是什么。

0. 关于 1 + (-1)

首先,先看一个问题。

1 的原码为[0000 0001],-1 的原码为[1000 0001],所以计算这两个数相加,应该是这样的:

1 + (-1) 

= [0000 0001]原 + [1000 0001]原 

= [1000 0010]原 

= -2
复制代码

结果竟然是 -2,很明显是错的,这样用原码计算就出问题了。当然,劳动人民的智慧不可估量,总能发现合适的方式来解决各种问题,于是,补码就诞生了,再看用补码计算的过程。

1 + (-1) 

= [0000 0001]原 + [1000 0001]原 

= [0000 00001]补 + [1111 1111]补 

= [0000 0000]补 

= [0000 0000]原 

= 0
复制代码

结果正确,问题得以解决,而这也是计算机都是以补码的形式来存储整数的原因。

但是,为什么用补码计算就能得到正确结果呢?为什么补码的计算方式是原码取反再加 1 呢?带着问题,我们继续往下看。

1. 钟表上的哲学

钟表,每个人应该都清楚的,上面的数字范围[0,11],也可以理解为[1, 12],毕竟上面没有写 0 这个数字,但是不变的是,都可以表示12个小时。

比方说,现在是 9:00,时针指向9。我要想知道 7 个小时之前是几点,那么我只需要将时针向回拨动 7 个格子即可,结果很显然,时针将会指向 2,表示 2:00;但是,我要想知道 5 个小时后是几点呢?也很简单,将时针向前拨动 5 个格子,结果也很显然,时针也会指向 2,表示 2:00。

通过不同方式,我们得到了同样的结果,也就是说在钟表上,9 – 7 = 9 + 5 = 2。不仅 7 和 5 有这样的规律,8 和 4、9 和 3等都有这样的规律,也就是说,相加等于 12 的两个数都符合这样的规律,即 X – Y = X + (12 -Y),而 12 在这里有个名字,叫做这个钟表的,12 – Y 叫做 Y 的补数

减去一个数,等于加上这个数的补数,应用这个规律就可以将减法转换为加法了。

那么问题来了,模长该怎么求?

2. 通俗的「模」

通俗的讲,很简单。还是拿钟表举例,上面能表示的数字的总数就是其模长,所以不管是[0, 11],还是[1, 12],都为12。

再来看 8 位二进制,其原码能表示的范围 (注意看,这里说的是原码),[1111 1111] ~ [0111 1111],即 [-2^7 – 1, 2^7 – 1] = [-127, 127],因为我们是要将其全部转变为非负数,即能表示的范围为[0, 127],所以模长为 128。

说完了这些,我们再来重新看下 -3 的补码的计算过程。-3 原码为 [1000 0011],而取反的过程实际上等同于用[0111 1111]减去 -3 原码中的符号位之外的部分,之后再加 1 即得到补码,所以:

-3 补码(未添加符号位)

= [1000 0011]原 取反 + [0000 0001]

= [0111 1111] - [0000 0011] + [0000 0001]
 
= [0111 1111] + [0000 0001] - [0000 0011]
 
= [1000 0000] - [0000 0011]

= 128 - [0000 0011]

= 模  - [0000 0011] 

= 模  - 3
复制代码

看到这,是不是一下就明白了?补码实际上就是模减去原码的值,再加上一个符号位,也就是所说的:符号位不变,取反再加1

所以,在计算机中,整数都是以补码的形式存储的,是为了统一加减法运算。因为计算机之中是没有做减法的逻辑门,减法都会被转化为加法来完成计算。

而通过溢出,符号位也可以直接参与计算,大大简化了计算过程,看个例子就明白了。

7 + (-3)

= [0000 0111]原 + [1000 0011]原 

= [0000 0111]补 + [1111 1101]补 

= [0000 0100]补 (溢出部分不用处理)

= [0000 0100]原 

= 4 

2 + (-3)

= [0000 0010]原 + [1000 0011]原 

= [0000 0010]补 + [1111 1101]补 

= [1111 1111]补 

= [1000 0001]原 

= -1
复制代码

再看个特例。

-1 + (-127) 

= [1000 0001]原 + [1111 1111]原 

= [1111 1111]补 + [1000 0001]补 

= [1000 0000]补 

= -128
复制代码

用原码能表示的最小负数为 -127,补码却能表示的最小负数为 -128,但是 -128 没有原码和反码表示,由于计算机中使用补码表示整数,所以这没有影响,因此 8 位二进制数,也就是 byte 类型能表示的范围是 [-128, 127]

说到这,对于补码,应该足够清晰了吧!


欢迎关注同名公众号「码一八」获取更多内容,用技术改变生活!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/101163.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 懒加载(Lazy Loading) – MyBatis懒加载 – Spring懒加载

    懒加载(Lazy Loading) – MyBatis懒加载 – Spring懒加载文章目录懒加载(LazyLoading)MyBatis中懒加载的使用Spring中懒加载的使用懒加载(LazyLoading)  懒加载也叫“延迟价值”,核心思想是把对象的实例化延迟到真正调用该对象的时候,这样做的好处是可以减轻大量对象在实例化时对资源的消耗,而不是在程序初始化的时候就预先将对象实例化。另外“懒加载”可以将对象的实例化代码从初始化方法中独立出来,从而提高代码的可读性,以便于代码能够更好地组织。  特别是在web应用程序中,它能够在用户滚动页面的时候自动获取更多的数据,而新得到的数据

  • rsyslog日志服务器_php日志系统

    rsyslog日志服务器_php日志系统特性介绍:http://www.rsyslog.com/features/下载: http://www.rsyslog.com/download/本文内容来源于:http://blog.csdn.net/xiangliangyu2008/article/details/8102064===========================

  • 汇编语言——移位指令[通俗易懂]

    基本概念移位操作指令:移位操作指令是一组经常使用的指令,属于汇编语言逻辑指令中的一部分,它包括移位指令(含算术移位指令、逻辑移位指令),循环移位指令(含带进位的循环移位指令),双精度移位指令三大类。其功能为将目的操作数的所有位按操作符规定的方式移动1位或按寄存器CL规定的次数(0~255)移动,结果送入目的地址。目的操作数是8位(或16位)的寄存器数据或存储器数据。基本格式格式为…

  • 打出三位数的所有水仙花数「建议收藏」

    打出三位数的所有水仙花数「建议收藏」/** * 题目:打印出所有的 "水仙花数 ",所谓 "水仙花数 "是指一个三位数, * 其各位数字立方和等于该数本身。例如:153是一个 "水仙花 * 数 ",因为153=1的三次方+5的三次方+3的三次方 */public class 水仙花数 { public static void main(String[] args) { for (int i = 100; i &l…

  • Postman汉化版本竟如此简单,全中文真香「建议收藏」

    Postman汉化版本竟如此简单,全中文真香「建议收藏」因此可以使用Apifox替代postman完成日常的接口调试工作。Apifoxsaas版本完全免费,

  • Linux chmod命令用法

    Linux chmod命令用法chmod—-改变一个或多个文件的存取模式(mode) chmod[options]modefiles 只能文件属主或特权用户才能使用该功能来改变文件存取模式。mode可以是数字形式或以whoopcodepermission形式表示。who是可选的,默认是a(所有用户)。只能选择一个opcode(操作码)。可指定多个mode,以逗号分开。 options:

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号