计算机系统基础(一)笔记——Week2 数据的表示和存储

本文最后更新于:2024年5月25日 凌晨

Week2 数据的表示和存储

2.1 数制和编码

信息的二进制编码

机器级数据分两类:

  • 数值数据:无符号整数、带符号整数、浮点数(实数)
  • 非数值数据:逻辑数(包括位串)、西文字符、汉字

计算机内部均使用二进制编码

真值和机器数:

  • 机器数:用0/1编码的计算机内部的0/1序列
  • 真值:真正的值

如unsigned short x=127,机器数是0000 0000 0111 1111

数值数据的表示

确定数值数据首先要确定三个要素:

  1. 进位计数制
    • 十/二/十六/八进制及其转换
  2. 定/浮点表示
    • 定点整数、定点小数
    • 浮点数
  3. 如何用二进制编码(解决正负号)
    • 原码、补码、反码、移码

定点数和浮点数

Q:如何表示数值数据中的小数点?

通过约定小数点的位置来表示

  1. 小数点位置约定在固定位置的数称为定点数
  2. 小数点位置约定为可浮动的数称为浮点数

定点小数用来表示浮点数的尾数

定点整数用来表示整数,分为带符号/无符号整数

💡 任何实数:X=(1)s×M×REX={(-1)^s}\times M \times R^E,其中s{0,1}s\in \{0,1\},用来决定符号;M是一个二进制定点小数(尾数);E是一个二进制定点整数(阶);R是基数,为2/4/16等。计算机只用这三个数,就确定X,这称为浮点数

2.2 定点数的编码表示

原码表示

0→0000,-0→1000

1→0001,-1→1001

容易理解,但是:

  • 0的表示不唯一
  • 加减运算方式不统一
  • 需额外对符号位处理,不利于硬件设计
  • 当a<b时,实现a-b困难

50年代开始,整数部分用补码表示,但尾数用原码定点小数表示

移码表示

即将每一个数值加上一个偏置常数(Excess/bias)

通常,当编码位数为n时,bias取2(n1)or2(n1)12^{(n-1)}or2^{(n-1)}-1

比如:n=4,bias=8

-8→0000B,-7→0001B,7→1111B

💡 当bias=2^(n-1)时,移码和补码仅第一位不同

移码用来表示浮点数的阶

  • 便于加减运算时的对阶操作(比大小)

    1.01×21+1.11×231.01\times 2^{-1} +1.11 \times 2^3 补码:111(-1)< 011(3)

    1.01×21+4+1.11×23+41.01\times 2^{-1+4} +1.11 \times 2^{3+4} 移码:011(3)<111(7)

补码表示(模运算)

举个例子:模12系统中,-4=8,-3=9,-5=7……

  1. 一个负数的补码等于模 减去 该负数的绝对值

  2. 对于模n,数a减去小于n的另一数字b,可以用a加上 -b的补码来代替

    10-4=10+(12-4)=10+8=6(mod12)

  3. 8位二进制加法器模运算系统:

    0111 1111-0100 0000=0111 1111+(2^8-0100 0000)

    =0111 1111+1100 0000=1 0011 1111(mod2^8)=0011 1111

[x]补=2^n+x(mod 2^n)举个例子:[-1000]补=10000-1000=01000=1000

补码和真值的对应关系

  • 特殊数的补码

    [2n1]=2n2n1=10...0(n10)(mod2n)[-2^{n-1}]_{补}=2^n-2^{n-1}=10...0(n-1个0)(mod 2^{n})

    [1]=2n0...01=11...1(n1)(mod2n)[-1]_{补}=2^{n}-0...01=11...1(n个1)(mod 2^n)

    💡 32位机器中,int、short、char型数据的机器数各占32、16、8位

  • 变形补码

    双符号位,用来存放可能溢出的中间结果

  • 真值求补码

    正数补码是其本身

    负数补码:各位取反,末位加1(从右往左的遇到的第一个1前面都取反)

  • 补码求真值

    A=an1an2...a1a0A_{补}=a_{n-1}a_{n-2}...a_1a_0

    A=an12n1+an22n2+...+a020A=-a_{n-1}2^{n-1}+a_{n-2}2^{n-2}+...+a_{0}2^{0}

    例子:1101 0110的真值:27+26+24+22+2=42-2^7+2^6+2^4+2^2+2=-42

    简便求法:

    符号为0,则为正数,数值部分相同

    符号为1,则为负数,数值各位取反,末位加1(从右往左的遇到的第一个1前面都取反)

2.3 C语言中的整数

