在计算机中,用二进制表示任何的数据,熟知的整数便是,浮点数同样也是用二进制来表示。举例:二进制 0.1 是十进制的 0.5,二进制中的 0.011 是十进制的 0.375.其中的转换和「二进制与十进制整数转换」的原理数一样的。
但整数的二进制和浮点数的二进制表示在语意是完全不同的。在 c 语言中,浮点数有分单精度(4B)和双精度(8B),显而易见后者较前者有更好的精度表示,且能表达更大的浮点数。以单精度为例,其在二进制的语意:
符号位(1 bit)阶码(8 bit)尾数(23 bit)
解释:
符号位 s:0 表示正数,否则表示负数
阶码 e:对浮点数的加权。根据阶码的不同,浮点数被分为规格化数,非规格化数,无穷大和 NAN。
尾数 f:二进制的一个小数,即 0.f(非规格化数)或者 1.f(规格化数)。
无论如何分类,我们假设最后的浮点值 F 都可以用下面的算式来表达:
F = sign(s) * N(e) * M(f).
其中 sign 表示对符号位的处理,N 表示对阶码的处理,M 表示对尾数的处理。
由于浮点数其本身的表示方法,因此 一些浮点数只能用一个逼近的值来表述,譬如 100.3 并不能确切的用 F = 100.3 表示出来,即不能用上面的算式得出。如果 float val = 100.3,那变量 val 也只是接近 100.3 的值。做一个简单的测试:
#include <stdio.h>
const int kTestCount = 5000;
int main(int argc, char const *argv[])
{
float a = 100.3f,
b = 100.0f;
float c = a - b;
printf("%f\n", c);
return 0;
}
结果是 0.300003 看!还是有稍微的差错的,并不是完全是 0.3。
通由上面的实例,我们吸取教训:不能像整数那样对浮点数进行比较判断,经典的错误是 x == 0.0,原因在前面的浮点数的简介中会有提示。
参考资料:《深入理解计算机系统》第二章 第四小节 如有需要强烈建议读这一小节。
Dylan 2013-07-05
05 July 2013 会持续更新