从如何判断浮点数是否等于0说起——浮点数的机器级表示(转)

http://www.cnblogs.com/kubixuesheng/p/4107309.html

这位前辈讲的不错,摘抄下来以表尊敬!

void isZero(double d)
    {
        if (d >= -DBL_EPSILON && d <= DBL_EPSILON)
        {
            //d是0处理
        }
    }

    void isZero(int d)
    {
        if (0 == d)
        {
            //d是0处理
        }
    }

    void isZero(int *d)
    {
        if (NULL == d)
        {
            //d是空指针处理
        }
    }

    void isZero(bool d)
    {
        if (!d)
        {
            //d就认为是false 也就是0
        }
    }

没错,很多经典的教科书或者指南,一些技术类的讲义,都会这样教授。但是为什么要这样写?

可能一部分人就糊涂了,不知道咋回答,搞技术或者做学问不是诗词歌赋,结论经不起严谨的推敲就不能服众,不可以说,书上是这样写的,或者老师告诉我的,那样太low了。尤其是浮点数比较的问题,不只是0,类似的和其他的浮点数比较大小的问题也是一样的。

要解决这个疑惑,必须先理解计算机是如何表示和存储浮点数据的,期间参考了IEEE单双精度的规范文档,和MSDN的一些文档,以及《深入理解计算机操作系统》一书。

这样的结果在不同机器或者编译器下,有可能不同,但是能说明一个问题,浮点数的比较,不能简单的使用==,而科学的做法是依靠EPISILON,这个比较小的正数(英文单词episilon的中文解释)。

EPSILON被规定为是最小误差,换句话说就是使得EPSILON+1.0不等于1.0的最小的正数,也就是如果正数d小于EPISILON,那么d和1.0相加,计算机就认为还是等于1.0,这个EPISILON是变和不变的临界值。

#define DBL_EPSILON      2.2204460492503131E-16 
2 #define FLT_EPSILON     1.19209290E-07F 
3 #define LDBL_EPSILON     1.084202172485504E-19 

浮点数表达的有效位数(也就是俗称的精度)和表达范围不是一个意思

经常说什么单精度一般小数点精度是7-8位,双精度是15-16位,到低怎么来的呢?前面说了,单精度数尾数23位,加上默认的小数点前的1位1,2^(23+1) = 16777216。关键: 10^7 < 16777216 < 10^8,所以说单精度浮点数的有效位数是7-8位,这个7-8位说的是十进制下的,而我们前面说的尾数位数那是二进制下的,需要转换。

又看,双精度的尾数52位存储,2^(52+1) = 9007199254740992,那么有10^16 < 9007199254740992 < 10^17,所以双精度的有效位数是16-17位。

貌似实际编码中,大部分直接用double了,省的出错。

 

posted @ 2017-08-19 13:25  颜小雀  阅读(1436)  评论(0编辑  收藏  举报