本文引用文章地址

科普文章-另一个视角解读计算机编码(修订版)_dog250的博客-CSDN博客https://blog.csdn.net/dog250/article/details/73381875现将其内容搞下来,自己加一些理解。以下解读中,方括号是吊丝加上的。


第一部分 另一个视角解读计算机编码-补码编码

数学的计算机表示

数学是一个完全抽象的学科,而计算机是这个学科的一种形象化的实现,显然无法处理一些仅在抽象意义上有意义的特殊“数字”,比如无穷之类的东西。像数学中的加法,乘法这样运算,计算机必须给与实现,然而由于数学中的实数加法(以及别的运算)是建立在实数域上的,而实数域又是无限的,而计算机只能处理有限域的运算,因此必须给定一个范围,

一种方案是在这个范围内保证运算的正确性,超出范围的结果给出错误提示,然而这样的计算机不是很完美,毕竟它能力太有限了,仅仅给出错误提示是不能让人满意的,如果能在有限的编码上实现诸如实数运算那样“无错误”运算就更好了,毕竟给出错误提示并不是一个很合理的计算结果,我们不需要一个提示,而是在任何情况下(包括超出范围)都可以得到一个“能够自圆其说的正确”结果,因此计算机采用了在有限域上的加法运算后再取模的方式将结果控制在一个有限的范围内。
  计算机是基于模运算来进行加法和乘法运算的,在实现编码之前,必须有一个理论支撑,对于加法,必须实现一个阿贝尔群,它要满足交换率,拥有一个“零”,每一个元素都存在一个逆,相加后等于零,并且结果也应该在该群中,只要按照如此的规则设计一个编码,那么对于计算机而言就非常圆满了,对于任何数字的加法,我们都不会得到一个“错误”,而是很实在的得到一个正确的结果,如果实数可以表示在数轴上【无限】,那么计算机处理的数就可以表示在一个圆环上【有限】。为了方便,以下将计算机表示数的范围仅考虑成字节,实际上现在计算机表示8字节的数已经不是什么稀罕事了。

【吊丝解读,阿贝尔群的定义,可以理解成"满足加法的集合"的定义】

【以下摘自wiki百科】

阿贝尔群需要满足四个条件:【上文只提到了第2、3、4点,没提到结合律】

1.结合律  (a+b)+c = a+(b+c)

2.单位元:要存在一个数e,使得 e+a=a+e=a 成立。我们都知道就是0了

3.逆元:使得任意的元素a有一个逆元素假设是b,使得 a+b=e(单位元即0)

4.交换律  a+b = b+a

计算机为什么要如此编码

【计算机编码,是为了让计算机可以根据编码格式,设计硬件电路,得到人类期望结果的设计。比如人们设计了源码、反码、补码,就是为了让计算机能按照电路结构自行运算人类期望的加法。】

一个字节可以表示从00000000到11111111范围内的256个数字,由于计算机编码不区分有符号和无符号数,按照和实数的一致性,我们将其视为有符号数, 这样的话负数和正数应该各占一半,它们中间有一个0,由于十进制数和二进制数仅仅是数制的不同,不管在什么数制下,0都是不变的,那么显然需要将0编码为00000000。【得到了计算机中阿贝尔群单位元0的编码】

现在考虑一下这样做的后果,8位二进制数的最小值被编码成了0,那么负数怎么办呢?毕竟没有比0更小的数字了啊!想象一下,我们现在做的事是“编码”,一个数字的编码只是一种表示方式,它真正的含义是其字面上的值,而不是编码的值,比如说,我们可以将数字1编码成“0”,而将数字0编码为“123”,仅此而已。

为了表示负数,我们先从-1开始考虑,在字面上【在人类的定义中】,-1加上1就是0,而1的二进制编码就是00000001(二进制和十进制仅仅数制不同,编码正数和0当然就是完全按照字面意义进行数制转换编码的,编码负数其实就是编码一个符号“-”),其最低位就是1,根据二进制加法,要想x+00000001的结果为00000000,x的值必然是11111111,但是不对啊,8位的1和00000001加在一起是100000000而不是00000000,也就是说,结果是9位,超出了一个字节。
  不过这没有关系,我们的前提是计算机只能表示8位的数字,那么最高位的1当然算是溢出了,我们得到的结果就是00000000,因此-1的编码就是11111111,【得到了计算机负数的编码】

