信息的表示和处理

注:以下内容均来自开源学习组织DataWhale

1 虚拟地址空间

将内存视为一个数组,数组中的元素是由一个个字节组成,每个字节由一个唯一数字表示,这个数字称为地址,所有地址的集合称为虚拟地址空间。

2 Byte(字节)与bit(位)

1byte = 8bits
对应二进制:00000000\~11111111;对应十进制:0\~255

进制转换:
对于 2 n 2^n 2n(二进制表示为1后面n个0)这样的二进制数字,快速转为十六进制的方法:先根据 n = i + 4 j n=i+4j n=i+4j计算i, j,最终十六进制表示为0x 2 i 2^i 2i后面加j个0。
例: 2 11 2^{11} 211 ; 11 = 3 + 2 × 4 11 =3+2\times4 11=3+2×4,i = 3, j = 2 对应十六进制为0x800
十进制与十六进制转换:辗转相除

3 字数据大小

字长为w位的机器,虚拟地址范围是 0 0 0 2 w − 1 2^w-1 2w1

例如32位机器,虚拟地址有 2 32 2^{32} 232个,每个地址是1byte,即总共 2 32 2^{32} 232bytes = 4GB

字长地址空间
w bit 0 0 0 ~ 2 w − 1 2^w-1 2w1
32 bit 0 0 0 ~ 2 32 − 1 2^{32}-1 2321, 4GB
64 bit 0 0 0 ~ 2 64 − 1 2^{64}-1 2641, 16EB

4 C语言中数据类型所占字节数大小

数据类型(有符号)数据类型(无符号)字节数(32位机器)字节数(64位机器)
[signed]charunsigned char11
shortunsigned short22
intunsigned44
longunsigned long48
int32_tuint32_t44
int64_tuint64_t88
char *48
float44
double88

5 寻址和字节顺序

假设一个int类型变量x(0x01234567),占4个字节,地址位于0x100处,因此变量x存储地址为0x100,0x101,0x102,0x103的内存处。

  • 大端法(最高有效字节存在最前面,即低地址处)
0x1000x1010x1020x103
···01234567···
  • 小端法(最低有效字节存储在最前面)
0x1000x1010x1020x103
···67452301···

注:大多数Intel兼容机采用小段模式,IBM和 Sun公司机器大多采用大端法,ARM架构的处理器支持双端法,但在Android和iOS系统之恶能运行小端模式。

6 十六进制与二进制对应关系

十六进制01234567
二进制00000001001000110100010101100111
十六进制89ABCDEF
二进制10001001101010111100110111101111

例如:字符串"abced",其在内存中存储信息为61 62 63 64 65 00,(C语言中字符串最后一位为null,即00)这个存储信息就是十六进制的,即十六进制的ASCII编码。单独拿出"a"对应的61看,十六进制数字61转为二进制可通过上表查到,6对应0110,1对应0001,即61对应二进制为01100001。

7 布尔运算

  • 非(NOT, ∼ \sim ): ∼ 0 = 1 \sim0=1 0=1 ∼ 1 = 0 \sim1=0 1=0

  • 与(AND,&): 0 & 0 = 0 0 \& 0=0 0&0=0 0 & 1 = 0 0 \& 1=0 0&1=0 1 & 0 = 0 1 \& 0=0 1&0=0 1 & 1 = 0 1 \& 1=0 1&1=0

  • 或(OR,|): 0 ∣ 0 = 0 0|0=0 00=0 0 ∣ 1 = 1 0|1=1 01=1 1 ∣ 0 = 1 1|0=1 10=1 1 ∣ 1 = 1 1|1=1 11=1

  • 异或(EXCLUSIVE-OR, ∧ \wedge ): 0 ∧ 0 = 0 0\wedge0=0 00=0 0 ∧ 1 0\wedge1 01=1 1 ∧ 0 = 1 1\wedge0=1 10=1 1 ∧ 1 = 0 1\wedge1=0 11=0

