float类型与0比较详解

我们先看一段程序:

  1. # include

  2. using namespace std;

  3. void main()

  4. {

  5. float a = 1.0004f;

  6. float d = 1.0003999f;

  7. if( d == a)

  8. cout<<"float a == c";

  9. else

  10. cout<<"float a != c";

  11. cout<<endl;

  12. }

 

从赋值上看,变量a与变量d明显不相等,运行程序,结果是



float a == c

这是为何?跟踪调试,发现在内存中变量a和变量d的实际取值为:

a    1.0003999    float

d    1.0003999    float

也就是说在内存中,float 变量a的值为1.004其在内存中是表示为1.0003999,所以变量a和变量d相等了。因此应该如何正确比较,我们先复习一下float和double这两种数据类型;

类型 比特数 有效数字 数值范围

float 32 6-7 -3.4*10(-38)~3.4*10(38)

double 64 15-16 -1.7*10(-308)~1.7*10(308)

long double 128 18-19 -1.2*10(-4932)~1.2*10(4932)

简单来说,Float为单精度,内存中占4个字节,有效数位是7位(因为有正负,所以不是8位,这个从跟踪调试结果可以看出);double为双精度,占8个字节,有效数位是16位;例如在VC中,double x =1.000015121212;在内存中的实际值为:1.0000151212120001。 还有需要注意的是:在C和C++中,如下赋值语句

float a=0.1;

编译器报错:warning C4305: ‘initializing’ : truncation from ‘const double ‘ to ‘float ‘

原因:

在C/C++中,上述语句等号右边0.1,编译器默认以为它是个float,于是就出现长类型转变为短类型,一般改成0.1f就没事了。 通常的做法,经常使用double,而不喜欢使用float。

那么应该如何比较才好?读者可以参考这篇文章

浮点数的比较 在数学运算当中经常会涉及到判断两个数是否相等的情况 对于整数很好处理 A==B这样的一个语句就可以解决全部的问题 但是对于浮点数是不同的;

首先,浮点数在计算机当中的二进制表达方式就决定了大多数浮点数都是无法精确的表达的 现在的计算机大部分都是数字计算机,不是模拟机,数字机的离散化的数据表示方法自然无法精确表达大部分的数据量的。

其次,计算机浮点数的精度在单精度float类型下,只有7位,在进行浮点运算的时候,这个精度往往会导致运算的结果和实际期望的结果之间有误差 因为前两个原因,我们很难用 A==B来判定两个浮点数是否相同 很自然,我们可以想到 fabs(A-B) < epsilon 这样的一种判别方法 但是这种判别方法稳妥吗? 它也不稳妥。

首先, epsilon是一个绝对的数据,也就是误差分析当中说说的绝对误差 使用一个固定的数值,对于float类型可以表达的整个数域来说是不可以的 比如epsilon取值为0.0001,而a和b的数值大小也是0.0001附近的,那么显然不合适 另外对于a和b大小是10000这样的数据的时候,它也不合适,因为10000和10001也可以认为是相等的呢 适合它的情况只是a或者b在1或者0附近的时候 既然绝对误差不可以,那么自然的我们就会想到了相对误差

bool IsEqual(float a, float b, float relError )

{

       return ( fabs ( (a-b)/a ) < relError ) ? true : false;

}

这样写还不完善,因为是拿固定的第一个参数做比较的,那么在调用 IsEqual(a, b, relError ) 和 IsEqual(b, a, relError ) 的时候,可能得到不同的结果 同时如果第一个参数是0的话,就有可能是除0溢出 这个可以改造 把除数选取为a和b当中绝对数值较大的即可

bool IsEqual(float a, float b, relError )

{

          if (fabs(a) relError ) ? true : false; return (fabs( (a-b)/b) > relError ) ? true : false;

};

使用相对误差就很完善吗? 也不是, 在某些特殊情况下, 相对误差也不能代表全部 比如在判断空间三点是否共线的时候,使用判断点到另外两个点形成的线段的距离的方法的时候 只用相对误差是不够的,应为线段距离可能很段,也可能很长,点到线段的距离,以及线段的长度做综合比较的时候,需要相对误差和绝对误差结合的方式才可以 相对完整的比较算法应该如下:

bool IsEqual(float a, float b, float absError, float relError )

{

if (a==b) return true;

if (fabs(a-b)b) return (fabs((a-b)/a>relError ) ? true : false; return (fabs((a-b)/b>relError ) ? true : false;

}

这样才相对完整 。

这篇文章讲得比较多,对于大部分应用来说,(这里考虑float   x 与0比较)这样写就行:

const  float  EPSINON = 0.00001;//这是精度要求

if((x > = –EPSINON )&& (X<= EPSINON))

转载http://ordinarysky.cn/?p=191

 

你可能感兴趣的:(C语言,float,编译器,include,算法,c)