接下来-2呢?很显然-2+1=-1,因此-2为11111110,依次类推,我们得到的最小的负数为10000000,这是为什么呢?设想还能表示比它小1的负数x,则x+1=100000000,这样的话x的值就是01111111了,我们姑且将这个数看成是比10000000还小1的一个负数,接下来考虑一下正数,我们知道1的编码是00000001,2的编码是00000010,依次类推,我们也得到了01111111这个数,这是因为计算机将它能表示的数字编码在一个圆环上而不是一个数轴上,那么01111111到底是正数还是负数呢?这时候考虑一下阿贝尔群的性质,如果将01111111编码为负数,那么它将和它的逆元相加结果为00000000,既然计算机算术仅仅最后做了取模操作,其它的群性质和实数域的是一样的,因此01111111的逆肯定是正数,我们求出它的逆是10000000,而这个数是我们从-1开始的负数编码推导出来的一个负数编码,因此这样的假设不正确,所以01111111必然属于一个正数的编码,它的十进制数是127,它是计算机能表示的最大的整数,而10000000则是计算机能表示的最小的负数,它的十进制值是-128。【找到了8位能表示的编码中的最大值最小值】
  如果最大的正数01111111加1的结果是什么呢?结果是10000000,变成了最小的负数,这也是合理的,因为计算机将数字编码在了一个圆环上。既然计算机将数字编码在一个圆环上,那么如果我们将此圆环从10000000处劈开并拉直,将得到一个线段,上面编码的数字从10000000开始是递增的,直到01111111。有了这个形象化的概念之后,下面看一下加法的实质,一个数x在圆环上,另一个数y肯定也在圆环上,x+y的计算过程则是维持x不变,将00000000到y的这一段圆弧ar摘下来,拼接到x处,最终的ar的终点处的编码就是结果,事实上ar有两种摘取方式-顺时针和逆时针,不管哪种方式,最后结果落到同一处。

计算机加法的结果最后按照圆环的周长取模,并不是说先得到实数域的字面结果,然后再执行取模操作,而是按照前面设计的圆环,二进制加法最后的取模是自动进行的,本质上说这个“自动”是通过高位的溢出来实现的。注意,我们现在讨论的是编码,而不涉及有无符号,具体有符号还是无符号,就看指令的解释了,10000000可以是有符号的-128,也可以是无符号的128,同样,11111111可以是有符号的-1,也可以是无符号的255。

取模和溢出

