OP's method is a good start.
(long long)((double)a) == a
Yet has a problem. E.g. long long a = LLONG_MAX; ((double)a)
results is a rounded value exceeding LLONG_MAX
.
The following will certainly not overflow double
.
(Pathological exception: LLONG_MIN
exceeds -DBL_MAX
).
volatile double b = (double) a;
Converting back to long long
and testing against a
is sufficient to meet OP's goal. Only need to insure b
is in long long
range. @gnasher729 Let us assume 2's complement and double
uses FLT_RADIX != 10
. In that case, the lowest long long
is a power-of-2 and the highest is a power-of-2 minus 1 and conversion to double
can be made exact with careful calculation of the long long
limits, as follows.
bool check_ll(long long a) {
constant double d_longLong_min = LLONG_MIN;
constant double d_longLong_max_plus_1 = (LLONG_MAX/2 + 1)*2.0;
volatile double b = (double) a;
if (b < d_longLong_min || b >= d_longLong_max_plus_1) {
return false;
}
return (long long) b == a;
}
[edit simplify - more general]
A test of b
near LLONG_MIN
is only needed when long long
does not use 2's complement
bool check_ll2(long long a) {
volatile double b = (double) a;
constant double d_longLong_max_plus_1 = (LLONG_MAX/2 + 1)*2.0;
#if LLONG_MIN == -LLONG_MAX
constant double d_longLong_min_minus_1 = (LLONG_MIN/2 - 1)*2.0;;
if (b <= d_longLong_min_minus_1 || b >= d_longLong_max_plus_1) {
return false;
}
#else
if (b >= d_longLong_max_plus_1) {
return false;
}
#endif
return (long long) b == a;
}
I would not expect a compile to be able to optimize out (long long)((double)a) == a
. IAC, by using an intermediate volatile double
, code prevents that.