浮点数(floating-point number)二进制存储格式
定义
浮点数就是小数点位置不固定的数,也就是说与定点数不一样,浮点数的小数点后的小数位数可以是任意的,根据IEEE754-1985(也叫IEEE Standard for Binary Floating-Point Arithmetic)的定义,浮点数的类型有两种:单精度类型(用4字节存储)和双精度类型(用8字节存储)。
存储方式
要理解浮点数的存储方式,首先要从科学技术法讲起。
对于十进制数345.67用科学计数法可以表示为3.4567 * 10^2,其中3.4567有很多英文叫法,有叫fraction part,或者叫characteristic,或者mantissa,但是大多数习惯叫significand。我们这里统一称这一部分为significand。345.67除了可以表示为3.4567 * 10^2,还可以表示为0.34567 * 10^3,0.034567 * 10^4,但是通常情况下,把sigificand介于[1, 10)的形式称为标准形式(nomalized form)。
对于二进制,也有类似的情形。比如二进制小数101.1101 = 1.011101 * 2^2 = 0.1011101 * 2^3 = 0.01011101 * 2^4,其中把significand介于[1, 2)之间的形式称为标准形式,1.011101 * 2^2就是101.1101科学计数法的标准形式。
有了上面的理解,那么我们就可以把任何二进制浮点数都化成如下标准形式:
(+/-)1.f * 2^e
其中(+/-)表示正负号,f表示signifcand的小数部分,e表示指数。而二进制的浮点数(无论是单精度,还是双精度)在计算机内部的存储格式就是依据上述的标准形式,被划分成3部分:
一 单精度
对于单精度浮点数,s使用1bit存储,0表示正数,1表示负数,e使用8bit存储,值范围是[0, 255],由于单精度总共使用4字节32bit存储,那么f就使用剩余的23bit存储。不用存储二进制标准形式1.f中的"1"的原因是,在标准形式下,它总是1,所以尽管单精度只存储了1.f中的23bit,但实际上它可以表示的精度是24bit(23bit + 没有存储的"1")。
上述存储形式中,需要特殊主意的指数e。
首先,这里的指数e是有偏的(biased),就是说,e是在实际指数的基础上加了一个偏移量(bias)对于单精度浮点数来说,这个偏移量 = 127(即2^(e的存储位数 - 1) - 1)。换句话说,有单精度浮点数的存储形式反推单精度浮点数的二进制标准科学计数法的公式为:
(-1)^s * 1.f * 2^(e - 127)
其中s是符号位的值,当s = 0时,是一个正的单精度浮点数,当s = 1时,是一个负的单精度浮点数。
其次,对于e = 0和e = 255,有特殊的意义,总结如下:
1)e = 0 & f = 0
此时表示的单精度浮点数就是0,可以是正0,也可以是负0。负0的表明表示的实际上是一个非常小的负数,但是这个数已经无法用单精度的存储方式来表示了,比如1.11 * 2^(-129)已经无法用单精度表示了,因为即使-129加了127的偏移量,仍然落在了e的值区间[0, 255]之外。
2) e = 0 & f != 0
此时表示的数可有下面的工时推出:
(-1)^s * 0.f * 2^(-127)
其中s仍然表示符号位,这种形式被称为非标准形式
3) e = 255 & f = 0
此时表示正无穷或者负无穷,依据符号位决定
4) e = 255 & f != 0
此时表示NaN
二 双精度
双精度和单精度的存储类似,只是在bit位数有有点不一样。s使用1bit存储,e使用11bit存储,因此bias是1023,f使用52bit存储,因此可以表示的精度是53bit。
由双精度浮点数存储形式反推的双精度浮点数标准二进制科学表示公式为:
(-1)^s * 1.f * 2^(e - 1023)
对于指数e也有和单精度一样的情形。