4 ms·
This ^^^^ is the core issue. It's insidious that LONG_MAX is too big to be exactly representable as a double. The answer by ambrop7 below solves a different pr
by fargle 7y ago
This ^^^^ is the core issue. It's insidious that LONG_MAX is too big to be exactly representable as a double.
The answer by ambrop7 below solves a different problem but appears to be correct. The reason escaped me at first and is super subtle. The trick is that LONG_MAX is 2^63 - 1, not 2^63. And the subtlety is that 2^63 is guaranteed to be exactly representable in IEEE double because it is an even power of 2, which 2^63-1 is not.
I don't care much for runtime ldexp() anyhow. So I'd be tempted to just pre-compute the exact limits -2^63 and nextafter(+2^63, 0) and encode them as doubles manually (omitting some #if method of portably determining the width of LONG):
#define FLONG_MIN 9223372036854775808.0 // exact -2^63
#define FLONG_MAX 9223372036854774784.0 // exact nextbefore(2^63)
if (value < FLONG_MIN || value > FLONG_MAX)
return(0);
Then the UB is avoided. I think the rest of the module works as is. Now, I question whether the author really wants integers between 2^53 and 2^63 to sparsely return true. So it might be better to just change the whole design to use +-2^53 as a hard limit, for trivially guaranteed round trip of the entire range and dispense with these nasty edge cases.