鸿蒙都发布了,不要再浑浑噩噩,赶紧来学习计算机底层编码原理(下)

简介: 哈喽,大家好,我是指北君。曾几何时,指北君北原码反码补码绕的有点晕,网上教程也很多,详细的太难理解,容易理解的又有问题。于是乎指北君花了很长时间,肝出了这篇文章,目的是让一个小白看完都能彻底理解。我们知道日常生活中使用的数分为整数和实数,整数的小数点固定在数的最右边,可以省略不写,而实数的小数点则不固定。在计算机中只能识别和表示“0”和“1”,而无法识别小数点,因此要想使得计算机能够处理日常使用的数据,小数点的问题是不可避免的。关于计算机系统中实数的表示,在下篇文章中会讲解。本篇博客我们讲解的是整数在计算机系统中如何表示。

我们发现补码运算就很简单了,产生的进位直接舍去,而且不做多余的操作也解决了进位的问题。还有 +0 和 -0 的表示,在原码和反码都有两种形式,但是补码却只有一种:

52.png53.png54.jpg

就这样我们完美的解决了计算机中整数运算的问题。计算机的机器数采用补码的形式,我们在做算术运算的时候,既不需要额外的判断,又能得到准确的结果。

看上去本文应该结束了,然而......

请求出 127+1 的值


4、溢出


接着上面抛出的问题,127+1的值,我们现在程序中看看:


55.png

byte在计算机正好是一个字节,也就是8位二进制序列。我们发现127+1结果不是128,反而是-128,这就是结果发生了溢出。因为byte表示数的范围是-128-127,128超出了这个范围。用补码计算如下:

56.png


我们发现这个数的符号位没有发生进位,但是数值最高位发生了进位。在看前面的2-1


57.png

这个表达式符号位和数值最高位发生了进位,但是结果却是正确的。总结如下:

只有一个高位进位或者符号位进位就为溢出的规则。

溢出是每种编码在运算时都不可避免的,一般来讲结果超过字长所表示数的范围都会发生溢出。而判断机器是正常进位还是溢出的基本依据,在微型机中可用异或电路来实现上述的判断。在实际编码中解决办法也很简单,就是将结果用更大范围的编码形式接收即可。比如两个byte类型的数相加,我们用 int 来接收即可。

58.png

所以我们可以说用补码进行运算,在不考虑溢出的情况下,结果都是正确的。确实也是这样,但是......

请求出 -128 的补码?


5、剧情反转


上面的给出的问题,-128 的补码,我们首先想到去求它的原码,嗯,原码应该是 [1000 0000],不对,第一位不是符号位吗,[1000 0000]应该表示 -0。那应该怎么用原码表示 -128呢,我们发现字长为 8 的计算机用原码是无法表示的,反码也是一样。我们看看补码,用 -127- 1 的表达式结果来计算 -128 的补码:

59.png-128的补码形式为 [1000 0000],我们能通过算术表达式得到某个数的补码形式,但是为什么直接就求不出来?那么计算机自己是怎么实现的呢?

再来看这样一个问题:我们日常使用的钟表,比如现在钟表指向的是 10点钟,我要将钟表调整到 6 点钟,则有两种拨法:

①、顺时针将时针拨动 8 格

②、逆时针将时针拨动 4 (12-8) 格

由此给大家普及一个概念叫 “模”,钟表便是一个典型的模运算系统,其模数为12。

同理,对于十进制两位数,在将结果百位舍掉的情况下,50可以用60-10得到,或者60+90得到。这里的90也就是100-10得来的,那么我们就说十进制两位数运算系统的模数为100。

我们判定:两个相加等于模的数互为补数。

在模表示的范围内做减法运算,可以将“X-Y”的减法变更为“X+Y的补数“的加法,当然这里不考虑结果溢出。

上面我们举的例子都是大数减小数,如果是小数减大数会怎样?

如果是10-80,结果应该是-70。但是如果按照 10+(100-80)的说法,结果是30。很明显,30和-70不是同一个结果,而且也没有产生百位进位。那我们应该怎么办呢?

解决办法很简单,就是让这两个数相等,而且这正好解决了负数的表示方法,-70的绝对值的补数正好是30。

但是问题又来了,这里的30已经表示正数30了,现在又表示负数-70,那我们怎么知道它到底表示哪个数?

为了解决这个问题,我们给这套规则规定一个范围,原来是0~99的正数,现在既然要用部分正数来代替负数了,那就要规定一个范围来使得一个数只代表一个含义,正好一人一半,0~49这个区间就代表正数,50~99的区间就用来代表各自补数的负值,例:98就代表-2

所以0-99的编码数可以表示的数的范围为 -50-49。

我们解决了十进制两位数的减法运算,那么在字长为 8 的计算机系统中,我们又该如何呢?

8位二进制数可以表示的数为2的8次方,0-255,一共 256 个数,0也要占用一位数。所以我们说 256 是8 位二进制数的模,这和上面说的十进制两位数0-99,模为100是一样的。

我们按照前面讲的逻辑,一半的数0-127,代表其正数本身,另一半的数128-255表示其补数的负值,即-1~-128。

所以而 “X-Y”的减法 就用 “X+Y的补数” 的加法来表示,即将减法的形式转换为加法的形式了,而且计算结果还是正确的。

