# 数据存储和进制转化
标签(空格分隔): 基础知识
---
传统的计算机都是基于冯诺依曼体系,用集成电路中二极管的通电和断电,高电平和低电平等状态位来表示1和0(就这么个意思,简要描述错误之处请指出),故计算机只能识别二进制的0、1。现实世界的数据都是通过一定的规则转化为二进制数据流然后才能在计算机中存储和运算.
1.进制的概念: 进制也就是进位制,是人们规定的一种进位方法。 对于任何一种进制---X进制,就表示某屏幕快照 2016-12-23 下午2.10.18一位置上的数运算时是逢X进一位。 十进制是逢十进一,十六进制是逢十六进一,二进制就是逢二进一
在采用进位计数的数字系统中,如果只用r个基本符号表示数值,则称为r进制(Radix-r Number System),r称为该数制的基数(Radix)。不同的数制的共同特点如下:
(1)、每一种数制都有笃定的符号集。例如,十进制数制的基本符号有十个:0,1,2。。。,9。二进制数制的基本符号有两个:0和1.
2、每一种数制都使用位置表示法。即处于不同位置的数符所代表的值不同,与它所在位的权值有关。
例如:十进制1234.55可表示为
1234.55=1×10^3+2×10^2+3×10^1+4×10^0+5×10^(-1)+5×10^(-2)
可以看出,各种进位计数制中权的值恰好是基础的某次幂。因此,对任何一种进位计数制表示的数都可以写成按权展开的多项式。
3. 八进制和十六进制
人类一般的思维方式是十进制,编码人员看到一堆0 1的二进制数肯定蛋疼,例如一个最简单char 类型字符 a的二进制表示: 0010 0110,直接用十进制又无法准确计算机思维方式(二进制 0B).所以出现了八进制和十六进制,当然十六进制的运用更加广泛,例如一个int型的32位数字,用八进制表示 32/3 = 2,余2也就是说我们每个前面要加2个0.学过编程的肯定知道变量的地址一般都是用十六进制表示 :
printf(" c address : %p\n",&c);
输出: c address : 0x7fff5fbff73c
所以说用十六进制表达二进制字符串无疑是最佳的方式,这就是八进制和十六进制出现的原因。
4.进制间的转换
常用的进制有 二进制 八进制 十进制 十六进制
- 1.二进制,八进制,十六进制 -> 十进制
都是按权展开多项式相加得到十进制
示例:
二进制1010.101 -> 1 * 2^3 + 0 * 2^2 + 1 * 2^1 + 0 * 2^0 + 1*2^(-1) + 0 * 2^(-2) + 1*2^-3=10.6875
八进制 13.1到十进制 1*8^1 + 3*8^0 + 1*8^(-1) = 11.125
十六进制13.1到十进制 1*16^1 + 3*16^0 + 1*16^(-1) = 19.0625
- 2.十进制 -> 二进制 八进制 十六进制 都是按照整数部分除以基数(r)取余,小数部分乘以基数(r)取整.
十进制10.25 到二进制
10/2 --0
5/2 --1
2/2 --0
1/2 --1
0.25 * 2 = 0.5 -- 0
0.5 * 2 = 1 -- 1
整数部分: 1010
小数部分: 01
所以到二进制 1010.01,
同理八进制和十六进制,只是基数改变而已
- 3 二进制 <----> 八进制 十六进制
二进制转化为八进制: 从小数点起,二进制每三个数字分为一组,若不够小数点前面的在每组前面加0,后面的在每组后面就0,然后把每组数转化为相应的十进制数就可以了
10010101.101 - (010 010 101) . (101) = (2 2 5) . (5) = 225.5
八进制转二进制: 八进制数每一位转化为二进制数,拼起来
257.56 = (10 101 111). (101 110) = 10101111.101110
二进制转十六进制: 小数点起,二进制数每4个二进制位分为一组,如果不够小数点前面的在每组前面加0,后面的在每组后面加0,然后把每组数转化为相应的十进制数就行,注意一点就是
10->A , 11->B , 12->C , 13->D , 14->E, 15->F 大于等于10的用字母表示(不区分大小写)
10101111.10111 -> (1010 1111).(1011 1000) = (12 16).(13 9) = AF.B8
数据的分类
编程中数据类型一般分为基本数据类型和复合数据类型,特别是面向对象编程中的类和对象就是一种典型的复合数据类型.本质上复合数据类型也是由基本数据类型构成.
以C语言为例,基本数据类型有 字符型char, 整型(无符号 带符号 长 短整型等等),实现(float,double),bool型(其实bool型也是整型,只不过用宏定义声明了而已)
先说基本数据类型
1.无符号
unsigned int b = 1; //
printf(" c address : %#x\n",b);
输出 : 0x7b (0x1)
可以看出直接就是二进制数表示的
2.带符号
对于带符号整数,最高位是符号位.0代表+,1代表-
int c = -1;
printf(" c address : %#x\n",c);
输出: 0xffffffff (11111111111111111111111111111111)
输出和无符号完全不一样,这是因为带符号整型和无符号整型的二进制表示方式不一样
这又涉及到另外一个问题,原码,反码和补码
- 1.原码:
数值X的原码记做[X]原,若果机器字长为n(即用n个二进制位表示数据).最高位符号位,其余的n-1表示数值的绝对值, 数值0的原码有两种表示方式: [+0]原 = 0000 0000 , [-0]原 = 1000 0000
例子: 字长n为8的数字
[+1] = 0000 0001 [-1] = 1000 0001
[+127] = 0111 111 [-127] = 1111 1111
两者相加明显有问题,这又引出了下一个问题-反码
- 2.反码
数值X的反码记做[X]反,最高位是符号位,0为正1为负.正数:反码=原码,负数: 反码=原码绝对值按位取反,数值0的反码有两种表示方式 [+0] = 0000 0000, [-0] = 1111 1111,
例子: 字长n为8的数字
[+1] = 0000 0001 [-1] = 1111 1110
[+127] = 0111 1111 [-127] = 1000 0000
用反码进行计算 1111 1110 -> 1000 0001
-1 + 1 = 0 | (1111 1110)反 + (0000 0001)�反 = (1000 0000)原= 0没有问题
1+(-2)=-1 | (0000 0001)反 + (1111 1101)反 = (1000 0001)原 = -1 没有问题
-1 + 2 = 1 | (1111 1110)反 + (0000 0010)反 = (0000 0000)原 = 0 发生了溢出
所以反码也是不对的,这就又引出了补码这个概念
- 3.补码
数值X的补码记做[X]补,如果数字字长为n,最高位为符号位,0代表正好,1代表负号.正数的补码和原码反码都相同,负数的补码等于反码在末尾加1.数值0有唯一的补码 [+0] = 0000 0000 [-0] = 0000 0000
例子: 字长n=8的数字
[+1]补 = 0000 0001 [-1]补 = 1111 1111
[+127]补 = 0111 1111 [-127]补 = 1000 0001
[+45]补=0010 1101 [-45]补=1101 0011
反码的运算:
-1 + 1 = 0 (1111 1111)补 + (0000 0001)补 = (0000 0000)补 = (0000 0000)原 没有问题
-2 + 1 = -1 (1111 1110)补 + (0000 0001补 = (1111 1111)补 = (1000 0001)原 没有问题
-1 + 2 = 1 (1111 1111)补 + (0000 0010)补 = (0000 0001)补 = (0000 0001)原
没有问题
- 浮点数的存储
根据IEEE754标准,任意一个浮点数V可以表示为以下形式
如十进制V = 9.0,表示为二进制 1001.0,相当于 1.001 * 2^3, 则 S = 0, M=1.001,E = 3;
同理十进制V = -9.0,表示为二进制 -1001.0*2^3,则S = 1,M=1.001,E=3;
参考:
http://blog.csdn.net/lonelyroamer/article/details/7670869
http://www.ruanyifeng.com/blog/2010/06/ieee_floating-point_representation.html