信息的表示和处理

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

1 虚拟地址空间

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

2 Byte(字节)与bit(位)

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

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

3 字数据大小

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

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

字长地址空间
w bit000 ~ 2w−12^w-12w1
32 bit000 ~ 232−12^{32}-12321, 4GB
64 bit000 ~ 264−12^{64}-12641, 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=10=1 ∼1=0\sim1=01=0

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

  • 或(OR,|):0∣0=00|0=000=0 0∣1=10|1=101=1 1∣0=11|0=110=1 1∣1=11|1=111=1

  • 异或(EXCLUSIVE-OR,∧\wedge):0∧0=00\wedge0=000=0 0∧10\wedge101=1 1∧0=11\wedge0=110=1 1∧1=01\wedge1=011=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有了数值含义,即表示−24-2^424,因此需要后面4位加−24-2^424等于-5,反过来说就是后面4位与+5的和等于242^424(即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]即−28−1-2^{8-1}281= -128,最大数字为[0111 1111]即28−1−12^{8-1}-12811=127,所以1byte的范围为−128∼127-128\sim127128127

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)满足下面公式:
    T2Uw(x)={x+2wx<0xx≥0 T2U_w(x)=\begin{cases} x+2^w & x<0 \\ x & x\geq0 \\ \end{cases} T2Uw(x)={x+2wxx<0x0

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

    T2Uw(x)T2U_w(x)T2Uw(x):转换后的无符号数

    www:二进制数的位数

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

U2Tw(u)={uu≤TMaxwu−2wu>TMaxw U2T_w(u)=\begin{cases} u & u\leq TMax_w \\ u-2^w & u>TMax_w \\ \end{cases} U2Tw(u)={uu2wuTMaxwu>TMaxw

uuu:无符号数(u≤TMaxwu\leq TMax_wuTMaxw即最高位数字0,u>TMaxwu>TMax_wu>TMaxw即最高位数字是1)

U2Tw(u)U2T_w(u)U2Tw(u):转换后的有符号数

www:二进制数的位数

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)被转换为无符号数,其十进制的值就变成了232−12^{32}-12321

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−2wc=a+b-2^wc=a+b2w ,其中www为二进制数的位数;

​ 例如:0(0000 0000) = 255(1111 1111) + 1(0000 0001) - 282^828

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 的和大于等于 2w−12^{w−1}2w1 时,发生正溢出,此时,得到的结果会减去 2w2^w2w
  • 当 x 加 y 的和小于 −2w−1−2^{w−1}2w1 时,发生负溢出,此时,得到的结果会加上 2w2^w2w

10.3 加法逆元(相反数)

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

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

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

TminwTmin_wTminw:w位有符号数的最小值
TMinw+TMinw=−2w−1+(−2w−1)=−2w TMin_w+TMin_w=-2^{w-1}+(-2^{w-1})=-2^w TMinw+TMinw=2w1+(2w1)=2w

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

TMinw+TMinw的逆元=−2w+2w=0因此TMinw逆元是其本身 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×29\times29×2

又例如:x×14=x⋅(24−21)=(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,需要先加上偏置(偏执量为2k−12^k-12k1)再进行算术右移
    • 当补码大于0,可以直接进行算术右移

    除法结果总是向0舍入,如3.14→33.14\rightarrow33.1433.14→33.14\rightarrow33.143

    11 浮点数

    11.1 IEEE浮点数表示

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

    sss:符号位; EEE:阶码; MMM:尾数

    例如: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 舍入

  • 向偶舍入
  • 向零舍入
  • 向下舍入
  • 向上舍入
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值