8 C语言中的位级运算

C语言一个特性就是支持按位进行布尔运算

例如: ∼ \sim 0x41,二进制为 ∼ \sim [0100 0001],运算结果为[1011 1110] ,运算结果十六进制表示为0xBE

位运算的一个常见用法就是实现掩码运算,例如:对于操作数0x89ABCDEF,如果想得到该操作数最低有效字节的值,可以通过&0xFF,就可以得到最低有效字节0x0000 00EF。

  • 左移运算
    左移几位就丢弃最高的几位,并在右端补相应个数的0
  • 右移运算
    (1) 逻辑右移:右移几位就丢弃最低的几位,并在左端补几个0
    (2) 算术右移:右移几位就丢弃最低的几位,左端补1
    unsigned右移是逻辑右移,signed右移一定是算术右移

9 整数的表示

  • 带有正、负号的二进制数称为真值。在计算机中约定:在有符号数的前面增加一位符号位,0表示正号,1表示负号。这种数被称为机器数。机器数的编码方式有原码、反码、补码3种。
  1. 原码:正数的符号位用0表示,负数的符号位用1表示,其余各位数表示数值本身
    例如:+1010110表示为01010110;-0110101表示为10110101
  2. 反码:正数的反码与其原码相同;负数的反码为保持其原码符号位不变,其余各位按位取反得到
    例如:+1010110表示为01010110;-0110101表示为11001010
  3. 补码:正数的补码与原码相同;负数的补码为保持原码符号位不变,其他位取反,最后再加1运算,即用其反码加1。
    例如:+1010110表示为01010110;-0110101表示为11001010+1即11001011

9.1 补码的意义

两种方式理解:

  1. 例如十进制数-5,二进制原码为1101,要得到-5的补码就需要找到与+5和为10000的二进制数(为什么这么找呢,我理解是-5补码地址位的1有了数值含义,即表示 − 2 4 -2^4 24,因此需要后面4位加 − 2 4 -2^4 24等于-5,反过来说就是后面4位与+5的和等于 2 4 2^4 24(即10000)),+5原码为0101,0101与1010和为1111,1111再加1就等于了10000,所以找到的那个二进制数为1010+1,即得到-5补码为1011。
  2. -5的补码为1011,由于最高位有了数值意义,其表示-8,另外两位上的1分别表示+2,+1,这样就可以根据补码直接计算出补码对应的十进制数。

9.2 byte的范围

1byte=8bits,即8位。对一个8位数据来说,其补码最小数字为[1000 0000]即 − 2 8 − 1 -2^{8-1} 281= -128,最大数字为[0111 1111]即 2 8 − 1 − 1 2^{8-1}-1 2811=127,所以1byte的范围为 − 128 ∼ 127 -128\sim127 128127

9.3 有符号数和无符号数的转换

short int a =-12345;
unsigned short b = (unsigned short)a;
printf(”a= %d , b = %u” , a, b);

