2.1数据的表示和运算
2026-03-15补充从源程序到可执行文件的流程:计算机无法直接理解高级语言程序,通常需要翻译程序
1.汇编程序:汇编器:将汇编语言(也就是所谓的RTL那些语句)翻译为机器语言
2:解释程序:解释器:将源语句中的程序按照执行顺序逐条翻译成机器指令并立即执行,例如python语言
3.编译程序:编译器:将高级语言程序翻译成汇编语言或机器语言程序
编译型语言(如C)**:
1. 你的C代码经过**编译器**,变成了**ARM汇编**.
2. 汇编器再把它变成**机器码**(即CPU能直接执行的 `0` 和 `1`).
3. CPU最终执行的是这个**静态的,已经翻译好的机器码文件**.
常见语言:C,C++,Go,Rust(和之前讨论的ARM汇编,链接的过程紧密相关)
区别:
- **解释型语言(如Python)**:
1. 你的Python代码(`.py` 文件)还是文本.
2. 当你运行时,**解释器**(它本身是一个用C写好的,已经编译成机器码的程序)会**逐行读取你的代码**.
3. 解释器分析这行代码要做什么(比如加法),然后**调用底层已经编译好的C函数**去执行这个操作.
4. 对CPU来说,它其实一直在执行**解释器这个程序的机器码**,而你的Python代码只是喂给这个程序的数据.
常见语言:Python,JavaScript,Ruby(浏览器里的JS引擎就是解释器).
一.进制
1.数制与编码
机器字:反映计算机能直接处理的二进制位数,决定了计算机的运算精度
指令字:指令中包含的二进制序列
存储字:存储单元中保存的二进制序列
r进制到十进制:各数码位按照权乘积之和,即是幂的0次,1次,2次这样按顺序
其中十六进制前面会加0x
二:编码表示
真数:符合人类认知的数
机器数:把真数转换成相应的01序列
加减可能产生进位或者借位,两个n位相乘将产生一个2n位的积
1.定点数:一个n位字可以表示从0到2的n次个可能的值,表示负数的方法是他的最高位表示符号,0表示正数,1表示负数
2:n位有符号的表示范围为-(2的n-1次-1)到(2的n减一次-1)之间的整数
定点数的运算:
如何实现|简要解释
在这里简单的解释一下,下下一个标题会较深入解释 :)
设一负数为 X,设 n 为 |X| 的二进制位数.接下来为 X 找一个对应的正数.
原码:对 |X| 加上一个最高位 1 代表符号位,表示 X 为一负数.
移码:对 X 加上一个常数 2^(n-1),把 X 本身转换为一个正数,再以正数编码.
反码:对 X 取 2^n-1 的模(按位取反,方便运算),用模的结果(一个正数)表示 X .
补码:对 X 取 2^n 的模(即按位取反再加 1 ),用模的结果(一个正数)表示 X .
原码:
没什么好解释的,加上一个最高位来表示此数为负数.
移码:
也没什么好解释的,加上一个被称为偏置常数( bias )的数 2^(n-1),使负数 X 本身变为正数.
反码:
实际上机器是对 |X| 按位取反,所以机器做此操作还是相当快的.
用数学语言表达就是 X 取 2^n-1 的模.
即用一个全部是1的n-1位的二进制数 减去 |X| ,得到 X 的反码表示.
所以 X 的反码加 |X| 就是一个全部为1的n-1位二进制数.
例:
[-5] = ( 2^4-1 ) - | 0101 | = 1010也就是5的码0101相反
[-7] = ( 2^4-1 ) - | 0111 | = 1000也就是7的码0111相反
补码:
补码这样做的原因是二进制的加减可直接运算,运算的结果和真值的运算结果相同.
机器对 |X| 按位取反然后加 1.
数学表达为 X 对 2^n 取模.
即用 2^n 减去 |X| ,得到 X 的补码表示.
所以 X 的补码加 |X| 就是一个 2^n 二进制数,由于最高位被计算机截断,结果为 0.
例:
[-5] = 2^4 - |0101| = 1011
[-7] = 2^4 - |0111| = 1001
真值和编码之间的转换
除移码外的编码,最高位都可表示此数的正负情况.(即 0正1负)
移码较为简单,故不列出.
原码:
由一个数符位和数值部分组成.
数学公式如下
真值转为编码编码转为真值正数直接转换直接转换负数绝对值转换后,设最高位为1数值部分直接转换,添上负号
注意编码转为真值时,先按最高位判断正负.
反码:
数学公式如下
真值转为编码编码转为真值正数直接转换直接转换负数绝对值按位取反按位取反再转换,添上负号
注意编码转为真值时,先按最高位判断正负.
正数的反码是自己的二进制码反过来,负数需要先取绝对值再求反码,如果是编码格式求反码则,最高位保留,后面几位取反加上最高位的符号即可
补码:
在补码的转换中,我们可以按照公式求真值,也可以通过一些简单操作进行转换.
真值转为编码编码转为真值正数直接转换直接转换负数先转换为正数的补码,再从右向左,第一个1之前的个位取反,变成负的补码从右向左,第一个1之前的个位取反,变成正数的补码,再转换成真值
注意编码转为真值时,先按最高位判断正负.
正数中原码等于反码等于补码
负数的补码是先保留最高位符号位然后后7位去取反码之后再加最高位最低位加1
相加结果如果要产生了9位二进制(进位位),即发生溢出,则把它丢弃,取后8位,最前面一位放在类似ccr的进位里面,如果这样是否会产生疑问~诶这样不就加不对了吗,别担心下一章做出解答
运算:对应真值,前面不是说移码上是加上2的m次吗,为什么现在又成左移一位乘2,右移除以2,这里说的是算术运算,和后面移位的区分(看不懂看没关系看后面的小数部分就明白了)
补码还会产生溢出判断:模2补码,模4补码非常繁琐不用管
无符号二进制乘法:

