1.IEEE754标准起源
IEEE 754
由1985年电子与电气工程师协会IEEE制定,用以表示浮点数的格式
,包括0
、INF
、NAN
等,以及这些数值的浮点数运算符。标准的指定便于不同处理器之间程序的移植及研制更为复杂的数值运算程序等。
2.IEEE754规定
尾数
用原码
表示,小数点前隐含一个1
。基值
隐含为2
。阶码
用移码
表示,移码的偏移值有专门约定,n
位移码的偏移值为01111111
即。- 阶码的最大值、最小值作为
特殊标记
预留,用来标记某些异常
事件或机器零
。- 单精度、双精度;单精度扩展、双精度扩展。
3.单精度浮点数float(32bit)的表达形式
由于
尾数
存在一个隐含的1
,尾数的数值位相当于多表示了1位
,且节省了存储空间。
4.IEEE754特殊标记
IEEE754有别于一般的移码偏移量()设计,而是采用,这样设计可以使得正数多表示一个数。在8位
移码的情况下所能表示的范围是-127~128
,其中00000000
和11111111
用来做特殊标记。
- 移码为
00000000
时,表示非规格化
尾数,此时小数点前没有
隐含的1,且指数
固定为-126
。- 移码为
11111111
时,表示INF和NAN。例如尾数数值
部分全为0
,则表示INF(根据符号位决定正负),其余情况则为NAN。
5.IEEE754下溢处理
假设尾数的数值位有3位,移码有3位,现有。
若执行以下代码
if(x - y == 0)
cout << "x == y" << endl;
else
cout << "x != y" << endl;
我们先口算以下减法的结果是,即,显然-3
的移码为000
,这是特殊标记
,且尾数数值部分全0,则表示+0
,从而会导致上述代码输出“x == y”,为了避免逻辑错误,IEEE754的解决方法是渐进下溢
,用非规格化浮点数
来表示接近0但不等于0的数
,即将上例转化为,这样就能用非规格化浮点数表示接近0的数了,避免出现逻辑错误。
6.IEEE754舍入模式
- 就近舍入:舍入到最接近的可表示值;当有两个最接近的可表示值时,首选“偶数”值。
- 朝0舍入
- 朝+舍入
- 朝-舍入
7.浮点数精度不足所带来的错误
首先来看这样一段代码
#include <stdio.h>
int main(){
float f = 123456789;
printf("%f\n", f);
return 0;
}
我们预期的执行结果是123456789.000000
,但实际上结果是这样的
123456792.000000
显然前7位
是对的,问题出在浮点数的精度
上,单精度浮点数尾数数值位有23位,再加上隐含的1,共计24位
,而代码中定义的变量f是用10进制表示的,那么24位2进制能表示多少位10进制呢,答案是24lg2
,向下取整
为7
,这样就能解释为什么执行结果的前7位是正确的。