编码和有没有符号是无关联的,那么取模是如何自动实现的呢?设想250+10的操作,字面操作的结果是260,可是计算机最大只能由8位来表示,因此按照无符号解释最大也只能表示为11111111,也就是255,可是260和255还相差5,显然结果需要在255的基础上再加上5,根据刚才的形象化的圆环加法,加上5之后落到了00000100这个位置,也就是十进制数4,这个4就是就是最后的结果,一个圆环的周长是256,4正好是260除以256的余数,而取余数就是取模。在计算机硬件上,这是通过溢出来实现的,255的二进制表示为11111111,它加上1之后就发生最高位溢出到第9位,由于计算机只能表示8位的数字,因此丢弃最高位,结果为[1]00000000([]中的被丢弃),一切从0开始,再加上4,结果就是4。不管在这个圆环上绕几圈,最终的落点都在圆环上,每绕一圈就会发生最高位的溢出,然后从00000000开始,这就是取模的实质。
  对于乘法,这个圆环依然使用,两个数相乘,只要有一个数是正数,那么就可以用上述的圆弧不断拼接来得到答案,比如3*2就是用2个3这个圆弧拼接两次,-2*4就是拿4个-2这个圆弧拼接四次,对于两个负数相乘,比如(-a)*(-b),总是可以拆成a*b*(-1)*(-1),只需要计算(-1)*(-1)即可,也就是11111111*11111111,列出递等式进行计算,最终的结果是[xxx]00000001,高位全部溢出了,结果就是正数1,在实数乘法中,我们人类依靠了一个规定“负负得正”,然而在计算机编码中,负号本身和数字一起被编码,依靠溢出竟然可以推导出“负负得正”这个所谓的规定,显然,计算机是不能被“规定”的,只有在纯抽象的领域才能规定,在计算机上,必须实现这个规定,将负号和数字一起编码可以解决这个问题,直接了当的推导出了一切在实数域上的异号数字乘法的性质。【人类依靠定义进行计算,计算机靠硬件电路】【其实人类依靠的定义是可以证明的,只不过没必要每个人都去证明,,,】
  加法和乘法都套入这个“圆环+溢出”模型之后,最后再来看一下0这个特殊的数字,在实数域上,-x+x=0也是一个规定,一个群的性质,然而在计算机,它却是被真实地实现的,也是依靠溢出,不失一般性,以-1+1为例,1的编码为00000001,要想得到-1的编码和1加和等于00000000,同时又没有对计算机的行为进行“规定”,根据二进制加法,只要能得到[x[y]]00000000就可以了,8位以上的不用管,由于计算机只能表示8位,8位以上的全部溢出即可,比如11111111+00000001=[1]00000000,就这样实现了群性质中的逆元加和等于零元的这个性质。

【至此可以看出,作者一直在说计算机编码要满足阿贝尔群的定义,其实也就是要满足人类世界中加法的定义】

回到现实

教科书上经常说原码,反码,补码之类的概念,还说计算机一律使用补码编码,正数和0的补码等于原码,负数的补码等于负数相反数的原码的反码加1。其实根本不需要这么复杂的概念,仅靠以上的“圆环+溢出”模型就能说明一切,什么原码,补码之类的概念根本就没有必要引出来,之所以这么引出来是为了符合科学精神,任何事物都要有概念,概念的导出是一个分析和综合的过程,在形成概念之前必然需要归纳出一个一般结论,接下来才可以形成概念。

由此可以想象,当初的编码设计者也是先想到了上述的“圆环+溢出”这个形象化的模型,进而才引出“原码,反码,补码”这些抽象的概念的,有了形象模型,再解释为何负数的补码是其相反数的反码加1就简单多了。

首先要明白负数和其相反数相加等于00000000,而由于计算机没有被“规定”而是真实实现了群的性质,因此这个00000000实际上应该是100000000,溢出了一个1到第9位,我们知道一个正数和该正数取反之后相加,会得到11111111这个数字,然而再加上1则会得到[1]00000000这个所谓的0,正数的二进制编码完全按照数制的转换机制由十进制(或者其它进制)数转化而来,因此它不能变,而负数由于需要编码一个“负号”,因此它需要被改成别的,因此就由“去掉负号的该数按位取反然后加上1”来表示负数。【去掉负号的该数按位取反,再加1。这样得到的数,就是计算机世界中正数的逆元的定义,因为此时计算机世界中正数和它的逆元相加等于0了。我们把它取名叫补码】

其中包含了两个部分,第一部分是负号,第二部门为该负数的相反数。最终,表示负数的时候,其相反数就成了“原码”,得到负数编码的中间步骤-按位取反操作的结果显然就是“反码”,而结果加1则称作补码,为了一致性,正数的补码就是原码!按照有符号数据解释,所有的负数的最高位都是1,而所有的正数最高位都是0,因此最高位也就成了负号位,注意,负号“-”的编码已经隐藏在了“取相反数-按位取反-结果加1”的整个过程中了,因此最高位虽然是符号位,它却不是负号“-”的编码,你不能说负号的编码是10000000。【好吧】
  如果教科书上不是先从原码,反码,补码这类概念讲起,而是先引出一个“圆环+溢出”的模型,最后通过这个模型自然而然导出这些概念的话,我想很多学生就不会被这些概念搞得糊涂且无助了。文艺复兴以来,西方科学精神风靡,要知道这种精神的本质和古代纯思辨推理精神的本质只差那么一点点,那就是“概念”要通过“现实的实现”来检验,任何概念都是通过归纳法得到感性认识,然后再通过推理得到一般性的表述,对于计算机编码以及任何其它的工程学原理而言,熟悉这个归纳的过程是最重要的,要比你熟练得掌握概念要有益得多,只有当你理解了这个归纳的过程,再去深入这些概念才会觉得轻松,理解概念的目的是将知识体系化,而只要理解归纳的过程才能真正学会这个概念。【昂】

