If the string is the same as the literal, will the comparison using ==
be true in all cases?
A common consideration not yet explored: FLT_EVAL_METHOD
#include <float.h>
...
printf("%d\n", FLT_EVAL_METHOD);
2 evaluate all operations and constants to the range and precision of the
long double
type.
If this returns 2, then the math used in value == 7.7
is long double
and 7.7
treated as 7.7L
. In OP's case, this may evaluate to false.
To account for this wider precision, assign values which will removes all extra range and precision.
scanf(file, "%lf", &value);
double seven_seven = 7.7;
if (value == seven_seven)
printf("strictly equal\n");
IMO, this is a more likely occurring problem than variant rounding modes or variations in library/compiler conversions.
Note that this case is akin to the below, a well known issue.
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;
}
Output
2
value == seven_seven
value != 7.7
Alternative Compare
To compare 2 double
that are "near" each other, we need a definition of "near". A useful approach is to consider all the finite double
values sorted into a ascending sequence and then compare their sequence numbers from each other. double_distance(x, nextafter(x, 2*x)
--> 1
Following code makes various assumptions about double
layout and size.
#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)); // 0
printf("%llu\n", double_distance(value, nextafter(value,value*2))); // 1
printf("%llu\n", double_distance(value, nextafter(value,value/2))); // 1
Or just use
if (nextafter(7.7, -INF) <= value && value <= nextafter(7.7, +INF)) {
puts("Close enough");
}