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

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

原文链接

上文「原码 反码 补码 移码」一探究竟(一)说了基本定义和原码,对于补码,我们只知道是对原码符号位不变,其他位置取反,最后再加 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]

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


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

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

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

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • docker入门(利用docker部署web应用)[通俗易懂]

    docker入门(利用docker部署web应用)[通俗易懂]前言:本课程是在慕课网上学习第一个docker化的java应用课程时所做的笔记,供本人复习之用目录第一章什么是docker1.1docker的发展史1.2docker国内应用史1.3什么是Docker第二章了解docker2.1docker思想2.1.1集装箱2.1.2标准化2.1.3隔离2.2docker解决的问题2.2.1…

    2022年5月28日
    37
  • Lunix 命令_linux常用基本命令实例

    Lunix 命令_linux常用基本命令实例将常用到的Lunix基本命令整理一下。1.文本编辑命令使用:vifilename:对文本可以增删改查操作。viewfilename:可以理解成vi版本的只读操作。catfilename:普通查阅2.vi命令详解(1)退出并保存::ZZ或是:wq退出不保存::q!(2)光标移动:hjkl分别对应←…

    2022年9月27日
    2
  • Springboot面试问题总结

    Springboot面试问题总结Q:什么是springboot?A:多年来,随着新功能的增加,spring变得越来越复杂。只需访问页面https://spring.io/projects,我们将看到所有在应用程序中使用的不同功能的spring项目。如果必须启动一个新的spring项目,我们必须添加构建路径或maven依赖项,配置applicationserver,添加spring配置。因此,启动一个新的spring项…

    2022年6月6日
    27
  • 点云处理算法整理(超详细教程)

    点云处理算法整理(超详细教程)

    2020年11月8日
    844
  • 一致性哈希算法的原理(一致性哈希与哈希的异同)

    (1)一致性哈希算法将整个哈希值空间按照顺时针方向组织成一个虚拟的圆环,称为Hash环;(2)接着将各个服务器使用Hash函数进行哈希,具体可以选择服务器的IP或主机名作为关键字进行哈希,从而确定每台机器在哈希环上的位置;(3)最后使用算法定位数据访问到相应服务器:将数据key使用相同的函数Hash计算出哈希值,并确定此数据在环上的位置,从此位置沿环顺时针寻找,第一台遇到的服务器就是其应该定位到的服务器

    2022年4月14日
    60
  • OSS对象储存_oss存储是什么意思

    OSS对象储存_oss存储是什么意思简介阿里云对象存储服务(ObjectStorageService,简称OSS),是阿里云提供的海量、安全、低成本、高可靠的云存储服务。使用流程名词解释Endpoint(访问域名)Acc

    2022年8月1日
    7

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

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