附:关于编码的符号

c语言中提供了有符号和无符号两种类型的数据类型,其实这仅仅指示如何解释这个数据类型,对于汇编层次的编码来说是不区分符号的,比如11111111可以解释成无符号的255,也可以解释成有符号的-1。那么c语言的关于有无符号的数据类型是给谁看的呢?其实是给指令看的,指令负责解释一个数据是有符号的还是无符号的,和大部分人的想象不一样,这种指令非常少,按照常理,理应每个算术指令都应该提供两套才对,一套针对有符号数据,另一套针对无符号数据,实则没有这个必要。这是因为计算机的数字编码不区分符号,甚至没有大小,它完全是一个封闭的阿贝尔群,两个数相加前怎么解释,它们的和就怎么解释,因此完全没有必要设计两套指令,加法的过程完全符合正文中的圆弧拼接法则。正文中假设计算机最多用8位编码数据,然而如今的计算机可以用8位,16位,32位等不同的位数来编码数据,那么就涉及到“将一个x位的数据放到一个y位的空间中”这种事情,在计算机中,实际上每一种数据都表示一个圆环,如果系统中有8位,16位,32位三种数据的话,系统中就有三个圆环,只有将一个数据从一个圆环放到另一个圆环的指令才会考虑符号,比如现有8位编码为11111111,现将其放入16位的圆环中,如果它是无符号数,显然它是255,因此16位编码为0000000011111111,然而如果它是有符号数,那么它就是-1,它的16位编码就是1111111111111111,可见放到16位圆环中的位置是不同的,因此只有在这种情况下才需要考虑符号,故计算机硬件在这种情况下提供了指令组,比如movzx/movsx等等,在同一圆环上进行的运算根本没有必要考虑符号,因此也就不需要提供两套指令。

【movzx是8位扩展到16位时,扩展的8位填充0】

【movsx是8位扩展到16位时,扩展的8位填充原有的符号位】

【后记】

本文作者引出了阿贝尔群的概念,一开始我是非常难受的,不知道他要干嘛。其实他是在把人类世界中加法的定义要满足的规则摆出来。

计算机进行的运算要符合人类世界的预期,因此也要符合(阿贝尔群,吊丝我愿称之为加法)的定义。

继而推导出计算机世界里的补码表示,是符合加法定义的,可以正确的运算人类世界的加法题。

【CSAPP里的东西】

【一补数 ones' complement】反码

【二补数 two's complement】补码

为啥叫这么奇怪的名字啊。。。CSAPP里的解释:

非负数x反码是很多个1减去x得到考虑8位能表示的数字求反码-2的反码是1111_1111 - 2 = 1111_1111 - 0000_0010 = 1111_1101补码是 2^w - x 得到考虑8位能表示的数字求补码,w就是8。-2的补码是2^8 -2 = 1_0000_0000 - 0000_0010 = 1111_1110

