首页 > 系统相关 >整数在内存中的天才存储方案

整数在内存中的天才存储方案

时间:2023-06-02 21:11:19浏览次数:48  
标签:存储 0000 运算 18 补码 1111 天才 内存 反码

加法和减法是计算机中最基本的运算,计算机时时刻刻都离不开它们,所以它们由硬件直接支持。为了提高加减法的运算效率,硬件电路要设计得尽量简单。对于有符号数,内存要区分符号位和数值位,对于人脑来说,很容易辨别,但是对于计算机来说,就要设计专门的电路:有符号加、减,这无疑增加了硬件的复杂性,增加了计算的时间。要是能把符号位和数值位等同起来,让它们一起参与运算,不再加以区分,这样硬件电路就变得简单了。

另外,加法和减法也可以合并为一种运算,就是加法运算,因为减去一个数相当于加上这个数的相反数,例如,5 - 3 等价于 5 + (-3),10 - (-9) 等价于 10 + 9。如果能够实现上面的两个目标,那么只要设计一种简单的、不用区分符号位和数值位的加法电路,就能同时实现加法和减法运算,并且非常高效。实际上,这两个目标都已经实现了,真正的计算机硬件电路就是如此简单。

然而,简化硬件电路是有代价的,这个代价就是有符号数在存储和读取时都要进行转化——为了计算相反数,必然需要转化。那么,这个转换过程究竟是怎样的呢?接下来我们就详细地讲解一下。

首先,需要弄清下面几个概念:原码、反码、补码。参考:补码、原码、反码 - 武装部 - 博客园 (cnblogs.com)

补码到底是如何简化硬件电路的

假设 6 和 18 都是 short 类型的,现在我们要计算 6 - 18 的结果,根据运算规则,它等价于 6 + (-18)。
如果采用原码计算,那么运算过程为:

6 - 18 = 6 + (-18)
= [0000 0000 0000 0110] + [1000 0000 0001 0010]
= [1000 0000 0001 1000]
= -24

直接用原码表示整数,让符号位也参与运算,对于类似上面的减法来说,结果显然是不正确的。

于是就考虑用反码代替原码参与计算行不行?下面就演示了反码运算的过程:

6 - 18 = 6 + (-18)
= [0000 0000 0000 0110] + [1111 1111 1110 1101]
= [1111 1111 1111 0011]
= [1000 0000 0000 1100]
= -12

这样一来,计算结果就正确了。

然而,若是将减数和被减数交换下位置:18 - 6

18 - 6 = 18 + (-6)
= [0000 0000 0001 0010] + [1111 1111 1111 1001]
= [1 0000 0000 0000 1011]
= [0000 0000 0000 1011]
= [0000 0000 0000 1011]
= 11

按照反码计算的结果是 11,而真实的结果应该是 12 才对,它们相差了 1。

蓝色的 1 是加法运算过程中的进位,它溢出了,内存容纳不了了,所以直接截掉。

6 - 18 的结果正确,18 - 6 的结果就不正确,相差 1。后来发现这么个规律:按照反码计算,小数减大数正确;大数减小数就不对了,始终相差1。好奇的话可以自己去试一试,如:5 - 13 和 13 - 5 。

于是开始设计补码,规则很简单就是通过打补丁来纠正差的这个1。补码 = 反码 + 1。

下面演示了按照补码计算的过程:

6 - 18 = 6 + (-18)
= [0000 0000 0000 0110] + [1111 1111 1110 1110]
= [1111 1111 1111 0100]
=  [1111 1111 1111 0011]
= [1000 0000 0000 1100]
= -12
## 这里由于符号位是负数,所以在补码转换回反码的过程中,要进行减一操作;一加一减,等于没变。
18 - 6 = 18 + (-6)
= [0000 0000 0001 0010] + [1111 1111 1111 1010]
= [1 0000 0000 0000 1100]
= [0000 0000 0000 1100]
= [0000 0000 0000 1100]
= [0000 0000 0000 1100]
= 12
## 这里由于符号位是正数,故补码/反码/原码都是一个,因此在反码转换补码时添加的那个计算完毕就被保留下来;于是便把大数减小数时差的那个1给补了上来。神不神奇?

在计算机内存中,整数一律采用补码的形式来存储,在读取整数时则进行一个由补到原的转换即可。这种天才般的设计一举达成了本文开头提到的两个目标,简化了硬件电路。

