文章目录
计算机底层如何存储不同的数据
一、计算机存储整数
1.1 简介
计算机底层存储的是整数的
补码
,要得到补码
,必须先得到原码
,和反码
。计算器中的 程序员模式 可以快速查看数字的补码。
1.2 原码、反码、补码
使用 1 字节 的 整数举例:1 字节(
byte
)等于 8 个 二进制位(bit
)
-
原码: 最高位是符号位(
0
表示正数,1
表示负数),其他位为数值位。10的原码: 00001010 -10的原码: 10001010
-
反码: 正整数的反码与原码一致,负整数的反码是在原码基础上,符号位不变,其他位按位取反
10的反码: 00001010 -10的反码: 11110101
-
补码: 正整数的补码与原码一致,负整数的补码是在反码基础上加1
10的补码: 00001010 -10的补码: 11110110
1.3 有了原码为什么要使用反码和补码
因为人脑可以知道第一位是符号位,可以根据符号位对二进制进行加减乘除。
但是对于计算机来说,加减乘除是最基本的运算,要设计的尽量简单,计算机辨别符号位会让计算机的设计电路变得很复杂。
于是人们想出了让符号位也参与到运算上来。减去一个数,等于加上他的负数。
原码表
从上面的原码表中可以看见左边每增加一个二进制单位对应的数字是递减的,而右边每增加一个二进制单位对应的数字是递增的,所以对于原码来说,能满足正数的加法,但无法满足负数的加法
2+ 1=[0000_0010]原+[0000_0001]原=[0000_0011]原 =3 // 正数相加正确
1+-1=[0000_0001]原+[1000_0001]原=[1000_0010]原=-2 // 负数计算失败
1.3.1 为什么要有反码
为了满足负数对加法的需求,就必须让负数与他对应的二进制码是同步递增或者同步递减。
于是就通过符号位不变,其余位取反来满足这个同步递增或者递减的要求,由于正数本来就满足它本身的加法,所以不需要做任何改变。这就是反码的定义由来。
反码表
127+1=[0111_1111]反+[0000_0001]反=[1000_0000]反=128=-127 // 超出存储范围从按余数取值
-2+ 1=[1111_1101]反+[0000_0001]反=[1111_1110]反=-1 // 满足负数计算
-1+ 2=[1111_1110]反+[0000_0010]反=[0000_0000]反=0 // -1 + 2 跨过 0 出现误差
- 超出范围加法算出来是128,由于128超过最大值,余1,所以取最小值开始的第一位,也就是最小值-127。
- 正负数的加法已经能满足要求, 但是这里有个不合理的地方,就是[1111_1111]和[0000_0000]都表示0,这导致在实际计算中每当跨过0一次,就有一个单位的误差
1.3.2 为什么要有补码
由于 [1111_1111]+[0000_0001]=[0000_0000],所以在负数反码的基础上
+1
就可以解决反码中跨0
的误差问题,同时不会对负数与它对应的二进制反码的同步递增产生影响,所以在反码的基础上+1
就完美的解决了符号参与预算的问题,这就是补码为什么是在负数反码的基础上+1
的由来。
补码表
从上面的图中发现还有一个 [1000_0000] 的二进制没有对应任何数字,于是就规定了这个数是 -128
所以补码的表示范围是[-128~127] ,这样一来 256 个二进制正好表示 256 个整数。
一个字节可以表示的数值范围:
-
不考虑负数:
0000 0000 ~ 1111 1111 ==> 0 ~ 255
-
考虑负数:
0000 0000 ~ 0111 1111 ==> 0 ~ 127 1000 0001 ~ 1111 1111 ==> -127 ~ -1 (补码形式存储) 1000 0000 ==> -128 特殊值,最高位既是符号位,又是数值位
二、计算机存储小数
- 计算机中不能精确存储小数,实际存储的是一个
近似值
。- 同样位数的二进制存储的浮点数的范围远大于存储整数。
三、 计算机存储字符
3.1 简介
在计算机的内部都是二进制的
0
、1
数据,如何让计算机可以识别文字呢?
这时就产生出了编码表的概念。
编码表: 就是将人类的文字和一个十进制数进行对应起来组成一张表格。
例如:
3.2 ASCII(编码表)
ASCII 因为只包含 英文字母,数字,符号。其他国家要使用计算机怎么办呢?
后面就有了很多很多的编码表(中文简体GBK
阿拉伯语ISO-8859-6
韩语EUC-KR
等等很多编码表)
世界上第一张编码表 ASCII(American Standard Code for Information Interchange 美国标准信息交换码)将所有的英文字母,数字,符号都和十进制进行了对应。
3.3 Unicode (编码表)
因为每个国家指定了不同的编码表,又出现了第二个问题。(乱码)
比如:你使用GBK
编码表 通过二进制 编好后,发文件给美国人。虽然你发的文档可能都是英文写的。但是他是使用的ASCII
解析,你的A
被其他编码表解码后就不一定是A
了。
为了解决乱码这个问题, Unicode 就诞生了,Unicode 包含了世界上已知的所有字符, 每个国家的人都使用这个编码表就解决乱码的问题了。
Unicode (统一码、万国码) 是计算机科学领域里的一项业界标准,包括字符集、编码方案等。Unicode 是为了解决传统的字符编码方案的局限而产生的,它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。
3.4 UTF-8(编码表)
unicode 使用两个字节存储一个字符,对于大量的英文字符(1个字节可以存储),无疑是浪费空间的。所以出现了 UTF-8
、UTF-16
等等编码规则。UTF-8是以 8 位为一个编码单位的可变长编码规则。
这时:
- 英文字符:还是按照
ASCII
码表对应的数字进行存储(1个字节) - 中文字符:通常需要 3 个字节来存储