一.数据是什么
单位 | 等于bit | 等于字节 | 等于字 |
bit | 1 | 1/16 | 1/8 |
字节 | 8bit | 1 | 1/2 |
字 | 16bit | 2 | 1 |
在计算机中处理信息的最小单位是bit(位),bit不可再分且bit只有两个值
计算机把信息以一组或者一串bit的形式保存在存储器中,该形式被称为字节,一字节等于8位。计算机处理信息是以一串bit为基础。所以所有微处理器的字长都是8位的整数。计算机所处理的字节位数越多那么计算机的性能越好。
在计算机中数据以二进制的方式进行保存,无论是指令、数据、图像、视频还是什么都以二进制进行保存。
计算机保存数值的方法
数字在计算机中存储
计算机存储的数字表
类型 | 存储方法 | 译解方法 |
无符号整数 | 以二进制原码进行存储 | 直接将内存中的无符号整数的二进制编码转换为十进制 |
符号加绝对值 | 待定 | |
有符号整数 | 二进制补码表示法 |
无符号整数的应用:
应用类型 | 解释 |
计数 | 计数不需要负数 |
寻址 | 地址都是从零开始,无符号整数适用 |
存储文本、图像、音频、视频 | 是以位的模式存储的,可以翻译为无符号整数 |
计算机中的所有信息,都是用二进制进行表示。二进制的最小单位是“bit”,可以表示两种状态。给这两种状态赋予数字的意义就是“0” 和 “1”,赋予电位的意义就是“高电位”和“低电位”,赋予逻辑的意义就是“是”和“否”。位(bit)本身没有意义,只有当人去赋予意义或者进行解释的时候才会有意义。一个位只有两种状态,显然是不够用来表示各种各样不同的信息,所以就需要很多的位(bit)来进行组合。
把位组合在一起,赋予某种解释或者意义就是编码。在计算机中数字的编码有三种重要的形式。无符号(unsigned)、补码(two's-complement)、浮点数(floating-point)。使用二进制编码的主要原因是因为底层的电路容易设计,并且比三进制电路便宜,是性价比的选择。
编码类型 | 作用 |
无符号编码 | 表示大于0或者等于0的整数 |
有编码 | 表示有符号整数,可以为正,可以为负的数字 |
浮点数编码 | 表示实数的科学计数法以2为基数的版本 |
没有什么东西是无限的,所以编码的位数是有限的。它们取决于计算机的位数,而计算机的位数同样取决于性价比。一但数字太大,有限的位数无法表示的时候,就会出现溢出。就如C语言中的char类型一样,只有8位,也就是一字节。
\(2^8-1=255\)
由于溢出的存在,在进行编程的时候,不得不考虑一下数据的范围,以防出现难以预料的错误。
计算机中的编码,一定要注意机器的字长。比如在8086处理器中,字长为16位。
无符号编码:
无符号编码,主要用来编码正整数,和计算机内存单元的地址。在二进制系统中,所有的位数都用来表示数值。比如有一个4位的二进制数。1010,在1010中的每一位,都是数值位。
比如整数6用二进制无符号的编码方式在16位处理器中进行表示。那么6的二进制码,就是6的二进制码,位数不足的时候要补零。
\[(6)_{10}=(0000000000000110)_{2} \]
计算的方式就是对10进制的6转换为2进制的6。
转换的方法为:
\[6\div2=3······0 \]
\[3\div2=1······1 \]
\[1\div2=0······1 \]
把余数从低到高排列 那么6的二进制就是 110。位数不足16位则补零,所以6的二进制无符号编码是0000000000000110。
有符号编码:
在有符号编码中,有原码,反码,和补码这三种编码方式,但计算机中表示有符号数采用的是补码。
原码
原码的编码最高位为符号位,其余位为数字位。组合是符号位+数值位 以16位处理器为例。
\[(6)_{10} = (0000000000000110)_{2} \]
\[(-6)_{10} = (1000000000000110)_{2} \]
\(~\){2^{15}-1}$
反码
反码的定义是原码取反,规定正数的反码是正数本身,负数的反码是负数反码的取反,符号位不变。还是以16位处理器中,6来举例。
6的原码
\[(6)_{10} = (0000000000000110)_{2} \]
6的反码
\[(6)_{10} = (0000000000000110)_{2} \]
-6的原码
\[(-6)_{10} = (1000000000000110)_{2} \]
-6的反码
\[(-6)_{10} = (1111111111111001)_{2} \]
-6的反码变化中,符号位没有发生变化,但其它为进行了取反。
任何一种工具的出现,一定是为了解决某个现有工具无法解决的问题。比如有符号编码的出现就是为了解决计算机中负数的表示,而反码的出现是为了解决计算机计算减法的问题。
我们来看一组运算二进制加法的运算,二进制加法的运算与十进制一样,唯一的差别在于十进制是逢十进一,而二进制是逢二进一。
用原码进行编码的加法:
计算3+6=9 在16位cpu上。
\[(6)_{10} = (0000000000000110)_{2} \]
3的原码
\[(3)_{10} = (0000000000000011)_{2} \]
3+6
\[{{~~0000000000000011}} \]
\[{{+0000000000000110}} \]
\[{~—————————} \]
\[{{~~~0000000000001001}} \]
正确计算出来的结果等于9
\[(9)_{10} = (0000000000001001)_{2} \]
计算-6+3 = -3
\[{{~~1000000000000110}} \]
\[{{+0000000000000011}} \]
\[{~—————————} \]
\[{~~1000000000001001} \]
计算出-6+3 = -9 这个结果明显是错误的,只有数值部分参与了运算,而符号部分没有。为了纠正这个错误,一是设计一种新的电路,可以让符号位参与运算,二是采用满足要求的编码方式。
电路的设计是很麻烦的,多在cpu的运算器上设计一个电路,对应的成本就会增加很多。于是决定采用同种电路运算,所以反码出现了。
以下是反码编码的运算:
计算3+6 =9 反码的计算这个结果,很容易得出结果是正确的,因为正数的反码是本身。
计算-6+3 = -3
-6的反码:
\[(-6)_{10} = (1111111111111001)_{2} \]
用反码计算-6+3的结果
\[{{~~1111111111111001}} \]
\[{{+0000000000000011}} \]
\[{~—————————} \]
\[{~~~1111111111111100} \]
\({~~~1111111111111100}\)
在来计算一个 -6 + 6 = 0 计算出的16位二进制表示是 \({(1111111111111111)_2}\)
\({(0000000000000000)_2}\) 这好像有点不太对,因为1的反码编码是\({(0000000000000001)_2}\)而不是 \({(0000000000000000)_2}\)
最后一种编码方式是补码编码。
补码
计算机对有符号数采用的编码方式是补码的编码方式。虽然C语言标准并没有要求用补码来表示有符号整数,但几乎所有的机器是这样做的。意思是,几乎所有机器,对有符号数采用的都是补码的编码方式。
这意味着,在计算机低层。所有的有符号运算,都是基于补码的运算。
补码的定义:
对于正数而言,正数的补码就是原码。
对于负数而言,负数的补码是反码+1。
比如 -6的补码
先要16位知-6的反码:
\[(-6)_{10} = (1111111111111001)_{2} \]
然后加一个 1
就是
\[(-6)_{10} = (1111111111111010)_{2} \]
就可以求出-6的补码为\((1111111111111010)_{2}\)