无符号整数

  • 机器中的位排列有两种:高到低从左到右/从右到左

    可以用LSB(Least Significant Bit)和MSB标识最低有效位和最高有效位,进行区分

    一般高到低采用从左往右

一般全是正数运算采用无符号整数(编码中没有符号位)

带符号整数

用MSB表示数符

用补码表示带符号整数

C语言中无/带符号整数

(unsigned) int/short/long

常在数后面加上’U’/’u’表示无符号数

如果同时有unsigned和signed,C编译器全部转换为unsigned

例子:32位用补码表示的机器上执行以下表达式

32位说明最大整数为2^31-1=2147483648-1=2147483647

表达式 结果 说明
0==0U 1 00…0B=00…0B
-1<0 1 11…11B(-1)<00…00B(0)
-1<0U 0 11…11B(2^32-1)>00…00B(0)
2147483647>-2147483647-1 1 011…1B(2^31-1)>100…0B(-2^31)
2147483647U>-2147483647-1 0 011…1B(2^31-1)>100…0B(2^31)
2147483647>(int)2147483648U 1 011…1B(2^31-1)>100…0B(-2^31)
-1>-2 1 11…1B(-1)>11…10B(-2)
(unsigned)-1>-2 1 11…1B(2^32-1)>11…10B(2^32-2)

编译器处理常量默认的范围

C90:

0~2^31-1 int
2^31~2^32-1 unsigned int
2^32~2^63-1 long long
2^63~2^64-1 unsigned long long

C99:

0~2^31-1 int
2^31~2^63-1 long long
2^63~2^64-1 unsigned long long

一些例子:

  • 某些32位系统上,-2147483648<2147483647==false

    编译器先将-号和2147483648分开,先确定2147483648的类型,C90下解释为unsigned int类型,而右边解释为带符号数,故处理为无符号类型。由于10…0B大于01…1B,结果为false

  • int i=-2147483648,则i<2147483647==true

    按int型整数比较,结果为true

  • -2147483647-1<2147483647==true

    -号分开处理,而2147483647=2^31-1,处理为int类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.h>
int main()
{
int x=-1;
unsigned u=2147483648;
printf("x = %u = %d\\n",x,x);
printf("u = %u = %d\\n",u,u);
if(-2147483648<2147483647)
printf("-2147483648 < 2147483647 == true\\n");
else
printf("-2147483648 < 2147483647 == false\\n");

if(-2147483648-1<2147483647)
printf("-2147483648-1 < 2147483647\\n");
else if(-2147483648-1==2147483647)
printf("-2147483648-1 == 2147483647\\n");
else
printf("-2147483648-1 > 2147483647\\n");
return 0;
}

在ISO C90下,结果为

1
2
3
4
x = 4294967295 = -1
u = 2147483648 = -2147483648
-2147483648 < 2147483647 == false
-2147483648-1 == 2147483647

2.4浮点数的编码表示

科学计数法与浮点数

科学计数法表示:6.02×10216.02\times10^{21},二进制实数表示:1.101×2101.101\times2^{-10}

浮点数的表示范围

image-20240525000808914

IEEE 754标准规格化数表示

规格化数:+/1.xxxxxtwo×2Exponent+/-1.xxxxx_{two}\times2^{Exponent}(小数点前总是1,故可隐含表示)

  • 单精度

    S Exponent Significand
    1 bit 8 bits 23 bits
    • Sign bit:1为负数,0为正数

    • Exponent:范围为移码0000 0001-1111 1110(-126到127),全0和全1表示特殊值

      移码中的偏置常数:单精度为127,双精度为1023

    • Significand:规格化尾数最高位总是1,所以隐含表示,省1位

      单精度:1+23bits 双精度:1+52bits

    SP:(1)S×(1+Significand)×2Exponent127(-1)^S\times(1+Significand)\times 2^{Exponent-127}

    DP:(1)S×(1+Significand)×2Exponent1023(-1)^S\times(1+Significand)\times 2^{Exponent-1023}

  • 举个例子:float型变量x的机器数是BEE00000H,求x的值?

    BEE00000H=1011 1110 1110 0000 0000 0000 0000 0000

    =1—01111101—11000000000000000000000

    S:1,负数

    Exponent:移码125 原码-2

    Significand:1+1×21+1×22+0×23+...=1+0.5+0.25=1.751+1\times 2^{-1}+1\times2^{-2}+0\times2^{-3}+...=1+0.5+0.25=1.75

    SP:1.75×22=0.4375-1.75\times2^{-2}=-0.4375

  • 举个例子:float型变量x=-12.75,求机器数?

    12.75=1100.11B=1.10011B×23-12.75=-1100.11B=-1.10011B\times 2^3

    S:1

    Exponent:原码3 移码130=1000 0010

    Significand:1001 1000 0000 0000 0000 000

    PS:1—1000 0010—1001 1000 0000 0000 0000 000=1100 0001 0100 1100 0000 0000 0000 0 000=C14C0000H