在C语言中将一个有符号数-12345(十进制)强转为无符号数,转化结果为53191(十进制)。
但两个数的二进制表示是一样的,都是1100 1111 1100 0111。

  • 有符号(T)转无符号(U)满足下面公式:
    T 2 U w ( x ) = { x + 2 w x < 0 x x ≥ 0 T2U_w(x)=\begin{cases} x+2^w & x<0 \\ x & x\geq0 \\ \end{cases} T2Uw(x)={x+2wxx<0x0

    x x x:有符号数( x ≥ 0 x\geq0 x0即最高位数字是0, x < 0 x<0 x<0即最高位数字是1)

    T 2 U w ( x ) T2U_w(x) T2Uw(x):转换后的无符号数

    w w w:二进制数的位数

  • 无符号转有符号满足下面公式:

U 2 T w ( u ) = { u u ≤ T M a x w u − 2 w u > T M a x w U2T_w(u)=\begin{cases} u & u\leq TMax_w \\ u-2^w & u>TMax_w \\ \end{cases} U2Tw(u)={uu2wuTMaxwu>TMaxw

u u u:无符号数( u ≤ T M a x w u\leq TMax_w uTMaxw即最高位数字0, u > T M a x w u>TMax_w u>TMaxw即最高位数字是1)

U 2 T w ( u ) U2T_w(u) U2Tw(u):转换后的有符号数

w w w:二进制数的位数

9.3.1 转换案例

在C语言中,有符号数和无符号数进行运算时,C语言会隐式的将有符号数强制转换成无符号数来执行运算。

1 int i = -1;
2 unsigned int b = 0;
3 if(a < b)
4 	printf(”−1 < 0)
5 else
6 	printf(”−1 > 0)

执行结果为-1>0。

这是因为-1(二进制表示为32个1)被转换为无符号数,其十进制的值就变成了 2 32 − 1 2^{32}-1 2321

9.4 扩展与截断

9.4.1 扩展
  • 无符号数转成更大的数据类型:只需在扩展的数位进行补0即可,称为零扩展
  • 有符号数转更大的数据类型:
    • 非负有符号数:扩展的数位补0即可
    • 负数有符号数:扩展的数位需要补1

转换定理:当有符号数从一个较小的数据类型转换成较大类型时,进行符号位扩展,可以保持 数值不变。

9.4.2 截断
  • 无符号数: 将一个 w 位的无符号数,截断成 k 位时,丢弃最高的 w-k 位,截断操作可以对应 于取模运算,即除以 2 的 k 次方之后得到的余数。
  • 有符号数:
    1. 我们用无符号数的函数映射来解释底层的二进制位,这样一来我们就可以使用与 无符号数相同的截断方式,得到最低 K 位;
    2. 我们将第一步得到的无符号数转换成有符号数。

10 整数的运算

10.1 无符号数加法溢出

c = a + b − 2 w c=a+b-2^w c=a+b2w ,其中 w w w为二进制数的位数;

​ 例如:0(0000 0000) = 255(1111 1111) + 1(0000 0001) - 2 8 2^8 28

C语言中判断是否溢出代码如下:

1 int uadd_ok(unsigned x, unsigned y){
2 	unsigned sum = x + y;
3 	return sum >= x; // 溢 出 返 回 0, 没 溢 出 返 回 1
4 }

10.2 补码加法溢出

  • 当 x 加 y 的和大于等于 2 w − 1 2^{w−1} 2w1 时,发生正溢出,此时,得到的结果会减去 2 w 2^w 2w
  • 当 x 加 y 的和小于 − 2 w − 1 −2^{w−1} 2w1 时,发生负溢出,此时,得到的结果会加上 2 w 2^w 2w

10.3 加法逆元(相反数)

对于减法运算可以转化为加法逆元,即 y − x → y + x ′ y-x\rightarrow y+x\prime yxy+x ( x ′ 为 x 的 加 法 逆 元 , 也 称 相 反 数 x\prime为x的加法逆元,也称相反数 xx)

w 位 的 无 符 号 数 逆 元 x ′ = { x x = 0 2 w − x x ≥ 0 w位的无符号数逆元x\prime=\begin{cases} x & x=0 \\ 2^w-x & x\geq0 \\ \end{cases} wx={x2wxx=0x0

w 位 的 有 符 号 数 逆 元 x ′ = { − x x > T M i n w T M i n w x = T M i n w w位的有符号数逆元x\prime=\begin{cases} -x & x>TMin_w \\ TMin_w & x=TMin_w \\ \end{cases} wx={xTMinwx>TMinwx=TMinw

T m i n w Tmin_w Tminw:w位有符号数的最小值
T M i n w + T M i n w = − 2 w − 1 + ( − 2 w − 1 ) = − 2 w TMin_w+TMin_w=-2^{w-1}+(-2^{w-1})=-2^w TMinw+TMinw=2w1+(2w1)=2w

因 为 − 2 w < − 2 w − 1 , 发 生 负 溢 出 , 所 以 得 到 结 果 会 加 上 2 w , 如 下 式 : 因为-2^w<-2^{w-1},发生负溢出,所以得到结果会加上2^w,如下式: 2w<2w12w

T M i n w + T M i n w 的 逆 元 = − 2 w + 2 w = 0 因 此 T M i n w 逆 元 是 其 本 身 TMin_w+TMin_w的逆元=-2^w+2^w=0 \\ 因此TMin_w逆元是其本身 TMinw+TMinw=2w+2w=0TMinw

10.4 乘法运算

  • 无符号数乘法

    w 位的无符号数 x 和 y,二者的乘积可能需要 2w 位来表示。在 C 语言中,定义了无符号数乘法所产生的结果是 w 位,因此,运行结果会截取 2w 位中的低 w 位。截断采用取模的方式,因此,运行结果等于 x 与 y 乘积并对 2 的 w 次方取模

  • 补码乘法

    计算机的有符号数用补码表示,因此补码乘法就是有符号数乘法。无论是无符号数 乘法,还是补码乘法,运算结果的位级表示都是一样的,只不过补码乘法比无符号 数乘法多一步,需要将无符号数转换成补码(有符号数)。

    虽然完整的乘积结果的位级表示可能会不同,但是截断后的位级表示都是相同的

注:如果乘以的是2的整倍数,可以通过左移进行快速计算。

例如:chart 9(0000 1001),左移一位变为18(00010010),等于 9 × 2 9\times2 9×2

又例如: x × 14 = x ⋅ ( 2 4 − 2 1 ) = ( x < < 4 ) − ( x < < 1 ) x\times14=x\cdot(2^4-2^1)=(x<<4)-(x<<1) x×14=x(2421)=(x<<4)(x<<1)

10.5 除以2的倍数也可以用移位运算实现

  • 无符号数采用逻辑右移

  • 有符号数(补码)采用算术右移

    • 当补码小于0,需要先加上偏置(偏执量为 2 k − 1 2^k-1 2k1)再进行算术右移
    • 当补码大于0,可以直接进行算术右移

    除法结果总是向0舍入,如 3.14 → 3 3.14\rightarrow3 3.143 3.14 → 3 3.14\rightarrow3 3.143

    11 浮点数

    11.1 IEEE浮点数表示

    V = ( − 1 ) s × M × 2 E V=(-1)^s\times M\times2^E V=(1)s×M×2E

    s s s:符号位; E E E:阶码; M M M:尾数

    例如:C语言中float为4个byte,占32bits,这32个bits划分如下:

在这里插入图片描述

最高位31为符号位(s=0为正数,s=1为负数)。23-30位这八位与阶码E的值有关,剩余23位与尾数M相关。

IEEE浮点表示可以分为一下三种

  • 当阶码字段不全为0,且不全为1,此时表示规格化的值
  • 当阶码字段全为0,此时表示非规格化的值
  • 当阶码字段全为1,表示特殊值(无穷或“不是一个数,NaN”)

11.2 整形转单精度浮点型

例如整形12345,对应二进制为[0000 0000 0000 0000 0011 0000 0011 1001],前18位没有意义,只看后14位,即11 0000 0011 1001。其中第一位为符号位,看后13位,由于单精度的小数字段长度位23,需要在后面补10个0,即[1 0000 0011 1001 0000 0000 00],这个二进制数即为单精度浮点数的小数字段。

从12345 的规格化表示可以发现阶码 E 的值等于 13,由于单精度浮点数的 bias 等于 127,因此根据公式 E=e-bias,可以计算出 e 的值等于 140,其二进制为1000 1100,这个二进制数即为浮点数的阶码字段。

最后再加上符号位的0,就可以推出来整个单精度浮点数的二进制数字。

11.3 舍入

  • 向偶舍入
  • 向零舍入
  • 向下舍入
  • 向上舍入
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值