IEEE Standard 754(浮点数二进制表示)以及浮点数运算
IEEE Standard 754(浮点数二进制表示)以及浮点数运算
一、什么是IEEE 754标准?
IEEE 标准 754成立于 1985 年,是浮点运算的统一标准。它统一了之前许多特殊的格式,便于CPU设计,受所有主流 CPU 支持。IEEE标准的特性包括:
- 由数字问题驱动
- 对圆角、溢流、下溢有良好的处理标准
- 在定义标准时,数值分析人员比硬件设计人员占主导地位(硬件较为难以驱动)
二、如何使用IEEE 754标准
这里我们主要讨论单精度(float in C)和双精度(double in C)的表示。
计算式:
- s:符号位
- m:小数位 M:编码尾数
- e:指数位 E:阶码
m,e 的得出 要考察E的具体形式得出:具体分为规格化、非规格化、特殊三种情况。
(1)规格化的值
E中既非全0,又非全1
e=|E|-bias ----bias=2^(k-1)-1
k的得出:k为E的位数(float时k=8,double时k=11;bias分别为127,1023)
m=|1.M| ---标准规定此时小数点左侧的隐含位为1,多获得一位存储空间
(2)非规格化的值
E中为全0,则N为非规格化的值
e=1-bias
m=|0.M|
(3)特殊数值
E中全为1,M中全为0,表示无穷大->(S为0则正无穷,S为1则负无穷)
若M中不全为0,表示NAN,非合法初始化
三种数字的大小可视化:
三、IEEE示例:以8位为例的“Tiny Example”
(注:字母与上文或有冲突,请理解含义)
图中展示了仅为正数的情况,把不同种类的浮点数用不同颜色分开(尤其注意这里k的大小和各个元素是怎么计算出的),可以很清楚的看到这种规划方式将denorm(非规格化),norm(规格化)丝滑过渡,保证刻度上的每个值都能够取到。
p.s.到这里你或许不记得这些数是怎么规定的,没关系,往上翻翻看(doge)
四、舍入
舍入:因为表示方法限制了浮点数的范围和精度,所以浮点运算只能近似地计算。因此,对于值 x,我们想用一种系统的方式,能够找到“最接近的”x',它可以用浮点形式表示出来。
如图展示了四种舍入方式,向0舍入,向正无穷舍入,向负无穷舍入,向最近偶数舍入。
前三种方式容易理解,而向偶数舍入初看上去好像是个相当随意的目标。有什么理由偏向取偶数呢?为什么不始终把位于两个可表示的值中间的值都向上舍入呢?
使用这种方法的一个问题就是很容易假想到这样的情景:这种方法舍入一组数值,会在计算这些值的平均数中引入统计偏差。我们采用这种方式舍入得到的一组数的平均值将比这些数本身的平均值略高一些。
相反,如果我们总是把两个可表示值中间的数字向下舍入,那么舍入后的一组数的平均值将比这些数本身的平均值略低一些。向偶数舍入在大多数现实情况中避免了这种统计偏差。这样有一半的时间向上舍入,而有一半的时间向下舍入。
相似地,向偶数舍入法可运用在二进制小数上。我们将末位为0的数称为“偶数”,末位为1的数称为“奇数”,一般来说,只有对形如XXXX···.Y···YYY1000··· 的二进制模式才有效,整数部分由X填充,最右侧的Y是舍入后的最后一位。只有这种位模式表示两个可能的结果正中间的值。例如,考虑舍入值到最近四分之一的问题(也就是二进制小数点右边两位)。我们将10.00011向下舍入到10.00 ; 10.00110向上舍入到10.01,因为这些值不是两个可能值的正中间值。我们将10.11100向上舍入到11.00,而10.10100向下舍入到10.10,因为这些值是两个可能值的中间值,并且我们倾向使最低有效位为0。
五、浮点计算
1.浮点数的加减运算
零操作数的判断(节省时间)
- 若加数或被加数其中有 0,则等于其中不为0 的那个数;若全为 0 则等于 0
- 若被减数为 0,则等于减数的相反数 ;若减数为 0,则等于被减数
对阶操作
以阶码加大(绝对值)的为标准,阶码较小的向较大的对齐
(为什么要对阶)
计算机中的浮点数定点表示时小数点的位置是固定的,在小数的数值位的最前面,为了避免阶码较大的浮点数尾数左移导致最高位的丢失
例:(3.14+1e10)-1e10 求值得到0.0
2.浮点数的乘法运算
如果M>=2,将M右移,增大E
如果E超出范围,溢出处理(表示为正无穷或负无穷)(当然,在您的程序中可以设计并抛出这种异常)
M估值至二进制可表示
3.浮点数的除法运算
除数为零的情况
- IEEE 754标准:在 IEEE 754 标准下,浮点数除数为零会导致以下两种情况之一:
- 被除数为零:结果是非数值(NaN),表示该操作是“无效的”。
- 被除数不为零:结果是正无穷大(
+Inf
)或负无穷大(
-Inf
),具体取决于被除数的符号。
(同样地,您也可以通过程序设计抛出这类异常)
常规情况,阶码直接相减,frac部分直接相除
运算技巧:二进制长除法
将尾数的除法过程视为二进制长除法。
例如,被除数是 dividend,除数是 divisor:
将 dividend 和 divisor 调整为整数形式(通过移动小数点),以简化除法运算。例如,如果 dividend 是 1.101 × 2^3,可以将其视为 1101.0 × 2^0,但需要注意阶码的调整。
使用二进制长除法计算 quotient = dividend ÷ divisor。
确保 quotient 符合规格化的尾数格式,必要时进行左移或右移操作。
精度问题:在尾数运算过程中,需要考虑舍入问题。如果尾数的精度超过浮点数格式的限制,需要对结果进行舍入处理,以符合标准的浮点数尾数精度要求。
示例:计算1010 ÷ 11(即 10 ÷ 3)
- 转换为二进制:
- 被除数:1010
- 除数:11
- 开始除法:
- 从被除数的最高位开始处理。初始时除数是11(二进制),被除数前两位是10(二进制10)。
- 11 > 10,所以商的第一位是0。
- 被除数的下一位是1,现在的前三位是101。
- 11 ≤ 101,商的下一位是1。
- 进行减法运算:101 - 11 × 1 = 101 - 11 = 10(二进制)。
- 将被除数的下一位(0)拉下来,形成新的被除数 100。
- 11 ≤ 100,商的下一位是1。
- 进行减法运算:100 - 11 × 1 = 100 - 11 = 01(二进制)。
- 现在,被除数处理完毕,余数为01(二进制1)。
- 结果:
- 商:11(二进制),即3
- 余数:01(二进制),即1
- 验证:3 × 3 + 1 = 10(十进制),正确。
六、C中的浮点数
float:单精度 double:双精度
C中的类型转换
float/double->int:
小数部分直接截断(向0舍入)
当超范围时(浮点数表示的范围较大)或未定义时通常赋值为TMin
int->double:
当int二进制位数小于53时,无精度损失
int->float:
将根据舍入模式进行舍入
参考:《深入理解计算机系统》(原书第三版)--Randal E.Bryant and David R.O'Hallaron