技术标签: 计算机组成原理
原码是有符号定点数的一种编码方式,规定了最高位为1代表负数,为0代表正数,数值位是数据的二进制真值。具体来说,又分为原码整数与原码小数,其中,原码整数的小数点默认在最低位的右边(隐式存在),原码小数的小数点默认在符号位的右边(隐式存在),此外,原码整数是在高位补0,而小数是在低位补0。
例如,-3的原码(4bit)为1011,-0.75的原码(4bit)为1.110。要注意的是,计算机内储存的二进制数是不存小数点的,小数点都是隐式存在的,书面表达时会标注小数点是为了方便理解。
然而,虽然原码规定了正数与负数,整数与小数的储存方法,但我们无法统一的用加法器对它们进行运算,例如(均用加法器):
综上,可见,用加法器是无法实现对负数原码进行计算的。那么,是否用减法器就能解决问题了呢,我简单查阅了一下资料。
补充:为什么没有减法器?
以下引用自百度百科:
ALU必须与数字电路的其他部分使用同样的格式来进行数字处理。对现代处理器而言,数值一律使用二进制补码表示。早期的计算机曾使用过很多种数字系统,包括反码、符号数值码,甚至是十进制码,每一位用十个管子。 以上这每一种数字系统所对应的ALU都有不同的设计,而这也影响了当前对二进制补码的优先选择,因为二进制补码能简化ALU加法和减法的运算。 一个简单的能进行与或非和加运算的2位ALU。
可见,当下用补码作为数值的二进制储存方法,并用加法器来实现减法运算,不是一蹴而就的,也是慢慢发展而来,最终由于这种方法实现较为简单而被采用。
又简单搜了一下,更精简的算术逻辑单元似乎可以使cpu主频更高,但有待考证,先写在这里。
通过上面的分析,已知当前cpu里没有减法电路了,那么如何用加法器来实现减法呢?先说结论:用补码。但在介绍反码和补码之前,想要先简单介绍一下模运算。
想象一下,在角度里,如果想要表示第一象限里的30°,则既可以描述为+30°,又可以描述为-330°,且任何一个度数加上或减去360°都可以认为角度没有变化(只是转了一圈)。
在上面的例子里,可以称30°与-330°进行模360°运算时,余数是一样的,均为30,因此,可以理解为,30和-330在运算时是等价的。即x-330,与x+30是等价的。通过这样的方式,就可以把减法转换为加法进行运算。
在二进制数里,由于位数有限,且溢出的部分会被丢弃,因此,也导致了这样的现象,以大小为4bit的数为例,它可以存的最大值是24-1即15,而15+1时,储存的二进制数就变回了0,(因为最高位的1超出了4位,被溢出截断了),它就像24小时或者360°一样,也有一个范围限制。
因此,同样可以通过对这个范围进行模运算,求出与负值等价的正值,来将减法转变为加法。例如,3-1=2(0010)可以改写为3+15=18(10010,截断最高位的1后也是0010),而-1模24的余数与15模24的余数是相等的,都是15,因此,它们可以被视为等价。
其实,讲的再通俗易懂一点,任何一个数加上10000(二进制),都不会改变它的大小,因为一个限定为4位的二进制数会把10000视作0,就像,任何一个角度加上360度,它的最终朝向都不会有变化一样。
因此,一个包含负数的表达式,后面无论加上多少个10000,或者360°,大小都不会有变化,基于该显而易见的理论,就可以更简单的理解为什么3-1=3+15,因为3-1+24=3-1+0=3-1。
而要计算与一个负数等价的正数,也可以简单的将这个负数与最大范围相加,直到出现正数为止,例如-330°+360°=30,因此,30°与-330°等价。
理论推导和数学定义就不写了,贴一个视频在这里,感兴趣的可以自己看下:计组网课p15,主要是简单理解下通过模运算是将减法转为加法的根基。
上一小节分析了如何将减法转为加法,还是以4位二进制数为例,-1的原码是1001,与-1等价的正数是-1+24=15(1111),因此,如果能够通过一种方式,将负值的原码转为等价正值的原码,那就可以用加法器计算减法了,而这个所谓的等价正值的原码,就是补码。
分析一下如何得到补码,还是以4位为例:
设x为一个负数的原码,最大范围是24,补码为y,则x+24=y,这里只加24即可,是默认了x<24,如果它超过了这个值,那也无法被只能容纳4位的数据类型储存。
已知y为所求,x+24=y,y-x=24=10000=1111+1,1111=y-1+(-x),设y-1=z,则可整理出表达式为:z+(-x)=1111,其中,由于x为负数,因此-x为正数,即在x的原码基础上,将最高位改为0。
显而易见,z的求法,是将-x的原码按位取反,例如,0110+1001=1111,0110和1001是按位取反的关系,又已知-x跟x在原码上的区别只是最高位,因此,也可以说,z=x除最高位外按位取反,而z就是反码。
又已知z=y-1,因此,y=z+1,即补码等于反码加1。
此外,正数的反码和补码跟原码都是一样的,因为首先,与它等价的其余正数都超过4位能容纳的最大值了,其次,补码本身就是针对负数的。
综上所述,补码的出现,是为了将减法统一为加法,而补码的计算方法是基于模运算的理论,此外,反码是计算过程中的一个中间值,一般不直接参与计算。
移码的出现,主要是为了在硬件层面方便对比两个数的大小,它常见于储存浮点数的阶数。
简单来说,在整数相加的过程中,只要直接计算即可,但是浮点数相加的过程中,有一个对比阶数的过程,用10进制举例,3.2x1012+1.5x1010=3.2x1012+0.15x1012=(3.2+0.15)x1012,最后的阶数是12,即12和10中的较大值,可见,在浮点数计算过程中,有一个阶数对比的步骤。
补:为什么不统一为阶数的较小值呢,因为浮点数中数值位是一个定点小数,小数点永恒定在开头,如果统一为较小值,就变成了(320+1.5)x1010,数值位的小数点就不是永远定在开头了,而是会变化,显然不方便机器层面的运算。
综上,得到优化目标为:加速阶数的大小对比。
已知数值都是用补码储存的,从小到大列出4位二进制数的补码如下:
真值 | 补码 | 移码 |
---|---|---|
-8 | 1000 | 0000 |
-7 | 1001 | 0001 |
-6 | 1010 | 0010 |
-5 | 1011 | 0011 |
-4 | 1100 | 0100 |
-3 | 1101 | 0101 |
-2 | 1110 | 0110 |
-1 | 1111 | 0111 |
0 | 0000 | 1000 |
1 | 0001 | 1001 |
2 | 0010 | 1010 |
3 | 0011 | 1011 |
4 | 0100 | 1100 |
5 | 0101 | 1101 |
6 | 0110 | 1110 |
7 | 0111 | 1111 |
观察一下就能发现,如果按照01234567,-8,-7,-6…-1这个顺序来看补码,刚好是将补码从小到大的排序!因此,只要将补码稍稍“移动”一下,就能得到可以很简单的对比大小的移码!
补:为啥说移码对比起来简单呢,举个例子,0111和1010比大小,从左到右遍历,先出现1的就更大,如果同时出现了1,那么下一个先出现1的就更大。所以其实移码就是,把补码移动一下,变成n位二进制数从小到大排列而已。而这个“移动”的过程,需要加上一个值,这个值就叫偏置值。
上述这种,移码的0从n位二进制数的最小值开始的情况,的计算方法是补码+2n-1,分析一下,要从上表的补码变成移码,就像捏着补码的0000,往上提8(2n-1,负数的最大值的绝对值)个格子,往上提1个格子的话,真值0对应的移码会变成0001,即0000+1,因此,提2n-1个格子,对应的计算方法就是补码+2n-1了。
而补码=真值+2n,因此,移码=补码+2n-1=真值+2n+2n-1=(真值+2n-1)+2n,也就是说,偏置值2n-1直接作用于真值也是可以的,此外,由于-2n-1是n位二进制数的最小值,因此真值一定≤2n-1,(真值+2n-1)一定≥0,因此,+2n就等于+0(正数的补码等于原码)。
因此,综上所述,如果手动计算移码的话,把真值+偏置值的结果直接转成二进制原码就行了。
然而不一定所有移码的0都是从n位二进制数的最小值开始,如float类型里阶数的移码形式,0是从-127开始的,它把-128和-127这两个状态单独扣出来有特殊用处,这就是按照不同需求,设置不同的移码实现方式了。
补码的出现,是为了用加法器实现减法运算,而移码的出现,是为了使得两个有符号整数对比的更快速,而现在常用的计算这两个码的方法,如补码是原码除最高位外取反+1,移码是真值+偏置值,这是基于理论推导后得出的等价算法,不那么好理解,但算起来很简单。
概述radix tree内核函数初始化radix tree复制 1234567 #include <linux/radix-tree.h>RADIX_TREE(name, gfp_mask); /* Declare and initialize */struct radix_tree_root my_tree;INIT_RADIX_TREE(my_tree, gfp_mask); 第一种方式以一种给定的名称初
radix在Character.MIN_RADIX与Character.MAX_RADIX之间是指在 2~~36之间;部分源码:public finalclass Character implements java.io.Serializable, Comparable&lt;Character&gt; { public static final int MIN_RADIX = 2;...
1:Hive的概念Hive是基于Hadoop的一个数据仓库工具。可以将结构化的数据文件映射为一张数据库表,并提供类SQL查询功能。本质是将SQL转换为MapReduce的任务进行运算,底层由HDFS来提供数据的存储支持。Hive可以理解为一个将SQL转换为MapReduce任务的工具,甚至更进一步可以说hive就是一个MapReduce的客户端。2:Hive与数据库的区别Hive 具有 SQL 数据库的外表,但应用场景完全不同Hive 只适合用来做海量离线数据统计分析,.
在Anacoda Prompt 中用 pip install jieba 出现了以下问题:最后一行显示,超时了(原来是网速不行啊。)试了用清华镜像网站下载https://pypi.tuna.tsinghua.edu.cn/simple/,成功了。安装在我的路径:D:\Anaconda3\Lib\site-packages后打开 Pycharm 想试试 jieba 库,提示我没导入 j...
1. Could not find com.android.tools.build:aapt2:3.3.2-5309881build失败,报错解决办法:在项目下的build.gradle repositories下加入 google()buildscript { repositories { jcenter() google() } ...
一台测试的单机环境需要将10.2.0.1升级到10.2.0.5,升级步骤比较简单,在此简单记录下。0. 停掉服务进入服务管理(services.msc)将oracle的DBConsole、iSQL*Plus、Server和Listener全部停掉1. 升级DBSOFTWARE解压升级包,打开升级安装程序,选择已有的安装ORACLE_HOME和安装路径,一路next。安装完成后打开L
毕业论文套了一份latex模板,但是格式采用硕士规范,硬生生调成了又丑又蠢的本科生规范。(除了封面)记录一下单双面的调整,正文之前是单面打印,左间距3cm,右间距2cm,正文开始是双面打印,单双面交替,装订部分3cm,外围2cm。想要实现oneside到twoside的切换,试了setboolean的方法,并不能实现,后来用\newgeometry实现了。开头文档属性是设为了oneside boo...
引用org.springframework.beans.BeanUtils类提供的方法copyProperties(Object source, Object target, String... ignoreProperties) 用于对象拷贝,spring 和 Apache都提供了相应的工具类方法,BeanUtils.copyPropertiespackage com.mixislink...
台式机下的系统环境下可以跑uuv笔记本下的虚拟环境下可以跑uuv目前遇到的问题是,台式机下的虚拟环境跑不了uuv接下来好好debug终端1运行source activate py27cd ~/catkin_wssource devel/setup.bashroslaunch uuv_gazebo_worlds ocean_waves.launch没有问题终端2运行source...
实例中有用到颜色的时候,只讲了部分颜色的代码,读者可以去看xlwt模块下的style.py查看更多颜色;实例4中有用到线条的样式,读者可以去看xlwt模块下的Formatting.py中的Borders类。worksheet.write(0, 0, '小红', font_style)worksheet.write(0, 0, '小名', style)#往表中写内容,第一个参数 行,第二个参数列,第三个参数内容。# 设置字体为红色,这里不能使用16进制表示颜色的方法去设置。抽空又来写一篇,毕竟知识在于分享!
Spring的注解需要在配置文件中指定需要扫描的包.具体配置参照:<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance...