1、进制
1.1 进制的由来
进制:是一种进位的方式。x进制,表示逢x进1。
计算机的电子原件的状态:开,关。
那么,我们表达数据的时候,也是按照开,关的状态来表示的。
如果我们表达数据仅仅使用这两种昨天,那么能够表达的数据是比较少的。
而我们常见的数据,英文字母,数字,标点符号,这就很多了。
为了能够表示更多的数据,国际化组织就规定,用8个这样的信号来表示一个数据,并且用1,0表示两种状态,这个数据的单位叫:字节。
由这样的1,0组成的数据就是二进制数据。
- 单位转换
1byte=8bit
1kB=1024byte
1MB=1024kB
1GB=1024MB
1T=1024GB
- 基础补充:
大写B(byte),字节;小写b(bit),比特;
1B=8b,即一个字节等于8个比特位。
1KB=8kb,k表示千,即1千字节等于8千比特。一般来说,计算机中的进位是1024进位的,但是在通信中,为了方便计算,通常用千进位。
(为什么要用1024进位,因为计算机码是以二进制为基础,2的幂数可以反映二进制的位数,因为2的10次幂是1024,最接近1000(1K),方便十进制的估算。)
1byte=8bits,两者换算是1:8的关系。
1Byte就是1个字节,1个字节是由8个二进制位组成。
1.2 进制的表示
定义:
二进制数
每一位使用两个不同数字表示(0,1)
低位和高位的关系是:逢2进1
各位的权值是2的整数次幂(基数是2)
标志:尾部加B
例:101.01B=1×22+0×22+1×20,+0×2−1+1×2−2=5.25
八进制数
每一位使用八个不同数字表示(0,1,2,3,4,5,6,7)
低位和高位的关系是:逢8进1
各位的权值是8的整数次幂(基数是8)
标志:尾部加Q
例:365.2Q=3×82+6×81+5×80+2×8−1=245.25
十六进制
每一位使用十六个不同数字表示(0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F)
低位和高位的关系是:逢16进1
各位的权值是16的整数次幂(基数是16)
标志:尾部加H
例:F5.4H=15×161+5×160+4×16−1=245.25
第一种表示方式:
(1100101100)2=(1454)8
(1100101100)2=(32C)16
第二种表示方式(在末尾加字母):
例如:二进制再末尾加B,十进制加D,八进制加Q,十六进制加H
1.3 进制的转换
1.3.1 R进制转十进制使用按权展开法
其具体操作方式为:将R进制数的每一位数值用RKRK形式表示,即幂的底数是R,指数为K,K与该位和小数点之间的距离有关。当该位位于小数点左边,K值是该位和小数点之间数码的个数,而当该位位于小数点右边,K值是负值,其绝对值是该位和小数点之间数码的个数加1。
例如 二进制: 10100.01=1⋅24+1⋅22+1⋅2−2=20.2510100.01=1·24+1·22+1·2−2=20.25
例如 七进制 604.01=6⋅72+4⋅70+1⋅7−2≈298.02604.01=6·72+4·70+1·7−2≈298.02
1.3.2 十进制转R进制
如果是整数,直接使用短除法。(例如将94转换为二进制。)
得到结果为1011110
- 如果是浮点数,对整数和小数分开转换;整数部分:除以2取余,小数部分:乘以2取整。(例如29.6875 -> 11101.1011B)
注意十进制小数(如0.63)在转换时会出现二进制无穷小数,这时只能取近似值。
1.3.3 二进制与八进制的互换(用三位二进制数一组表示一位)与十六进制数(用四位二进制数一组表示一位)
- 八进制 -> 二进制:把每个八进制数字改写成等值的3位二进制数,且保持高地位的次序不变。
例:2 4 6 3 2 Q - >
010 100 110 111 011 010 B
- 二进制 ->八进制:整数部分从低位到高位每3组用一个等值的八进制数来替换,不足3位时在高位补0凑满3位;小数部分从高位向低位每3位用一个等值八进制数来替换,不足3位时在低位补0凑满三位。
例:1 101 001 110. 110 01B ->
001 101 001 110. 110 010B ->
1 5 1 6 6 2Q
3. 机器数采用原码,反码和补码等编码方法,称为码制。
3.1 机器数与真值
3.1 机器数
一个数在计算机中的二进制表示形式, 叫做这个数的机器数。机器数是带符号的,在计算机用一个数的最高位存放符号, 正数为0, 负数为1.
比如,十进制中的数 +3 ,计算机字长为8位,转换成二进制就是00000011。如果是 -3 ,就是 10000011 。
那么,这里的 00000011 和 10000011 就是机器数。
3.2 真值
因为第一位是符号位,所以机器数的形式值就不等于真正的数值。例如上面的有符号数 10000011,其最高位1代表负,其真正数值是 -3 而不是形式值131(10000011转换成十进制等于131)。所以,为区别起见,将带符号位的机器数对应的真正数值称为机器数的真值。
例:0000 0001的真值 = +000 0001 = +1,1000 0001的真值 = –000 0001 = –1
3.2 原码,反码和补码
3.2.1 概念
在探求为何机器要使用补码之前, 让我们先了解原码, 反码和补码的概念.对于一个数, 计算机要使用一定的编码方式进行存储. 原码, 反码, 补码是机器存储一个具体数字的编码方式.
- 原码
原码就是符号位加上真值的绝对值, 即用第一位表示符号, 其余位表示值. 比如如果是8位二进制:
[+1]原 = 0000 0001
[-1]原 = 1000 0001
第一位是符号位. 因为第一位是符号位, 所以8位二进制数的取值范围就是:
[1111 1111 , 0111 1111] 即 [-127 , 127]
原码是人脑最容易理解和计算的表示方式.
- 反码
反码的表示方法是:正数的反码是其本身
负数的反码是在其原码的基础上, 符号位不变,其余各个位取反.
[+1] = [00000001]原 = [00000001]反
[-1] = [10000001]原 = [11111110]反
可见如果一个反码表示的是负数, 人脑无法直观的看出来它的数值. 通常要将其转换成原码再计算.
- 补码
补码的表示方法是:
正数的补码就是其本身
负数的补码是在其原码的基础上, 符号位不变, 其余各位取反, 最后+1. (即在反码的基础上+1)
[+1] = [00000001]原 = [00000001]反 = [00000001]补
[-1] = [10000001]原 = [11111110]反 = [11111111]补
对于负数, 补码表示方式也是人脑无法直观看出其数值的. 通常也需要转换成原码在计算其数值.
3.2.2. 为何要使用原码, 反码和补码
现在我们知道了计算机可以有三种编码方式表示一个数. 对于正数因为三种编码方式的结果都相同:
[+1] = [00000001]原 = [00000001]反 = [00000001]补
1
所以不需要过多解释. 但是对于负数:
[-1] = [10000001]原 = [11111110]反 = [11111111]补
1
可见原码, 反码和补码是完全不同的. 既然原码才是被人脑直接识别并用于计算表示方式, 为何还会有反码和补码呢?
首先, 因为人脑可以知道第一位是符号位, 在计算的时候我们会根据符号位, 选择对真值区域的加减. (真值的概念在本文最开头). 但是对于计算机, 加减乘数已经是最基础的运算, 要设计的尽量简单. 计算机辨别”符号位”显然会让计算机的基础电路设计变得十分复杂! 于是人们想出了将符号位也参与运算的方法. 我们知道, 根据运算法则减去一个正数等于加上一个负数, 即: 1-1 = 1 + (-1) = 0 , 所以机器可以只有加法而没有减法, 这样计算机运算的设计就更简单了.
于是人们开始探索 将符号位参与运算, 并且只保留加法的方法. 首先来看原码:
计算十进制的表达式: 1-1=0
1 - 1 = 1 + (-1) = [00000001]原 + [10000001]原 = [10000010]原 = -2
1
如果用原码表示, 让符号位也参与计算, 显然对于减法来说, 结果是不正确的.这也就是为何计算机内部不使用原码表示一个数.
为了解决原码做减法的问题, 出现了反码:
计算十进制的表达式: 1-1=0
1 - 1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原= [0000 0001]反 + [1111 1110]反 = [1111 1111]反 = [1000 0000]原 = -0
发现用反码计算减法, 结果的真值部分是正确的. 而唯一的问题其实就出现在”0”这个特殊的数值上. 虽然人们理解上+0和-0是一样的, 但是0带符号是没有任何意义的. 而且会有[0000 0000]原和[1000 0000]原两个编码表示0.
于是补码的出现, 解决了0的符号以及两个编码的问题:
1-1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原 = [0000 0001]补 + [1111 1111]补 = [0000 0000]补=[0000 0000]原
1
这样0用[0000 0000]表示, 而以前出现问题的-0则不存在了.而且可以用[1000 0000]表示-128:
(-1) + (-127) = [1000 0001]原 + [1111 1111]原 = [1111 1111]补 + [1000 0001]补 = [1000 0000]补
-1-127的结果应该是-128, 在用补码运算的结果中, [1000 0000]补 就是-128. 但是注意因为实际上是使用以前的-0的补码来表示-128, 所以-128并没有原码和反码表示.(对-128的补码表示[1000 0000]补算出来的原码是[0000 0000]原, 这是不正确的)
使用补码, 不仅仅修复了0的符号以及存在两个编码的问题, 而且还能够多表示一个最低数. 这就是为什么8位二进制, 使用原码或反码表示的范围为[-127, +127], 而使用补码表示的范围为[-128, 127].
因为机器使用补码, 所以对于编程中常用到的32位int类型, 可以表示范围是: [-231, 231-1] 因为第一位表示的是符号位.而使用补码表示时又可以多保存一个最小值.
3.2.3 总结:
原码是最符合人脑的,用最高位表示符号位,其余位表示数值位。
反码是为了方便带符号的机器数之间运算,让符号位也参与运算。(原理是对原码操作,符号位不变,数值位取反)(注意结合1-1这个例子来理解!)
补码是为了解决-0以及[00000000]原和[10000000]原两个编码都表示0这个问题,在反码的基础上加1,就能只用[00000000]来表示0了,[10000000]则表示-128.(原理是对反码基础上加1)(注意结合1-1和-1-127这两个例子来理解!)
转自:
https://blog.csdn.net/sgq_csdn/article/details/79181440#11-进制的由来,个人感觉这篇文章写得非常赞,强烈推荐