补码(为什么按位取反再加一):告诉你一个其实很简单的问题(转自醍醐灌顶)...

首先,阅读这篇文章的你,肯定是一个在网上已经纠结了很久的读者,因为你查阅了所有你能查到的资料,然后他们都会很耐心的告诉你,补码:就是按位取反,然后加一。准确无误,毫无破绽。但是,你搜遍了所有俯拾即是而且准确无误的答案,却仍然选择来看这篇毫不起眼的文章,原因只有一个,只因为你还没有得到你想要的东西。

             因为你想要的,不是1+1=2,而是,1+1为什么等于2。当然,我们不讨论1+1的问题。我们讨论的,是补码。

             你已经困惑了很久,你明明知道补码就是按位取反,然后加一,但是你想知道的,不是它怎么求滴,而是,它怎来滴。当然,对于阅读这篇文章的你,既然想要知道这个答案,一定是有一定编程基础的读者,肯定知道补码与有符号数与无符号数的关系(有符号数指带有正负号的数,无符号可以理解为只大于0的数),你所查阅的所有资料首先都会用一个8位的二进制数给你举例,ok,我们也用一个8位的二进制数。

             8位二进制数,最小00000000,最大数11111111,换算十进制为0~255,当然,所有的参考资料都会这样讲,而且这也不是你想要的,但我们必须说下去。1~255,一共255的字符,再加上最前面的0,一共256个字符。现在,我们要用一个8位二进制数字来表示一个负数,可是二进制里没有负号,谁都知道二进制里只有0,1,再无其他符号。那么所以我们必须用一种方式来代替正负,也就是我们规定,当然是人规定的,而不是电脑,我们规定这个8位的二进制数的最前面一位数来表示这个数的正负,0代表是正,1代表是负。那么当第一位是0时,我们一共可以表示00000000~01111111这么多正数,因为第一位必须是0来代表正数;当第一位是1时,我们一共可以表示10000000~11111111这么多负数,然后,我们用00000000~01111111来代表0~127,那岂不是10000000~11111111代表  -0  ~  -127??可是网上都说不能有 负0,可是我觉的没什么不妥啊,负0不还是0 吗?10-0=10,不就是相当于10+(-0)=10吗,现在我们不讨论正负0的问题,我们来讨论一个小学生的问题。

             我们现在要把00000000~11111111分成两组数,一组是正数,另一组是负数,正数是0,1,2,3,4,5,6,7,8,… 负数是 -1,-2,-3,-4,-5,-6,-7,-8,… 那么这里就有一个小学问题,那就是1+(-1)肯定要等于0,2+(-2)=0,他们是相反数,相加等于0,小学生都会。后面都是一样,那么现在我们使用上面的编码的方式进行一个计算,现在上面的编码中 1 对应的二进制是00000001,-1对应的二进制是10000001,然后你把这俩二进制数加起来,看看等于几,对,答案是10000010,不是00000000,也不是10000000,  10000010在上面的编码中代表 -2,00000000和10000000都在上面代表0,可是结果并不是他们。而00000001与10000001分别对应着1和-1,加起来理论的结果应该是0才对,也就是说上面的编码是错误的。

            或许接下来很多资料又讨论了反码,但是我们不,我们来求一个一元一次函数,一个小学的函数,1+x=0,求x=?,答:-1。没错,而且准确无误。那么现在问题来了,前面的正数编码应该是没有错的,00000000代表0,  00000001代表1,这些都符合我们的习惯,那么出错的是在后面的负数编码上,我们到底该如何编码对应负数编码它才能正确呢,因为我们知道1+(-1)必须等于0,也就是他们对应的二进制相加也必须等于0,1对应00000001,那么00000001+x=00000000,里面的x就应该代替 -1的二进制编码才对,这样,我们得到 x=11111111,大家看一下这和按位取反,然后加一的结果一样吗。

           所以我们的结论是,一个正数对应的负数(也就是俩相反数),这两个数的二进制编码加起来必须等于0才对,所以我们只要知道其中一个数的编码x,然后用0-x就是他对应的数的编码,这样的话,从0~127,我们用(0 - 其中一个二进制数的编码)=(另一个二进制数的编码),例如 2 的二进制编码是00000010,那么-2 的二进制编码就是0 - 00000010=11111110,因为他就应该这样,因为它就是一个小学问题,他俩加起来就应该等于0。那么1000000对应的编码是多少呢,当然也必须满足加起来等于0才行,那么10000000+x=0,求解x,答x=10000000,还是它本身,也就是在00000000~11111111这个范围里所有的二进制数都无法满足它,也就是没有一个数加上它等于0,但是两个数要有对应的编码,就必须加起来等于0才行,其实不止它没有,0也没有,0+x=0,那么x=0,也是它本身,既然这样了,那么也没有办法了,无可奈何只能做单身汉了,然后我们规定,既然10000000第一位是1,代表负数,那么我们规定它是一个负数,那么10000000就代替了-128,而且,它只自己一个人,也就是只有-128,没有正数128。

         然后,他们每个数都有了自己对应的编码,而且准确无误。1~127对应-1~ -127,再加上两个单身汉0和-128。然后呢,不知道谁起的名字,就把这种编码叫做了补码,如果你乐意,你也可以给它起个名字。但是呢,还有一个问题,为什么补码的求法是按位取反再加一呢,其实当你不明白为什么各大书籍都要用按位取反来计算补码的时候,我们完全可以直接用0减去它就得到他相反数的二进制编码了,譬如随便一个十六进制数 6C ,那么我们可以直接0-6C就得到他的相反数的补码了,结果为十六进制的94,跟按位取反再加一的效果一样。

         现在我们知道补码是怎么来的了,也就是为了保证两个相反数对应二进制的和必须是0,然后又不知道谁给它起了补码这个名字。补码补码,有没有感觉两个相反数是互补的呢,也就是任意两个相反数加起来一定等0,其中一个数变大,另一个就一定会变小互补保证结果为0。但是你肯定还在纠结,为啥要按位取反,为啥还要加一呢。其实,这涉及到一个二进制减法的问题,你既然知道补码这个概念,就一定会知道有进位丢失这么个东西。现在我们知道了补码是怎么来的,也就是(00000000 - 其中一个正数的补码)=(这个数相反数的补码),那么我们知道了1的二进制是00000001,那么我们来求-1的补码,也就是应该00000000 - 00000001=?,我们该怎么计算这个二进制减法呢,而且还是一个小数减去大数,连借位都没地方借,前面我们提到进位丢失这个东西,那么我们来计算一个算式,11111111+00000001=?知道进位丢失的你,肯定知道加起来后等于00000000,虽然结果应该是100000000(后面是8个0),但是只能有8位,所以最高位的1丢失了,那么现在好了,也就是说,我们可以把00000000看做(11111111+00000001)因为他俩是相等的,我们已经计算过的了,那么我们现在就可以把前面讲的公式中的00000000换成(11111111+00000001),也就是我们要计算-1的补码,我们就0-1的编码,也就是00000000-00000001,也就是(11111111+00000001)-00000001=(-1的补码),这个算式我觉的你应该会计算了,大数减小数,到现在,或许你现在已经发现什么了,是的,你发现了之前一直迷惑你的一个东西,“按位取反再加一”,但是可能还有一点迷惑,我们继续,因为我们每次都是用一个0减去一个数的补码来得到另一个数的补码,也就是里面的(11111111+00000001)是不变的,因为它就是0,那么我们现在要求一个数的补码,就是(11111111+00000001)- 一个数的补码=它相反数的补码,咱们把括号去掉,也就是11111111 - 一个数的补码+00000001=它相反数的补码,这是加法交换法则,只是把位置交换一下,小学生都会的,然后呢再加个括号方便我们理解,也就是(1111111 - 一个数的补码)+00000001=它相反数的补码。好了,问题来了,(11111111 - 一个数的补码)的结果是什么,这个你心里应该是清楚的,你也可以算一下,它正好的等于它的反码,也就是按位取反的一个数,其实也好理解,你减几个数就看见规律了,描述好麻烦,现在好了,也就是(11111111 - 一个数的补码)=这个数的反码,也就是(11111111 - 一个数的补码)=把这个数按位取反,到现在,你应该你已经很清楚他是怎么来的了。

         那么我们现在就可以把公式写成这样,(11111111 - 一个数的补码)+00000001=它相反数的补码,现在我们知道了(11111111 - 一个数的补码)=把这个数按位取反,然后把公式里的(11111111 - 一个数的补码)换成 “按位取反”,也就是 (按位取反)+000000001=它相反数的补码,现在,按位取反,再加一,就终于出来了,这就是各大书籍资料所讲的,补码=按位取反+1..。好了,真相大白

         本文章属个人领悟,错误必有,不吝赐教

转载于:https://www.cnblogs.com/zhugeanran/p/9223501.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/570699.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Kettle报错:Entry to update with following key could not be found

问题描述: 一个转换对一个表进行插入操作,第一次查询然后插入数据,但是有些字段需要特殊处理下,也就是要先插入主要的信息,然后针对这个记录根据刚才生成的id进行更新操作,在开发环境上测试没问题&#xf…

IntrospectorCleanupListener作用

https://www.cnblogs.com/qiankun-site/p/5886673.html 1、此监听器主要用于解决java.beans.Introspector导致的内存泄漏的问题 2、此监听器应该配置在web.xml中与Spring相关监听器中的第一个位置(也要在ContextLoaderListener的前面)3、JDK中的java.beans.Introspector类的用途…

CentOS安装Oracle12C

文章转载: https://www.howtoforge.com/tutorial/how-to-install-oracle-database-12c-on-centos-7/

7-2 幼儿园数学题(29 分)

我系渣渣辉,我在梦工厂等你,是兄弟就来砍我啊!! 刚上幼儿园的渣渣辉迷上了一款名叫贪玩蓝月的新游戏,由于过于沉迷游戏,上课听讲的效率直线下降。 今天,他的数学老师给他布置了一道求解二元一次…

PLSQL中文显示乱码(问号)