标签:存储,0000,运算,18,补码,1111,天才,内存,反码
From: https://www.cnblogs.com/mikewzp/p/17452907.html

相关文章

  • 图的存储
    1.邻接矩阵法包括一个一维数组用于存储顶点信息(称为顶点表),一个二维数组用于存储各顶点之间的链接关系(邻接矩阵)不同情况下的邻接矩阵:首先,对于顶点数为n的任何图,其邻接矩阵肯定是n乘n的有向图:A到B和B到A是两条不同的边,所以有向图的邻接矩阵不一定为对称矩阵无向图:无向图一定是......
  • 存储接口测试简介与测试方法
    本文分享自天翼云开发者社区《存储接口测试简介与测试方法》,作者:杨****鹏 1、接口测试的概念接口测试原理是通过测试程序模拟客户端向服务器发送请求报文,服务端接收报文并处理后再把应答报文发送回客户端,客户端接收应答报文的过程测试接口目的就是保证接口调用的正确性和稳......
  • Android通过 SharedPreference 实现用户名与密码的存储与调用
    注:Android实验课(一)的内容一、实验原理1.1实验目标编程实现用户名与密码的存储与调用。1.2实验要求设计用户登录界面、登录成功界面、用户注册界面,用户注册时,将其用户名、密码保存到SharedPreference中,登录时输入用户名、密码,读取SharedPreference,读取不到该用户名提示用户不存在,用......
  • Java的内存回收
     Java的内存回收http://blog.sina.com.cn/s/blog_4c925dca0100ilk0.html ......
  • 【C语言】动态内存管理函数的 深度解析 #是不是对数组不能变大变小而烦恼呢?学会动态内
    前言动态内存管理函数可以说很好用,但是有些小危险。所谓动态内存分配,就是指在程序执行的过程中动态地分配或者回收存储空间的分配内存的方法。动态内存分配不像数组等静态内存分配方法那样需要预先分配存储空间,而是由系统根据程序的需要即时分配,且分配的大小就是程序要求......
  • lucene底层数据结构——FST,针对field使用列存储,delta encode压缩doc ids数组,LZ4压缩算
    参考:http://www.slideshare.net/lucenerevolution/what-is-inaluceneagrandfinalhttp://www.slideshare.net/jpountz/how-does-lucene-store-your-data摘录一些重要的:看一下Lucene的倒排索引是怎么构成的。我们来看一个实际的例子,假设有如下的数据: docid年龄性别118女220女318男 ......
  • 表存储时间序列数据存储体系结构
    随着近年来物联网(IoT)的快速发展,时间序列数据出现了爆炸式增长。根据过去两年DB-Engines数据库类型的增长趋势,时间序列数据库的增长是巨大的。这些大型开源时间序列数据库的实现是不同的,并且它们都不是完美的。但是,这些数据库的优点可以结合起来实现完美的时间序列数据库。阿里云表......
  • linux服务器cache占用内存过高导致内存不足
    问题描述linux服务器内存不足触发监控报警。K8S在创建pod之后启动失败,日志报错如下: 问题检查登录服务器发现服务器8G内存正在被使用的和空闲内存大概4G,还有大概4G被cache占用   这个cache占用了大量内存,那么这个cache时干什么用的?Linux中的缓存称为PageCache。它......
  • 可执行文件的内存模型,变量的值是放在栈上还是放在堆上
    作者:@古明地盆喜欢这篇文章的话,就点个关注吧,或者关注一下我的公众号也可以,会持续分享高质量Python文章,以及其它相关内容。:点击查看公众号楔子作为开发者,我们一辈子会经历很多工具、框架和语言,但是这些东西无论怎么变,底层逻辑都是不变的。所以今天我们就回头重新思考编程中那些耳......
  • Java进行内存泄露​ GC 分析都有哪些常用好用的工具
    使用Java语言开发应用程序,虽然JVM帮我们进行了GC收集、清除工作;但是使用不当的话,还是会导致某些对象常驻堆空间无法给垃圾收集器清除,导致内存泄露、内存溢出等情况,今天盘点一下在项目中进行内存泄露分析和GC分析的一些常用、好用的工具。0x01:JDK自带工具在处理内存泄露方面JDK本身......