引言: 浮点数是计算机科学中一种常见的数值表示方法,它能够精确地表示大范围的数字,并且在科学计算、图形处理等领域中被广泛使用。为了统一浮点数的表示方式并进行有效的计算,国际电气与电子工程师协会(IEEE)提出了IEEE 754标准,该标准规定了浮点数的存储格式和计算规则。
1. IEEE 754标准概述:
IEEE 754标准于1985年首次发布,之后进行了多次修订,最新版本为2008年发布的IEEE 754-2008。该标准定义了浮点数的二进制表示方法、舍入规则、运算规则以及特殊值的处理方式,使得不同平台的计算机能够以相同的规则进行浮点数的计算。
2. 浮点数的二进制表示:
根据IEEE 754标准,浮点数由三个部分组成:符号位(S)、指数位(E)和尾数位(M)。其中,符号位决定了浮点数的正负性,指数位用于表示浮点数的大小范围,尾数位用于表示浮点数的精度。
- (-1)^S * M * 2^E
- (-1)^S表示符号位,当S=0,为正数;当S=1,为负数。
- M表示有效数字,大于等于1,小于2。
- 2^E表示指数位
3. 单精度和双精度浮点数:
IEEE 754标准定义了两种浮点数格式:单精度和双精度。单精度浮点数使用32位存储,符号位占1位,指数位占8位,尾数位占23位;双精度浮点数使用64位存储,符号位占1位,指数位占11位,尾数位占52位。其余的位用于特殊值(如NaN和无穷大)的表示。
3.1 指数位的计算
在 IEEE 754 标准中,浮点数的指数部分使用了移位偏置(exponent bias)的方法来表示带符号整数,以便能够表示正数、负数和零。
首先,E为一个无符号整数(unsigned int)
这意味着,如果E为8位,它的取值范围为0~255;如果E为11位,它的取值范围为0~2047。但是,我们知道,科学计数法中的E是可以出现负数的,所以IEEE 754规定,存入内存时E的真实值必须再加上一个中间数,对于8位的E,这个中间数是127;对于11位的E,这个中间数是1023。比如,2^10的E是10,所以保存成32位浮点数时,必须保存成10+127=137,即10001001。
3.2 尾数
前面说过, 1≤M<2 ,也就是说,M可以写成 1.xxxxxx 的形式,其中xxxxxx表示小数部分。
IEEE 754规定,在计算机内部保存M时,默认这个数的第一位总是1,因此可以被舍去,只保存后面的xxxxxx部分。比如保存1.01的时候,只保存01,等到读取的时候,再把第一位的1加上去。这样做的目的,是节省1位有效数字。以32位浮点数为例,留给M只有23位,将第一位的1舍去以后,等于可以保存24位有效数字。
3.3 示例
- 单精度浮点数(32位)示例: 假设我们要表示数字3.14作为单精度浮点数。首先,我们将数字3.14转换为二进制表示形式: 3.14 = 11.0010001111...接下来,根据IEEE 754标准,我们需要将这个二进制数规范化,即确保尾数部分的最高有效位为1。在单精度浮点数中,尾数占23位。所以,我们将上述二进制数进行舍入和截断后,得到以下表示: 3.14 ≈ 1.10010001111010111000011 × 2^1在存储时,符号位为0(因为3.14是正数),指数位为1(1+127 = 128 = 10000000),尾数位为10010001111010111000011。将它们合并在一起,得到最终的单精度浮点数的二进制表示: 0 10000000 10010001111010111000011
- 双精度浮点数(64位)示例: 现在我们来看一个双精度浮点数的示例,比如表示数字12345.6789。同样地,我们将该数字转换为二进制形式: 12345.6789 = 11000000111001.101101001110000101011000...接下来,进行规范化处理。在双精度浮点数中,尾数占52位。我们对上述二进制数进行舍入和截断,得到以下表示: 12345.6789 ≈ 1.1000000111001101101001111000010101100000101011001 × 2^13在存储时,符号位为0,指数位为13(13 + 1023 = 1036 = 1000000110),尾数位为1000000111001101101001111000010101100000101011001。将它们合并在一起,得到最终的双精度浮点数的二进制表示:
0 10000001100 1000000111001101101001111000010101100000101011001
4. 正规化表示和非正规化表示:
根据IEEE 754标准,浮点数可以采用正规化表示或非正规化表示。正规化表示是指将浮点数转换为科学计数法形式,其中尾数部分的最高有效位必须为1。非正规化表示则允许尾数部分的最高有效位为0,从而表示较小的数值。
4.1 正规表示(Normalized representation):
正规表示用于表示大多数非零的浮点数。在正规表示中,浮点数的尾数部分采用隐藏位(hidden bit)的方式,即默认情况下尾数的最高位总是1,并且不对其进行存储。这样可以有效地提高浮点数的精度,并且可以节省存储空间。在正规表示中,指数部分具有一定的范围并且不为全0或全1。
4.2 非正规表示(Denormalized representation):
非正规表示主要用于接近于零的非常小的浮点数。当指数部分全为0时,尾数部分的隐藏位为0,此时浮点数被视为非正规表示。非正规表示允许更小的数值范围,但相应地牺牲了一些精度。
5. 舍入规则:
由于浮点数的存储格式有限,对于某些数值,无法以完全精确的方式表示。因此,IEEE 754标准定义了不同的舍入规则,用于确定浮点数在存储过程中的近似值。常见的舍入规则有向最近舍入、向正无穷舍入、向负无穷舍入和向零舍入。舍入方式一般是由编译器或解释器默认选择的,例如,在Java中,默认使用的是向最近偶数舍入规则(Round to nearest, ties to even)。不过,在一些编程语言中,可以通过代码来控制舍入方式,以满足不同的精度和近似处理要求。例如,在C++中,可以使用fesetround函数来设置舍入模式,从而控制浮点数运算的舍入规则。
6. 特殊值的处理:
IEEE 754标准还规定了一些特殊的浮点数值,如正无穷大(+∞)、负无穷大(-∞)、NaN(Not a Number)等。这些特殊值在浮点数计算中具有特定的含义和处理方式,能够帮助解决计算中的异常情况。
6.1 正无穷大(Positive Infinity):
当一个正数超过了浮点数能够表示的最大值时,就会出现正无穷大。正无穷大可以用来表示计算结果溢出的情况,例如某个数除以0。
6.2 负无穷大(Negative Infinity):
与正无穷大类似,当一个负数超过了浮点数能够表示的最小值时,就会出现负无穷大。负无穷大可以用来表示计算结果下溢的情况,例如某个极小数除以0。
6.3 NaN(Not a Number):
NaN是指在浮点数操作中未定义或不可表示的值,它通常出现在一些异常情况下,例如:
- 0/0 产生 NaN
- 负数的平方根产生 NaN
- 对负数进行对数运算产生 NaN 等
NaN可以用来表示无效的计算结果或未定义的数学操作。NaN本身并不能参与计算,但是它可以被传递到后续的计算中,从而影响整个计算过程的结果。在实际应用中,需要对NaN进行特殊处理,以避免对后续计算结果的影响。
总之,正无穷大、负无穷大和NaN是浮点数运算中的特殊情况,它们的出现通常代表着某个计算结果无法表示或者不符合数学规则,需要针对具体情况进行特殊处理。