比较C中的相同浮点值
可能重复:
与float和float文字相比较的奇怪输出
当我尝试比较2个相同的float
值时,它不会在以下代码中打印“相等的值”:
void main() { float a = 0.7; clrscr(); if (a < 0.7) printf("value : %f",a); else if (a == 0.7) printf("equal values"); else printf("hello"); getch(); }
提前致谢。
虽然很多人会告诉你总是将浮点数与epsilon进行比较(这通常是一个好主意,虽然它应该是被比较的值的百分比而不是固定值),但这里实际上并不是必需的,因为你是使用常量。
你的具体问题是:
float a = 0.7;
使用双常数0.7
来创建单个精度数(失去一些精度),同时:
if (a == 0.7)
将比较两个双精度数字( a
首先提升)。
将双0.7
转入浮球a
时丢失的精度在将背部提升为双倍时无法恢复。
如果你将所有这0.7
值更改为0.7f
(强制浮动而不是双倍),或者如果你只做一个双float
,它将正常工作 – 我现在很少使用float
除非我有大量数组并需要保存空间。
您可以通过以下方式查看此操作:
#include int main (void){ float f = 0.7; // double converted to float double d1 = 0.7; // double kept as double double d2 = f; // float converted back to double printf ("double: %.30f\n", d1); printf ("double from float: %.30f\n", d2); return 0; }
这将输出类似的东西(略微修改以显示差异):
double: 0.6999999|99999999955591079014994 double from float: 0.6999999|88079071044921875000000 \_ different beyond here.
浮点数不是你想象的那样:这里有两个有更多信息的来源: 每个计算机科学家应该知道浮点运算和浮点指南 。
简短的回答是,由于表示浮点数的方式,您无法进行基本比较或算术并期望它能够工作。
您正在将0.7的单精度近似与双精度近似进行比较。 要获得预期的输出,您应该使用:
if(a == 0.7f) // check a is exactly 0.7f
请注意,由于表示和舍入错误,可能不太可能从任何操作获得正好0.7f。 通常,您应该检查fabs(a-0.7)
是否足够接近0
。
不要忘记0.7f的确切值不是0.7,而是略低:
0.7f = 0.699999988079071044921875
0.7的双精度表示的精确值是更好的近似值,但仍不完全是0.7:
0.7d = 0.6999999999999999555910790149937383830547332763671875
a
是float
; 0.7
是double
类型的值。
两者之间的比较需要转换。 编译器会将float
值转换为double
值…而将float转换为double所产生的值与编译器将文本字符串(源代码)转换为double所产生的值不同。
但是不要将浮点值( float
, double
或long double
)与==
。
您可能希望阅读“每个程序员应该知道的关于浮点运算的内容” 。
不能将浮点数与“==”运算符进行比较。
您可以使用如下函数来代替将浮点数与“==”运算符进行比较:
//compares if the float f1 is equal with f2 and returns 1 if true and 0 if false int compare_float(float f1, float f2) { float precision = 0.00001; if (((f1 - precision) < f2) && ((f1 + precision) > f2)) { return 1; } else { return 0; } }
浮点数缺乏绝对精度使得进行简单比较比整数更难。 请参阅此页面以比较C中的浮点数。特别是,从那里取出的一个代码段展示了此问题的“解决方法”:
bool AlmostEqual2sComplement(float A, float B, int maxUlps) { // Make sure maxUlps is non-negative and small enough that the // default NAN won't compare as equal to anything. assert(maxUlps > 0 && maxUlps < 4 * 1024 * 1024); int aInt = *(int*)&A; // Make aInt lexicographically ordered as a twos-complement int if (aInt < 0) aInt = 0x80000000 - aInt; // Make bInt lexicographically ordered as a twos-complement int int bInt = *(int*)&B; if (bInt < 0) bInt = 0x80000000 - bInt; int intDiff = abs(aInt - bInt); if (intDiff <= maxUlps) return true; return false; }
一个简单而常见的解决方法是为epsilon提供如下代码:
if (fabs(result - expectedResult) < 0.00001)
这基本上检查了值之间的差异是否在阈值内。 请参阅链接文章,了解为什么这并不总是最佳的:)
另一篇文章几乎是事实上的标准,当人们询问SO上的浮动时。
如果你需要比较a
0.7
比
if( fabs(a-0.7) < 0.00001 ) //your code
这里0.00001可以更改为更少(如0.00000001)或更多(如0.0001)>这取决于您需要的精度。