浮点数在计算机中的表示

在计算机中,用二进制表示任何的数据,熟知的整数便是,浮点数同样也是用二进制来表示。举例:二进制 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

http://daoluan.github.io

05 July 2013 会持续更新