计算机组成原理:如何计算数据(数学理论)(七-1) 这是计算机组成原理系列文章的第7-1篇,欢迎持续!
:游戏服务器开发 上一篇罗罗的游戏:计算机组成原理:如何读取数据(地址选择)(六) 前言 在学习如何计算数据之前,我们先来回顾一下我们拥有的工具:编码器(键盘)+ 存储器(内存&硬盘)(当然还有地址译码器,但可以把它算入存储器中) 再重复一下我们计算机的第一原则:输入数据 + 计算数据 + 输出数据 编码器(键盘)帮助我们把人类容易理解的信息(字母,数字,文字)转化为二进制数据传给计算机,存储器(内存&硬盘)帮助我们永久地记录这些二进制数据,在需要使用数据的时候,能够自动快速地提取这些数据给CPU进行使用,这就是我们现在所做的一切:实现数据输入(键盘)+ 优化数据输入(内存&硬盘提前存储好数据) 现在数据准备好了,接下来就应该考虑如何计算这些数据,也就是来到我们的第二部分:计算数据。正如你做菜时,当准备好食材,配料,煤气,锅碗后,是时候准备动手做菜了!! 计算机处理数据方式与人类有很大的不同,这是计算机的第二个原则。这在第三章《逻辑和逻辑门》当中说过,现在是用到它的时候了,因为计算机的计算方式和人类做计算的方式是完全不一样的,计算机有自己的处理方式,计算机用二进制,能把数据运算的又快又准确,因此我们需要尊重计算机,要以计算机的思维方式,去处理和计算数据,而不是用人类的思维 注意:现在我们现在处于计算数据这个部分了 如何实现加减法 人类加法 人类在计算数字的时候,是非常容易的,例如: 因为我们知道需要每一位进行相加,如果产生进位就往前一位加1,最终得到231的结果人类减法 我们也会减法,每个位进行相减,如果不够数,就向前一位借1,最终得到95的结果 如果前一位也不能借位了,那就增加负号,表示数不够了 而计算机的加减法在这一点上的机制是一样的,只是形式转化为二进制了而已计算机加法 计算机加法也是0+1=1,1+0=1,0+0=0,1+1 = 0(进位1)计算机减法 计算机减法也是1-1=0,1-0 = 1,0-0=0,0-1 = 1(借位1,没得借就是-1) 计算机加减法的实现最后还是得依靠物理的电路,也就是我们第一层抽象的逻辑门来实现的,并且加法的运算规则:0+1=1,1+0=1,0+0=0,1+1 = 0(进位1),是可以通过布尔代数,逻辑,逻辑门来表达和实现的 (在下一篇文章,半加器与全加器中会详细介绍物理电路的实现) 也就是说:计算机可以很容易的通过电路实现加法,但是却没有办法计算减法,它没办法计算向前借一位的操作,甚至如何标记这个数是正数还是负数都困难,因为计算机不认识人类的[ + ] 和[ – ]符号,它只知道0和1的符号 此时我们需要解决问题:如何在二进制数据中区分正数和负数?如何把减法变为加法?只要能区分正数和负数,并把减法转换为加法,那么计算机就算实现了加法减法的计算了!! 原码 对于人类来说,区分正数和负数通过符号 [ + ] 和 符号 [ – ] 来区分 对于二进制数来说,计算机需要有个标记来区分正数还是负数 把二进制的首位当作标记符,[ 0 ]表示正数,[ 1 ]表示负数 完美解决二进制表示正负数的问题,不需要用到符号 [ + ] 和 符号 [ – ] 唯一的缺点就是第一位不能用来存储值了,因为第一位被占用作为正负的标记位 让我们来计算一下1+2=3 得到十进制:3,结果正确,非常好 反码 对于人类来说,做【加法3 + 5】 和 【减法3 – 5】是非常容易的 但根据前面说的:计算机只会加法,我们该如何把减法转换为加法? 把减法变为加法是小学的知识:3 – 5 = 3 + (-5),并让符号位参与运算 说不定可以完美解决计算机只会加法的问题 计算一下:3 + (-5) = -2 得到十进制:-8,结果错误,出问题了 看来直接用原码进行加法是不行的,因为原码的符号位参与了运算 此时Niubility的数学家规定:用反码进行计算 正数的反码为本身 负数的反码为除符号位不变,其余位取反 3的原码为: 0 0000011 -5的原码为:1 0000101 -5的反码为:1 用反码,计算一下:3 + (-5) = -2 得到结果:1 因为1 的首位为1,表示为负数,反码需要转化为原码 把1 除符号位取反得原码:1 0000010 得到十进制:-2 反码完美解决原码进行加法时错误的问题,并且符号位也参与了运算 很棒!现在,我们实现了计算机的加法和减法的计算,进展顺利!! +0 和 -0 的问题 但是我们再来看一种特殊情况: 正数+1的原码为:0 0000001 负数-1的原码为: 1 0000001 用反码,计算一下:1 + (-1) = 0 得到结果:1 因为1 的首位为1,表示为负数,反码需要转化为原码 把1 除符号位取反得原码:1 0000000 得到十进制:-0 我们十进制数0成为了负数! 但0是没有正负数区分的!还是出现了错误! 我们发现用反码计算,真值的部分是正确的,问题出现在符号位 我们可以得知: 0 0000000[ + 0 ] 和 1 0000000[ – 0 ] ,都表示为0,问题很大 补码 此时Niubility的数学家再次规定:用补码进行计算 正数的补码为本身 负数的补码为反码再加上1 3的补码为: 0 0000011 -5的原码为:1 0000101 -5的反码为:1 -5的补码为:1 用补码,计算一下:3 + (-5) = -2 得到结果:1 因为1 的首位为1,表示为负数,补码需要转化为原码 把1 除符号位取反,得反码:1 0000001;反码再加1得到原码:1 0000010 得到十进制:-2, 结果正确,Perfect! 用补码,计算一下:1 + (-1) = 0 得到结果:0 0000000 结果的首位为0,表示为正数,不需要再取反,则原码就为:0 0000000 得到十进制:0,结果正确,好像可以了! 最后用[ 0 0000000 ]来表示0,简直Nice! 0 和 -128 的问题 我们来看最后一种特殊情况: 用补码,计算一下:-1 + (-127) = -128 得到结果:1 0000000 因为1 0000000的首位为1,表示为负数,补码需要转化为原码 把1 0000000除符号位取反,得反码:1 ;反码再加1得到原码:0 0000000 得到十进制:0,结果错误! 明明0 0000000已经被表示为0了!!现在又要表示-128!! 我们发现实际上是以前的-0的补码就是1 0000000,现在用来表示-128,所以-128并没有原码和反码表示,只要补码是[1000 0000],其十进制数值就为-128 最后规定:用[ 1 0000000 ]来表示-128,也就不存在-0的说法了 我们甚至可以写程序打印一下128和-128的每个bit的情况 会发现128和-128的是一样的 128 和 -128 的问题 此时新的问题出现了,你可能会问计算机存储128和-128的数值是一样的,那是如何区分这2个数的呢? 答案是根据具体情况决定。其实正如计算机在存储数据时候,并不会在意这个数是正数(首位是0)还是负数(首位是1),它只负责存储数据,至于这个数据代表的含义,它不关心 对于这个数据的解释,也是根据我们的需要来实施的: 如果你把它当做是负数,那么就是代表-128;如果你把它当做是正数,那么就是代表128 那我们在对比128和-128的时候,会出现这2个数相同的情况吗? 答案是不会。因为在8位的情况下,对于有符号数而言,128是不能被表达的,已经超出了8位有符号数能表达的有效范围 但是128依然能被8位的无符号数表达,所以此时无符号128和有符号-128进行大小比较时,会进行类型转换 所以有C语言的知识:有符号数与无符号数比较,有符号数会转换成无符号数来进行比较 我们会根据计算机最终得出的结果,来分情况确定这个数是表示正数还是负数。这就是我们在学习C语言时候,区分有符号和无符号的原因,其实在计算中存储的数据都是一样的,例如存储的都是一样的数据1 0001011 1 0001011,假如你把它当作无符号数,那首位就表示数值,值为139,没问题 1 0001011,假如你把它当作有符号数,那首位就表示符号位,值为-11,也没问题 甚至你拿2个数去运算,符号位也可以参加运算,得出的结果依然没问题! 这方面的知识在七-3的文章中我在详细说明吧! 最后解释一下:-128的补码为什么是1000 0000? 128为正数,正数的补码是其本身 那-128的补码为什么是1000 0000?给我个理由! 我们知道,8位二进制的补码组合序列有256个,为0 ~ 255范围原码形式: 0000 0000 – 0111 1111 0 ~ +127(原码) 1000 0000 用来干啥好呢? 1000 0001 – 1111 1111 -1 ~ -127(原码)补码形式: 0000 0000 – 0111 1111 0 ~ +127(补码) 1000 0000 用来干啥好呢? 1111 1111 – 1000 0001 -1 ~ -127(补码)再看看这个规律表原码补码值0111 1111+ 1110+126… …补码不断-1… …0000 00000000 000001000 00011111 1111-11000 00 1110-21000 00 1101-3… …补码不断-1… …1111 0001-127无法表达1000 0000-128 于是就有了规定1000 0000定为-128的补码 求补码最全的方式 如何计算负数的补码? 虽然可以直接规定:-128的补码是1000 0000 但是根据上面的分析,我们在求得一个负数的补码时,是通过统一的计算方式来的即: 首位为1,表示为负数,需要转化为补码;符号位不变,其他位全部取反,得反码,反码再加1得到补码 首位为0,表示为正数,不需要转化,本身就是补码 -128也是负数,那我们应该如何统一计算负数的补码呢? 总不能-128就搞个特例吧?在数学理论里面可以规定说-128的补码就是,但是我们实际还是需要电路去完成的,单独弄个-128的补码就非常特殊,电路上不好实现 其实,求补码并不是教科书上说的: 正数的补码是它本身 负数的补码是除符号位取反,得反码,反码再加1 它只适用于不是-128的大部分数负数最统一的方式求补方式是: 第一:将负数取绝对值,再用二进制表示出这个绝对值 (不用管符号位!不是符号位保持不变!就是只用负数的绝对值,根本没用到符号位) 第二:对二进制数进行取反加1操作就得到负数的补码(也就是求补操作) 以下是例子: -128绝对值是128 128的二进制表示为:1000 0000 取反 (不用管符号位,全部取反)得到:0111 1111 再加1 ,得到:1000 0000 这就是-128的补码 这种办法算出的结果符合“规定值” -1绝对值是1 1的二进制表示为:0000 0001 取反 (不用管符号位,全部取反),得到:1111 1110 再加1,得到:1111 1111 -127绝对值是127 127的二进制表示为:0111 1111 取反 (不用管符号位,全部取反),得到:1000 0000 加1,得到:1000 0001 由上面三个例子可以看出,求补码最全的方式是: 正数的补码是它自身,负数的补码为绝对值取反加1 注意:补码和求补是两回事,补码表示的是一种存储数据的方法,求补是一种运算,千万不能弄混 补码解决的问题 如果用原码或反码来表示 8位最多能表示:[ -127, 127 ] 但会造成计算机加法问题,+0 和 -0的问题如果用补码来表示 8位最多能表示:[ -128, 127 ] 完美解决加减法,+0 和 -0的问题 无符号8位也能表示256位所以补码解决的问题如下 补码解决了计算机减法转化为加法的难题,使得减去一个数,变为加上那个数的补码 补码解决了+0和-0的问题 补码解决了符号位不能参与运算的问题,这非常关键 补码也使得我们多了1位来表示-128 总结 当然以上的原码补码的原理是基于一种叫模的方法推导的,这个是数学家的事 我们需要充分相信那群Niubility的数学家,那群家伙厉害的很! 因此我们只需要记住以下规则就行: 正数的原码,反码,补码都是它本身,不用变 负数的反码就是除首位的符号位之外,所有值取反 负数的补码为绝对值取反加1 现在,我们很好地解决了计算机不能做减法的问题,我们成功地把计算机的减法转化为了加法!以后计算机再也不用管什么正号,负号,借位,进位的东西了,一股脑地根据上面所说的加法规则:0+1=1,1+0=1,0+0=0,1+1 = 0计算即可(注意这里没有了进位的描述) 另外需要一点说明的是:计算机数据所有的存储和计算都是根据补码的形式来的! 毕竟计算机有自己的处理方式,计算机的处理方式是和人类不一样的,我们需要尊重计算机,要以计算机的思维方式,去处理和计算数据,我们只需要记住就行,不用觉得奇怪和麻烦 如果你在上一章《如何读取数据》中有亲自去写C语言的程序,尝试打印一个整数的逻辑顺序和存储顺序是怎么样的,你就会发现这个规则!当然,这个程序我是自己写过了的,有机会再整理一下发出来,可以加深理解,并且验证上面说的理论是正确的 最后,在程序的世界里,数据的类型,大小,表示范围也是非常重要的,如果处理不当会造成很严重的漏洞或者使程序运行崩溃。基于C语言的知识,我做了一个思维导图,里面大概总结了一些知识点,如下图,有机会的话会详细地写篇文章来记录,但是我们可以根据这个图大概知道数据的表示原理和要注意的点在那里
如果这篇文章对你有帮助,就点个赞,反正你们收藏了也不看的 上一篇罗罗的游戏:计算机组成原理:如何读取数据(地址选择)(六) 下一篇罗罗的游戏:计算机组成原理:如何计算数据(具体实现)(七-2) :游戏服务器开发
2024最新激活全家桶教程,稳定运行到2099年,请移步至置顶文章:https://sigusoft.com/99576.html
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。 文章由激活谷谷主-小谷整理,转载请注明出处:https://sigusoft.com/21792.html