三;类型转换
1. **长字长变量向短字长变量转换**(如 `int` → `short`)
- 直接将高位截断,保留低位.
- 例如:32位 `0x12345678` 赋给16位变量,结果为 `0x5678`.
2. **短字长变量向长字长变量转换**(如 `short` → `int`)
- 低位保持不变,高位根据原变量的类型进行扩展:
- 若原变量是**无符号**类型,则高位补0(**零扩展**).
- 若原变量是**有符号**类型,则高位补原数的符号位(**符号扩展**).
- 实际上,符号扩展时补的高位就是原数的符号位(0或1).
3. **有符号数与无符号数之间的转换**(相同字长)
- 机器数(二进制位模式)不变,只是解释方式不同.
- 例如:`short` 的 `0x8001` 作为有符号数是 -32767,作为无符号数是 32769.
四:接下来引入浮点数
我将引入最直观的讲解来说明这是怎么回事,尽量用口语化表示,因为真的很麻烦~
首先我们知道一个十进制带小数点的真值可以和一个二进制的32位形式来表示
那么怎么表示呢~
我们知道这个小数点表示有很多种方法,比如说0.200或者,3.141,这种计算机转换成01的二进制码怎么区分什么时候开始是小数呢,还有就是0.03和0.3这种怎么区分呢,我们得用二进制表示啊对吧,你会发现一个问题就是说一个是两位小数一个是一位小数,这样的话会出现导致位数不对的操作,也就是说比如说我们这个数据有10位,其中前8位是整数部分,后面2位表示小数,但是你这个0.03导致后面可能是3位表示小数,导致前面这个10位成了7位表示整数,那这样就会导致这个数字前面的整数很大的话他可能得用11位表示,这样就没有固定的格式了,对吧,因为你每个不同小数位数的数字用几位二进制表示都不一样,所以我们怎么办
我们的方法规定有点像这个科学计数法,接下来就引入这个IEEE754浮点数的定义(我们先看的都是原码的变换哦,补码目前不考虑)
1.首先我们定义这种表示方法的格式要求
我们只看下32位的格式就好了双精度太复杂了,其实我也不是完全清楚~也不怎么需要掌握,小数点当然也有补码运算,但基本题目不考虑~我们只讲解基础的十进制转换二进制小数,小数二进制转换十进制
首先第一条,这个尾数最高数位我们定为1,即是小数点的所在地方,然后我们需要依次左移位,每移一位表示数字的大小乘2,写成科学技术法的形式表现成阶数
注意这个移码的区别:1. 算术左移:是在"改变数值"
这就像你手里有一个数字 **3**(二进制 `0011`).
- **你做的事**:你把这个数字的二进制位向左推了一位,变成 **6**(二进制 `0110`).
- **结果**:**数值本身变了**,从 3 变成了 6(相当于乘以2).
- **结论**:**算术左移是一个"动作"**,它实实在在地改变了寄存器里存的值.你之前的理解"算术左移等于乘以2的m次方",说的就是**这个动作的结果**.
### 2. 移码:是在"重新编码"以方便存储(也就是说这是改变了他的一种格式)
这就像你手里有一个数字 **-5**(真值).
- **你做的事**:你并没有去改变 -5 的大小.你只是为了让计算机能更方便地存储和比较它,给它加了一个固定的数(比如加 8),把它变成了一个新的编码 **3**(也就是移码).
- **结果**:**数值本身没变(还是代表 -5),但用来代表它的那串二进制码变了**.
- **结论**:**移码是一个"规则"**,它定义了一种"用另一串二进制码来表示原数值"的方法.你之前提到的"加 2的m次方",说的就是**这个编码规则**.
### 3. 关键区别:对象不同
- **算术移位**:是对**寄存器里的数值**进行**运算**.结果是原数值变成了一个新数值.
- **移码**:是对**一个已有的数值**进行**编码**.结果是得到了一个代表原数值的新代码,原数值本身并没有被改变.
这里的这个类似科学计数法用的就是我们算术左移的移码,就是写成多少多少乘以2的幂次方,那个幂次就是他的阶数,所以我们要一直左规找到那个阶数,找到之后我们带公式,记得我们目前做的事是把十进制转换二进制
IEEE754上面的是他的公式,二进制默认底数是2,记得这是个二进制的形式,下面是他的格式,就是32位中,第一位到第八位,后23位的表示
拿个例子来看一下
我们找到了这个阶码这里是127,后面会提到为什么是127,加6,然后表示为8位二进制,后面这个尾数是固定的23位,加上第一位s表示符号位,最后能表示出这个短浮点数代码
这个图是不同情况的二进制格式的浮点数:也就是不同请假表示的不同类型
这时候就有小可爱问啦~诶你那个82.25用的不是127吗,为森么这里是-127,简单来说,就是这个图是把二进制转换为十进制,是反过来的方向,让我们问一下D老师,看它怎么变回来~


看懂互相转换了吗~
一点小补充(表格里"偏置 -127"的写法)
你在第一个表格里看到"阶码偏置:-127",这其实是教材里一种简略写法,意思是"解码时要减127".它和你编码时用的 `+127` 不矛盾,只是视角不同.你只要记住:**存的时候加127,取的时候减127**,就不会乱.
结果就是这样的
最后注意一下补码~很少考
补码表示的尾数规格化要求
规则:尾数的最高数值位必须与符号位相反.
- 正数(符号位 `0`):最高数值位应为 `1`.
- 负数(符号位 `1`):最高数值位应为 `0`.
合格例子
- 正数 `0.101`:符号位 `0`,最高数值位 `1`,相反.
- 负数 `1.011`(补码,表示 -0.101):符号位 `1`,最高数值位 `0`,相反