1、输入 select * from V$NLS_PARAMETERS 查看第一行value值是否为简体中文 simplified chinese 实际显示为:AMERICAN 2、设置本地环境变量 :NLS_LANG NLS_LANGAMERICAN_AMERICA.ZHS16GBK NLS_LANG的值为三个划线值拼接而成。 3、重新打开PLSQL…

python2精确除法

python2和python3除法的最大区别: python2: print 500/1000 python2结果:取整数部分,小数并没有保留 0Process finished with exit code 0 python3: print 500/1000 python3结果:得到真实结果,小数保留 0.5Process finished with exit code 0 那么,如果python2想保留小数部分,要…

vim 中代码的折叠和打开

文章转载自:http://liufabin66688.blog.163.com/blog/static/13968548200810140486304/ 仅用于个人学习备查收藏。 在查看代码的时候,如果代码十分冗长,尤其是c/c系列的时候, 代码结构比较让人难以理清,主要是各种注…

WGCNA | weighted correlation network analysis

早就接触过这个包了,只是一直畏惧,以为很复杂,也没有应用场景,所以认识很肤浅。 现在有应用场景了,我自己开发了一个幼稚的版本,发现了很多需求,后来想起了WGCNA似乎部分解决了我的问题&#xf…

CentOS7安装Oracle11g R2全过程

安装过程主要参考: 1、https://www.howtoforge.com/tutorial/how-to-install-oracle-database-12c-on-centos-7/ 2、http://www.cnblogs.com/sonnychen/p/5366021.html 3、 https://www.jianshu.com/p/57e3e6ad81ef 遇到的问题: 1、安装完KDE&…

Mybatis下collections使用pageHelper进行分页

pageHelper在对mybatis一对多分页时造成查询总页数结果不对的情况。 可以做出如下修改&#xff1a; service层&#xff1a; public CommonResult worksList(String userId, int page, int pageSize) throws Exception { PageHelper.startPage(page, pageSize); List<…

