IEEE二进制浮点数算术标准(IEEE 754)。IEEE 754 定义了表示浮点数的格式、反常值、特殊数值、浮点数运算,以及四种数值舍入规则和五种例外状况。

浮点数的二进制表示方式

IEEE 754规定了四种表示浮点数值的方式:单精度(32bit)、双精度(64bit)、延伸单精度(>43bit)和延伸双精度(>79bit)。以下以单精度为例说明。

存储格式

IEEE 754 规定的二进制浮点数分为三部分,由高位bit到位bit依次为:符号部分、指数部分、有效数(小数)部分。单精度表示如下,其中符号部分1bit、指数部分8bit、小数部分23bit。

1
2
3
 X   XXXXXXXX   XXXXXXXXXXXXXXXXXXXXXXX
 S   EEEEEEEE   FFFFFFFFFFFFFFFFFFFFFFF
31  30-----23  22---------------------0

符号

最高位为符号位,符号位的值为1表示负数,值为0表示正数。

指数部分

真实的指数值加上一个固定的偏移值,得到指数部分的编码值。将用原码表示的编码值保存在浮点数的指数部分。

对于单精度浮点数,其指数部分位宽为8bit,所以其编码值能够表示的数值范围是0到255;而其偏移值是2811=127;因此真实的指数值能够表示的数值范围是-127到128。事实上-127和128指数会做特殊处理,单精度指数部分的实际取值范围是-126到127,见下面关于数值解析的说明。

有效部分

浮点数的有效部分,也叫小数部分,表示的是一段小数,小数点紧邻在最高位之前,根据数值解析情况的不同,小数点前面的整数为0或者1,这个整数不会被储存。

以单精度为例,其小数部分有23bit,那么根据情况不同,读出的数值可能为(0+223)或者(0+223)

数值解析

规约形式的解析

当指数部分的编码值在[1,282]范围,即真实指数值在[126,127]的范围内时,分数部分小数点前的整数字为1,分数部分表示的值在[1,2)的范围内。例如:

1
0   00000001   11000000000000000000000

表示的数值为+1.752126

非规约形式的解析

当指数部分的编码值为0时,偏移值为126,真实的指数值为-126,分数部分小数点前的整数字为0,分数部分表示的值在(0,1)的范围内。例如:

1
0   00000001   11000000000000000000000

表示的数值为+0.752126

这里出现了一个问题,为什么不像规约形式那样,定义上面那个数字为+1.752127呢?为什么要修改指数和小数部分的解析方式呢?

如果使用统一的规约形式解析,这种表示称为突然式下溢出。按照这种解析方式,绝对值最小的浮点数为+(1+1223)2127,而小浮点数之间的距离为+12232127,当计算两个小浮点数的差时将会得到结果0。如下:

1
2
3
4
// 突然式下溢出
0   00000000   00000000000000000000000  // zero
0   00000000   00000000000000000000001  // smallest
0   00000000   00000000000000000000010  // second smallest

而使用当前规定的,在指数部分编码值为0时,进行非规约解析的这种表示,称为渐进式下溢出。绝对值最小的浮点数为+(0+1223)2126,小浮点数之间的距离为+12232127。如下:

1
2
3
4
// 渐进式下溢出
0   00000000   00000000000000000000000  // zero
0   00000000   00000000000000000000001  // smallest
0   00000000   00000000000000000000010  // second smallest

特殊值

  • 如果指数编码值为0,而且小数部分为0,表示正负0。
  • 如果指数编码值为255,而且小数部分为0,表示±Inf
  • 如果指数编码值为255,而且小数部分不为0,表示非数(NaN)。

各种精度的位宽定义

精度 符号位 指数位数 小数位数
单精度 1 8 23
双精度 1 11 52

浮点数的数值比较

指数部分如此设计,优势在于这使得对浮点数的比较更容易,可以按照字典次序比较两个浮点表示的大小,先比较符号,之后是指数的高位、指数的低位、小数的高位、小数的低位。

浮点数的舍入

IEEE标准列出4种不同的舍入方法:

  • 舍入到最接近:会将结果舍入为最接近且可以表示的值,但是当存在两个数一样接近的时候,则取其中的偶数(在二进制中是以0结尾的)。
  • 朝正无穷方向舍入:会将结果朝正无限大的方向舍入。
  • 朝负无穷方向舍入:会将结果朝负无限大的方向舍入。
  • 朝0方向舍入:会将结果朝0的方向舍入。

浮点数的运算

标准运算

  • 加减乘除。加减运算中+0.0=0.0
  • 平方根。x0(x0)0.0=0.0
  • 近似到最近的整数round(x)。恰好在中间则近似到偶数。
  • 浮点余数。返回x(round(x/y)y)
  • 比较运算。Inf<<<0.0<+0.0<<<+Inf
  • 特殊比较。Inf=Inf+Inf=+Inf,NaN与任何浮点数(包括NaN)比较都为假。

精度

单精和双精浮点数的有效数字分别是有存储的23和52个位,加上最左手边没有存储的第1个位,即是24和53个位。 log224=7.22log253=15.95 由以上的计算,单精和双精浮点数可以保证7位和15位十进制有效数字。