IEEE 754标准特殊数表示

  • 0的表示

    +0:0 00000000 00000000000000000000000

    -0: 1 00000000 00000000000000000000000

  • +/+\infty/-\infty的表示

    💡 浮点数除0的结果是+/+/-\infty,而不是溢出异常

    ++\infty:0 11111111 00000000000000000000000

    -\infty:1 11111111 00000000000000000000000

  • “非数”的表示

    即NAN(Not a number)

    Exponent=255,Significand=nonzero

    举个例子:0/0=NaN,sqrt(-4.0)=NaN

总结以上内容:

Exponent Significand 表示
0 0 正负0
0 nonzero 非规格化数
1-254 任意小数点前隐含1 规格化数
255 0 正负无穷
255 nonzero NaN

规格化数的范围:1.0..0×21261.1..1×21261.0..0\times2^{-126}-1.1..1\times2^{-126}

非规格化数的范围:0.0..0×21260.1..1×2126(1)s×0.xx...x×21260.0..0\times2^{-126}-0.1..1\times2^{-126}\rightarrow (-1)^s\times0.xx...x\times2^{-126}

💡 当输入一个不可表示数时,机器会将其转换为最近的可表示数

2.5 非数值数据的编码表示

逻辑数据的编码表示

逻辑值:关系表达式

表示:用一位表示逻辑值,N位串表示N个逻辑数据

运算:按位进行运算

识别:计算机靠指令识别逻辑数据

西文字符的编码表示

表示: 常用7位ASCII码表示

常见ASCII码:0~9 ⇒ 011 0000~011 1001

汉字及国际字符的编码表示

编码形式:

  1. 输入码(拼音、微软输入法等):对汉字用相应按键进行编码表示,用于输入
  2. 内码:用于在系统中进行存储、查找、传送等
  3. 字模点阵或轮廓描述:描述汉字轮廓,用于显示/打印

多媒体信息的表示

图形由构成图形的直线或曲线的坐标点及控制点来描述/数值数据

2.6 数据宽度和存储容量的信息

数据的基本宽度

bit(比特)→Byte(字节)→word(字)

  • 现代计算机中,存储器按字节编址

💡 字\not =字长,字长指CPU内部的数据流经部件 的宽度

小k通常表示1000,大K通常表示1024

2.7 数据存储时的字节排列

对于一个数据比如int型变量x=-10,x的存放地址为100,机器数是FFFFFFF6H,占4个单元

  1. 变量的地址是最小地址,即x存放在100#~103#

  2. 多个字节在存储单元中如何存放?

    大端/小端方式

举个例子:int i=-65535,存放在100号单元(100~103),访问100号单元取出i时,要清楚其如何存放的。

65535=2161=00...0151...11665535=2^{16}-1=0\underbrace{0...0}*{15}\underbrace{1...1}*{16}

65535=11...1150...0151=FFFF0001H-65535_{补}=1\underbrace{1...1}*{15}\underbrace{0...0}*{15}1=FFFF0001H

FF FF 00 01
小端 103 102 101 100
MSB LSB
大端 100 101 102 103
  • 大端:MSB所在的地址是数的地址

    IBM 360/370,Motorola 68k,MIPS,Sparc,HP PA

  • 小端:LSB所在的地址是数的地址

    Intel 80*86,DEC VAX

检测系统的字节顺序

union的存放顺序是所有成员从低地址开始。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>
int main()
{
union NUM{
int a;
char b;
}num;
num.a=0x12345678;
if(num.b==0x12)
printf("大端存放\\n");
else
printf("小端存放\\n");
printf("num.b = 0x%x\\n",num.b);
return 0;
}

举个例子:

以下是由反汇编器生成的针对IA-32处理器的机器级代码表示文本

1
80483d2: 89 85 a0 fe ff ff   mov %eax,0xfffffea0 (%ebp)

其中80483d2是指令地址,89 85 a0 fe ff ff是机器指令,mov %eax,0xfffffea0 (%ebp)是汇编指令,0xfffffea0是立即数

  • 请问0xfffffea0的值和存放地址?IA-32是大端还是小端方式?

    存放地址为0x80483d4,值为=-101100000B=-352,小端方式

字节交换问题

大小端转换时涉及到字节顺序问题


计算机系统基础(一)笔记——Week2 数据的表示和存储
http://kcollision.github.io/2024/047f128493.html
作者
collision
更新于
2024年5月25日
许可协议