使用Kylin导入JDBC数据源遇到的问题

一、目标&#xff1a; 直接使用Mysql数据作为Kylin数据源 二、参考官方配置 JDBC 数据源 准备 Sqoop Kylin 使用 Apache Sqoop 从关系型数据库加载数据到 HDFS。在与 Kylin 同一个机器上下载并安装最新版本的 Sqoop。我们使用 SQOOP_HOME 环境变量指出在本指南中 Sqoop 的安…

php 通过array_merge()和array+array合并数组的区别和效率比较

众所周知合并两个数组可以使用array_merge()&#xff0c;这是php提供的一个函数。另外还可以通过 array 的方式来合并数组&#xff0c;这两种直接有什么区别&#xff0c;哪一个的效率更高呢&#xff1f; array_merge() 格式&#xff1a; array array_merge ( array … ] ) 注意…

解决ubuntu系统root用户下Chrome无法启动问题

说明&#xff1a;本文转载自-https://www.cnblogs.com/hbsygfz/p/8409517.html 由于ubuntu16.04系统自带的是Firefox浏览器&#xff0c;需要安装Chrome浏览器&#xff0c;但是在root用户下安装后发现&#xff0c;Chrome无法正常启动。安装及问题解决具体如下&#xff1a; 1. …

mysql ERROR 1045 和2058时(28000): 错误解决办法

mysql ERROR 1045 (28000): 错误解决办法 听语音|浏览&#xff1a;54286|更新&#xff1a;2018-02-23 14:34|标签&#xff1a;mysql 1234567分步阅读ERROR 1045 (28000): Access denied for user ODBClocalhost (using password: NO) ERROR 1045 (28000): Access denied for us…

Hive设置参数-指定引擎-队列

文章转载&#xff1a;https://www.cnblogs.com/huangmr0811/p/5571001.html Hive提供三种可以改变环境变量的方法&#xff0c;分别是&#xff1a;&#xff08;1&#xff09;、修改${HIVE_HOME}/conf/hive-site.xml配置文件&#xff1b;&#xff08;2&#xff09;、命令行参数&…

php实现 字符串加密(分类分布分工,化不可能为可能)

php实现 字符串加密&#xff08;分类分布分工&#xff0c;化不可能为可能&#xff09; 一、总结 一句话总结&#xff1a;谋而后动&#xff0c;加先伪代码&#xff0c;在带函数逻辑&#xff0c;在函数的方式可以极大的避免错误和降低难度。不然这个题目乎出现各种乱七八糟的错误…

Redis集群安装

注&#xff1a;官方给出的安装文档是在一台物理机安装多个Redis实例&#xff0c;https://redis.io/topics/cluster-tutorial&#xff0c;我的生产环境是多台物理机&#xff0c;安装起来就更简单 环境: 6台物理机 CentOS7.2-1511-minimal ip:192.168.1.101-192.168.1.106 网…

Redis-集群监控之Redis monitor

连续两天配置Redis 集群监控&#xff0c;尝试过三种开源软件&#xff0c;Redis-live,Redis-state,Redis-monitor &#xff0c;由于内网生产环境&#xff0c;每一个软件的部署都费了老劲。 简单说一下&#xff0c;避免再有人趟坑。 1、Redis-live&#xff1a;此项目5年没有维护…

Magento 架构原则

Magento架构原则 》OOP体系结构和编程原则OOP体系结构和编程原则面向对象编程&#xff08;OOP&#xff09;设计允许软件组件具有最大的灵活性和可扩展性&#xff0c;允许您设计和实现高度定制的网站。面向对象原则的优点包括结合行业标准的编程设计模式以及业务逻辑与表示的严格…

vue-cli脚手架中webpack配置基础文件详解

一、前言 vue-cli是构建vue单页应用的脚手架&#xff0c;输入一串指定的命令行从而自动生成vue.jswepack的项目模板。这其中webpack发挥了很大的作用&#xff0c;它使得我们的代码模块化&#xff0c;引入一些插件帮我们完善功能可以将文件打包压缩&#xff0c;图片转base64等。…