如果字符串与字面值相同,使用
==
进行比较在所有情况下都是真的吗?
一个常见但尚未探讨的考虑因素:
FLT_EVAL_METHOD
。
#include <float.h>
...
printf("%d\n", FLT_EVAL_METHOD);
评估所有操作和常量的范围和精度,以 long double
类型为准。
如果返回值为 2,则在 value == 7.7
中使用的数学运算是基于 long double
,而 7.7
被视为 7.7L
。在 OP 的情况下,这可能会得出错误的结果。
为了考虑到更宽广的精度,分配值时需要移除所有额外的范围和精度。
scanf(file, "%lf", &value);
double seven_seven = 7.7;
if (value == seven_seven)
printf("strictly equal\n");
在我看来,这个问题比变量舍入模式或库/编译器转换的差异更有可能发生。
请注意,这种情况类似于下面一个众所周知的问题。
float value;
fscanf(file, "%f", &value);
if (value == 7.7)
printf("strictly equal\n");
Demonstration
#include <stdio.h>
#include <float.h>
int main() {
printf("%d\n", FLT_EVAL_METHOD);
double value;
sscanf("7.7", "%lf", &value);
double seven_seven = 7.7;
if (value == seven_seven) {
printf("value == seven_seven\n");
} else {
printf("value != seven_seven\n");
}
if (value == 7.7) {
printf("value == 7.7\n");
} else {
printf("value != 7.7\n");
}
return 0;
}
输出
2
value == seven_seven
value != 7.7
替代比较
为了比较两个“相近”的double
,我们需要定义“相近”的概念。一个有用的方法是将所有有限的double
值按升序排序,然后比较它们之间的序列号。double_distance(x, nextafter(x, 2*x)
--> 1
以下代码对double
的布局和大小做出了各种假设。
#include <assert.h>
unsigned long long double_order(double x) {
union {
double d;
unsigned long long ull;
} u;
assert(sizeof(double) == sizeof(unsigned long long));
u.d = x;
if (u.ull & 0x8000000000000000) {
u.ull ^= 0x8000000000000000;
return 0x8000000000000000 - u.ull;
}
return u.ull + 0x8000000000000000;
}
unsigned long long double_distance(double x, double y) {
unsigned long long ullx = double_order(x);
unsigned long long ully = double_order(y);
if (x > y) return ullx - ully;
return ully - ullx;
}
....
printf("%llu\n", double_distance(value, 7.7));
printf("%llu\n", double_distance(value, nextafter(value,value*2)));
printf("%llu\n", double_distance(value, nextafter(value,value/2)));
或者只需使用。
if (nextafter(7.7, -INF) <= value && value <= nextafter(7.7, +INF)) {
puts("Close enough");
}
inf
和NaN
被排除在外。 - Jabberwocky