注意:这里还是一样,不考虑结果的溢出,也就是计算值和结算结果都必须在-128~127之间,一旦超过这个范围,结果就不准了,这也是程序员日常编码说的int=int+int,如果结果大于int类型表示的范围,那得出来的结果肯定不准。

由此我们得出来的结论是:

计算机编码其实并没有什么所谓的符号位,但是由于计算机没有减法运算,为了将负数变为某个可以运算的编码来进行加法运算,补码产生了。这也间接说明了正数的补码是不变的,而负数的解决办法是首位不变,其余的取反再加1。

我们上面说的补码怎么得来的,就是 模-绝对值 。

所以这个时候我说让你求 -128的补码,你马上就会知

256 - |-128|=128  而128的二进制补码是不是就是 [1 0 0 0 0 0 0 0]

让你求 -1 的补码,你马上就会知

256 - |-1| = 255,其255的二进制补码形式就是[1111 1111]

注意:关于这样求补码的具体数学证明,请参考《计算机组成与系统结构》。


60.png

6、总结

指北君画重点:本篇文章你可以直接从第 5 点开始看,忘掉计算机编码的什么首位符号位,忘掉计算机补码是由原码取反加1,回归简单直白的理解。计算机是机器,硬件能理解的只有高低电平,也就是0或者1。它知道什么是符号位吗?这些规则只不过是为了更好的完成减法运算所yy出来的。

我是指北君,操千曲而后晓声,观千剑而后识器。感谢各位人才的:点赞、收藏和评论,我们下期更精彩!




相关文章
|
1月前
|
存储 JavaScript 前端开发
“纯血鸿蒙”要来了,赶紧入手学习吧
1月18日,华为宣布HarmonyOSNEXT鸿蒙星河版面向开发者开放申请,这一最新版本的鸿蒙系统也被喻为“纯血鸿蒙”。赶紧入手学习吧
111 1
|
3月前
|
存储 前端开发 IDE
【华为鸿蒙系统学习】- 如何利用鸿蒙系统进行App项目开发|自学篇
【华为鸿蒙系统学习】- 如何利用鸿蒙系统进行App项目开发|自学篇
99 0
|
3月前
|
数据管理 API 调度
【华为鸿蒙系统学习】- HarmonyOS4.0开发|自学篇
【华为鸿蒙系统学习】- HarmonyOS4.0开发|自学篇
204 0
|
8月前
|
开发框架
HarmonyOS学习路之方舟开发框架—学习ArkTS语言(状态管理 四)
被@Observed装饰的类,可以被观察到属性的变化;子组件中@ObjectLink装饰器装饰的状态变量用于接收@Observed装饰的类的实例,和父组件中对应的状态变量建立双向数据绑定。这个实例可以是数组中的被@Observed装饰的项,或者是class object中是属性,这个属性同样也需要被@Observed装饰。单独使用@Observed是没有任何作用的,需要搭配@ObjectLink或者@Prop使用。
|
5月前
|
安全 前端开发 Android开发
鸿蒙开发|鸿蒙系统的介绍(为什么要学习鸿蒙开发|鸿蒙系统的官方定义|鸿蒙和安卓、ios的对比)
鸿蒙开发学习是一项探索性的工作,旨在开发一个全场景分布式操作系统,覆盖所有设备,让消费者能够更方便、更直观地使用各种设备。
295 6
鸿蒙开发|鸿蒙系统的介绍(为什么要学习鸿蒙开发|鸿蒙系统的官方定义|鸿蒙和安卓、ios的对比)
|
5月前
|
文字识别 数据管理 API
双十一钜惠!三门不可多得的HarmonyOS学习教程
今年双十一,各大商城优惠不断。这里介绍三门不可多得的HarmonyOS学习教程,都有非常大的折扣优惠。
65 0
|
5月前
|
数据可视化 Java 程序员
通过实例学习鸿蒙静态库的创建与使用
通过实例学习鸿蒙静态库的创建与使用
|
8月前
|
存储 开发框架 JavaScript
HarmonyOS学习路之方舟开发框架—学习ArkTS语言(状态管理 五)
LocalStorage是ArkTS为构建页面级别状态变量提供存储的内存内“数据库”。应用程序可以创建多个LocalStorage实例,LocalStorage实例可以在页面内共享,也可以通过GetShared接口,获取在UIAbility里创建的GetShared,实现跨页面、UIAbility内共享。组件树的根节点,即被@Entry装饰的@Component,可以被分配一个LocalStorage实例,此组件的所有子组件实例将自动获得对该LocalStorage实例的访问权限;
|
8月前
|
缓存 API 开发者
HarmonyOS学习路之开发篇——Service Ability
基于Service模板的Ability(以下简称“Service”)主要用于后台运行任务(如执行音乐播放、文件下载等),但不提供用户交互界面。Service可由其他应用或Ability启动,即使用户切换到其他应用,Service仍将在后台继续运行。
|
8月前
|
开发者
HarmonyOS学习路之开发篇——Page Ability
Page与AbilitySlice Page模板(以下简称“Page”)是FA唯一支持的模板,用于提供与用户交互的能力。一个Page可以由一个或多个AbilitySlice构成,AbilitySlice是指应用的单个页面及其控制逻辑的总和。