前言:一文掌握计算机必备基础之数据表示及运算(下)
3 二进制数据的运算
3.1 定点数与浮点数
原码、反码和补码可以表示正负整数和纯小数,对于整数和小数部分兼有的数值却没有办法表示。为了合理表示,我们引入定点数和浮点数的概念
3.1.1 定点数的表示方法
- 小数点固定在某个位置的数被称为定点数
- 定点数的表示方法
对于既有整数又有小数的原始数据,需要设定一个合适的比例因子,数据按比例因子缩小成定点小数或扩大成定点整数再参加运算,结果输出时再按比例折算成实际值。
举例: 计算 11.01 + 10.01
选择比例因子 0.01,可将两操作数变换成 0.1101 + 0.1001,但 0.1101 + 0.1001 = 1.0110,运算结果不是纯小数,出现了机器数不能表示的数,即出现了正溢出。
如果选择比例因子
=0.001,可将两操作数变换为 0.01101+0.01001 则运算结果 0.01101+0.01001=0.10110 为正常结果。将 0.10110 除以比例因子
,可得到正确结果 101.10。
3.1.2 浮点数的表示方法
引进浮点数的原因如下
- 计算机处理的很大程度上不是纯小数或纯整数
- 数据范围大,定点数难以表达
- 浮点数的表示格式
先复习一下读书时代学过的科学计数法:
浮点数的表示方法与科学计数法类似,如下:
需要注意的是浮点数规定尾数必须使用小数,如
上面两个浮点数表现形式在计算机中是这样存储的(规定尾数数值位为8位)
浮点数的表示范围 假设阶码数值取m位,尾数取 n 位(尾数只能为小数):
- 阶码能够表示的最大值:
- 算上负数,可得阶码表示范围:
- 尾数能够表示的最大值:
- 尾数能够表示的最小值:
- 尾数能够表示范围有:
- 阶码能够表示的最大值:
结合阶码和尾数即可得浮点数的表示范围,不在此范围内的则溢出,分上溢和下溢,(上溢因为数值太大,下溢因为数值太小)
浮点数的精度
- 单精度浮点数:使用4字节、32位来表达浮点数(float)
- 双精度浮点数:使用8字节、64位来表达浮点数(double)
- 浮点数的规格化
- 尾数规定使用纯小数
- 尾数最高位(小数点后一位)必须是 1
举个例子
+ 11.0101 = 0.110101*2^10
- 11.0101 = 0.0110101*2^11 //尾数最高位为0,不符合
- 11.0101 = 0.00110101*2^100 //尾数最高位为0,不符合
- 11.0101 = 1.10101*2^1 //尾数不是纯小数,不符合
来做两道题检测一下学习效果
- 例子1:设浮点数字长为16位,阶码为5位,尾数为11位,将十进制数13/128表示为二进制浮点数。
- 原码 = 反码 = 补码: x = 0.0001101000
- 浮点数规格化:
- 例子2:设浮点数字长为16位,阶码为5位,尾数为11位,将十进制数-54表示二进制浮点数
- 原码:x = 1,110110
- 浮点数规格化:
3.1.3 定点数和浮点数的对比
- 当定点数与浮点数位数相同时,浮点数表示的范围更大
- 当浮点数尾数为规格化数时,浮点数的精度更高
- 浮点数运算包含阶码和尾数,浮点数的运算更为复杂
- 浮点数在数的表示范围、精度、溢出处理、编程等方面均优于定点数
- 浮点数在运算规则、运算速度、硬件成本方面不如定点数
3.2 定点数的加减法运算
- 整数加法: A[补]+B[补] = [A+B][补](
)
- 小数加法: A[补]+B[补] = [A+B][补](
)
运算的时候,数值位与符号位一同运算,并将符号位产生的进位自然丢掉
- 🌰 例子1:A = -110010, B = 001101,求 A+B
- 🌰 例子2:A=-0.1010010,B=0.0110100,求A+B
- 🌰 例子3:A = -10010000,B = -01010000,求 A+B
- 🌰 例子4:A= -10010000,B= -11010000,求 A+B
在 🌰 例子4中,我们发现一个很奇怪的问题,A和B都是负数,它们相加结果却为正数,这是为什么呢?
因为A和B都是用8位数字来表示,但是A+B的结果用8位存不下来,于是发生了溢出。
如何判断溢出?
- 双符号位判断法
- 单符号位表示变成双符号位:0=>00,1=>11
- 双符号位产生的进位丢弃
- 结果的双符号位不同则表示溢出
用这种方法再来看下 🌰 例子4:A = -10010000, B = -11010000,求 A + B
再用这个方法看下 🌰 例子3:A = -10010000, B = -01010000,求 A + B
前面提到的这么多都是关于整数和小数的加法运算,现在来讲整数和小数的减法运算
整数减法: A[补] - B[补] = A + (-B)[补](
)
小数减法: A[补] - B[补] = A + (-B)[补](mod2)
- B[补] 等于 B[补] 连同符号位按位取反,末位加一
- 如B[补]=1,0010101, - B[补]=0,1101011
- 例子5:A=11001000,B=-00110100, 求 A-B
- A[补] = A[原] = 0,11001000
- B[补] = 1,11001100,(-B)[补] = 0,00110100
- A[补] - B[补] = A+(-B)[补]=0,11111100
- A - B = 111111100
3.3 浮点数的加减法运算
浮点数的加减法运算较之前要麻烦一些,主要有以下步骤
- 对阶
- 尾数求和
- 尾数规格化
- 舍入
- 溢出判断
对阶
- 浮点数尾数运算简单
- 浮点数位数实际小数位与阶码有关
- 阶码按小阶看齐大阶的原则
对阶的目的是使得两个浮点数阶码一致,使得尾数可以进行运算
接下来看个例子:,
,它们如果要进行加减运算,首先要进行下面对阶操作
尾数求和
- 使用补码进行运算
- 减法运算转化为加法运算: A - B = A + ( - B)
x[原] = 00.0011, x[补]=00.0011
y[原] = 11.1010, y[补]=11.0110
尾数求和完成以后,接下来要进行尾数规格化
- 尾数规格化
- 对补码进行规格化需要判断两种情况:S>0 和 S<0
前面尾数求和得到 S = (x+y)[补] = 11.1001
利用上述的公式进行规格化处理后, S = (x+y)[补] = 11.0010
通过补码求得其原码为 (x+y)[原] = -0.1110,带上阶码最终结果为:
尾数规格化(右移)
- 一般情况下是左移
- 双符号不一致下需要右移(定点运算的溢出情况)
- 右移的话需要进行舍入操作
舍入
- “0舍1入”法(二进制的四舍五入)
假设 S[补] = 10.10110111,可知符号位为 10,符号位不一致则需要进行右移的操作,右移之后可得 S[补] = 11.010110111
最后一位的1没有办法存储,需要进行舍入操作(0舍1入)
浮点数运算同样需要考虑溢出的情况,现在来讲解溢出判断
溢出判断
- 定点运算双符号位不一致为溢出
- 浮点运算尾数双符号位不一致不算溢出,因为尾数双符号位可以进行右移
- 浮点运算主要通过阶码的双符号位判断是否溢出
例子:
,假设阶码4位,尾数8位,计算x+y
在进行规格化的时候,移位了记得阶码也要相应改变
最后来张脑图总结一下浮点数加减法运算的全流程
3.4 浮点数的乘除法运算
下图是浮点数乘除法运算的各个流程
- 乘法:阶码相加,尾数求积
- 除法:阶码相减,尾数求商
- 🌰 例子:
,假设阶码4位,尾数8位,计算 x*y
小结
知识点基本都是公式,繁多易忘,温故而知新。看完还想找题目再练练的朋友可以私信我,我这里有几十道附带答案的相关计算题可供练习。
感谢阅读
本文使用 mdnice 排版