理解浮点数
Example
首先从两个例子开始。
- 例 1,下例输出是?
#include<stdio.h>
void main(){
float p = 1000000.9;
printf("%f", p);
}
结果:
1000000.875000
- 例 2,下例输出是?
#include<stdio.h>
void main(){
int i = 1;
float* p = &i;
printf("%f", *p);
}
结果:
0.000000
理解浮点数
从例 1 可知,浮点数表示的精度有限;由例 2 可知,同样为 4 Byte,float 和 int 的数据组织不一样。那么浮点数是如何组织的呢?首先回忆科学计数法。在科学记数法中,一个有限的实数可用如下表示:
a * 10^n
其中:
1 <= |a| < 10
n 为整数
以上式子亦可表达为如下:
(-1)^s * a * 10^n
其中:
s = 0 或 1,s 为 0 表示正数,为 1 表示负数
1 <= a < 10
n 为整数
计算机采用二进制,科学计数法的二进制表达如下:
(−1)^s × a × 2^n
其中
s = 0 或 1,s 为 0 表示正数,为 1 表示负数
1 <= a < 2
n 为整数
以 4 Byte 的 float 为例,IEEE 754 对其的定义如下:
|s|exponent(8 bit)| fraction (23 bit) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- s 表示符号位,共 1 bit,0 表示正数,1 表示负数
- e(exponent) 共 8 bit,它决定了 n 的值,即浮点数能表达的范围
- f(fraction) 共 23 bit,它决定了 a 的值,即浮点数的精度
e 和 n 的关系如下:
n = e - 127
其中 0<= e <= 255
所以 -127 <= n <= 128。(当 n = 128 时,表示浮点数无穷大)
f 和 a 的关系如下:
a = f/(2^23) + 1
其中 0 <= f <= 8388607
所以 1 <= a <= 1.99999988
所以 float 类型的浮点数能表示的范围为:
± 1.99999988 * 2^-127 至 ± 1.99999988 * 2^127
即:± 1.18 × 10^-38 至 ± 3.4 × 10^38
float 类型的浮点数精度为:
1/(2^23) = 1.19 * 10^-7,十进制下为 7 位。
同理,double 类型的浮点数能表示的范围和最大精度为:
范围:± 2.23 × 10^-308 到 ± 1.80 × 10^308
精度:十进制下为 16 位
例 1 中,因为 1000000.9 长度为 8 位,超出 float 所能表示的最大精度,所以不能被精确表示。
例 2 中,对于 int i = 1,其在内存中的数据为:
|s|exponent(8 bit)| fraction (23 bit) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
故有 s = 0, e = 0, f = 1,其值为 (-1)^0 * (1 + 2^-23) * 2^-127,即 5.88 * 10^-39,所以显示的结果为 0。