科普文章-另一个视角解读计算机编码(修订版)【一个吊丝的个人理解】相关推荐

  1. 科普文章-另一个视角解读计算机编码(修订版)

    我不知道本文该作为原创发布还是作为转载发布,因为本文是<另一个视角解读计算机编码-补码编码>的"排版后的版本",内容几乎没有变,除了增加了一系列的图解. 后来想了下,还 ...

  2. 科普文章-另一个视角解读计算机编码 修订版

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! 我不知道 ...

  3. 小波科普文章精粹:看森林,也看树木

    英文原名:Wavelets: Seeing the forest and the trees 转自:http://yswhu.bokee.com/viewdiary.10391865.html 一.前 ...

  4. 两篇科普文章【开创文章】

    两篇科普文章 分享两篇来自科学松鼠会的科普性文章: 1.压缩感知与单像素相机(陶哲轩,Terence Tao) 原文链接:http://songshuhui.net/archives/11006 2. ...

  5. 科学松鼠会压缩感知科普文章两篇:“压缩感知与单像素相机(陶哲轩)”“填补空白:用数学方法将低分辨率图像变成高分辨率图像(Jordan Ellenberg)

    题目:科学松鼠会压缩感知科普文章两篇:"压缩感知与单像素相机(陶哲轩)""填补空白:用数学方法将低分辨率图像变成高分辨率图像(Jordan Ellenberg)" ...

  6. 计算机编码技术ppt,计算机编码技术.ppt

    计算机编码技术.ppt (43页) 本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦! 11.90 积分 计算机编码技术 第二章 计算机信息技术基础 第二单元2.2 ...

  7. 蛋疼的中文编码及其计算机编码历史

    更好的博客:http://my.oschina.net/goldenshaw/blog?catalog=536953 一:编码发展: 1 ANSI编码:计算机在美国出现,使用单字节8位编码,共可以表示 ...

  8. 计算机编码详解_什么是计算机编码?计算机编码的起源与操作系统是如何解码的。

    目录 前言 编码是什么? 操作系统是如何绘制编码的 编码的起源 Unicode和Utf-8的区别 什么是抽象码?它与编码的区别 Utf-8与Utf-16 目前是谁在维护编码统一性? 宽字符与窄字符的区 ...

  9. 机器学习科普文章:“一文读懂机器学习,大数据/自然语言处理/算法全有了”

    PS:文章主要转载自CSDN大神"黑夜路人"的文章:           http://blog.csdn.net/heiyeshuwu/article/details/43483 ...

最新文章

  1. 暂停发布,谢谢支持!
  2. linux 下,解决tomcat服务器接收中文乱码的问题
  3. 最大公共子序列、子串、可重叠重复子串
  4. 安全的 ActiveMQ
  5. 【实用】ABAP“FOR ALL ENTRIES”的Hints 优化
  6. 修改mysql的max_allowed_packet值
  7. 算法训练 出现次数最多的整数
  8. 外观模式和代理模式的联系和区别_java23种设计模式-结构型模式之外观模式
  9. OJ1001: 植树问题
  10. Linux查看负载 uptime,w ,top,iostat 命令
  11. 第一次失效_直击震撼场面!宁乡新沩丰坝建成以来第一次高水位应急演练!
  12. python标准库——math模块
  13. vi+ctags+cscope联合使用
  14. python 自然语言处理(四)____词典资源
  15. Excel 数据透视表教程大全之 03 刷新数据、添加多个字段作为值字段、值显示为总数的百分
  16. 刚学会的画丝滑的箭头ppt
  17. Sqoop基于时间列的增量数据之LastModified方式
  18. Python3网络爬虫
  19. html背景音乐音量控制,视频加背景音乐 调小背景音乐音量 这样不影响原视频声音...
  20. Python学习笔记 | opencv图像处理(一)

热门文章

  1. 机器学习极简入门课程
  2. JS数据类型-mdn
  3. Letswave 教程:脑电数据预处理与叠加平均
  4. 国内移动应用数据安全发展现状
  5. zuk android os 流量,ZUK Z1国际版:细数Cyanogen OS的几点不同
  6. 插入页眉和页脚-----------毕业设计必备攻略
  7. [UWP] ExReaderPlus 英语阅读软件
  8. 通过一个测试项目了解EF CORE
  9. 服务器修改文件名卡死,知道地址修改服务器文件名
  10. 10亿个IP地址排序、10亿年龄排序