浮点数运算
浮点数加减法
步骤:
- 检查0:运算双方是否有一方等于0?
- 对齐有效值:阶码向大阶对齐,也就是需要将阶码小的那个数的阶码增加m位,直到与阶码大的数的阶码相同。每次阶码+1就要把尾数右移1位。
- 加或减有效值:进行尾数的运算。需要带上原来的隐藏位
- 规格化结果:最后得出的结果需要转变为规格化数的形式。如果小于1就要左归(尾数左移,阶码减少);大于等于2就要右规(尾数右移,阶码增加)
乘法和除法
计算步骤:
- 检查0:运算双方是否有0存在?需要针对不同情况进行不同处理
- 阶码相加减:两个数的乘除就相当于对阶码相加减。注意:使用移码进行阶码的加减时需要额外加减一次偏置常数,如果是乘法,最后需要减去偏置常数127;如果是除法则加上127。
- 尾数相乘除:把尾数看出整数,执行整数的乘除,结果也用整数表示
- 规格化结果:和加减法一样,将结果表示为规格化数的形式。
溢出
阶码操作过程中可能会发生溢出:
- 上溢:超过11111110(127)
- 下溢:小于00000001(-126)
有效值可能也会发生溢出:
- 上溢:两个数相加可能导致最高位的进位。一般可以右移重新对其
- 下溢:最右端数字在对其过程中被移出,此时需要某种形式的四舍五入(右规)操作
IEEE754中的五种异常
- 无效运算:结果为NaN,一般为负无穷加正无穷、0/0等等
- 有限值除以0:正负无穷大
加法
减法示例:
首先确定两个阶码的差值,为1,所以需要对-0.4375的尾数右移,变为了0 1110…0,注意前面的隐藏位变为了0.
然后就对阶码进行相加(负负得正,变为了加法),得到最后的结果。省去一个隐藏位,就得到了结果。
示例2:
这里加一个负数。还是先确定阶码的差值,为1,把-0.4375的尾数右移1位。由于它是一个负数,执行尾数相加的时候需要加尾数的相反数(所有的位取反+1).
乘法
阶码相加,尾数相乘。在尾数相乘的时候都要带上隐藏位。然后乘完以后还需要根据乘积的高两位做出不同的处理。如果高两位为01则无需处理;为10或11就右规一位(不处理00是因为IEEE 754标准中,只有右规)
符号位就是两个符号位的异或,尾数高两位判断时01因此不需要操作,直接取高两位之后的23为写入尾数中,舍去乘积最后的23个0
除法
与乘法相似,先判断除数和被除数的特殊值,然后阶码相减,尾数相除,对最后结果的高两位判断,如果为01则左归一位,为10或11则无需处理
示例:
精度考虑
舍入位
为了确保结果的精确度,需要在中间结果的尾数中都使用附加位。
- 保护位:在尾数右边的位,左归时被移到尾数中
- 舍入位:在保护位右边的位,作为舍入的依据
舍入:
- 就近舍入(默认方式):结果被舍入成最近的可表示的数(非中间值:0舍1入;中间值:强制结果为偶数)
- 朝+∞舍入:结果果朝正无穷大方向向上舍入
- 朝-∞舍入:结果果朝负无穷大方向向上舍入
- 朝 0 舍入:结果朝 0 舍入,
数据类型:
- int:整数,范围为-2147483648到2147483647
- float:单精度浮点数,1+8+23
- double:双精度浮点数,1+11+52
其中,int变成float、float变成int都会失去精度,而double可以完整的表示所有的int和float值。
牢记IEEE754不完美
- 尽量简化运算步骤
- 低精度和一个高精度在运算时,低精度的数变成了高精度(补0)
- 运算后注意舍入
- 运算时,警惕二进制不能精确表示的数
- 运算时,警惕