Before this afternoon, I thought that a check like this for a double 'd':
    d == floor (d) && d >= LONG_MIN && d <= LONG_MAX
was sufficient to determine whether converting 'd' to 'long' would
yield a 'long' with the same value as 'd'.

Now I realize that this is wrong. In particular, take a look at the
following program:

#include <limits.h>
#include <stdio.h>

int main (void)
{
  long i = LONG_MAX;
  double d = i;
  long j = d;
  printf ("%ld, %f, %ld\n", i, d, j);
  return 0;
}

On my system, this prints:

9223372036854775807, 9223372036854775808.000000, -9223372036854775808

In other words, LONG_MAX gets rounded up to 2**63 when it's converted to
'double', which makes sense because 'double' only has 53 bits of precision,
but this also means that 'd <= LONG_MAX' and still doesn't fit in 'long', as one
can see from it getting converted to a wrong answer (-2**63 instead of
2**63) when converted back to 'long'. And of course any answer is OK there,
since this out-of-range conversion yields undefined behavior.

Can anyone suggest a correct way to check whether a 'double' is in the
range of 'long'?

One workaround would be to check for the range of 'int' (or int32_t, I guess
really), since there's not going to be any loss of precision converting
INT(32)_MAX to 'double'. But I'd rather support a wider range in the code
I'm working on.

Thanks,

Ben.

Reply via email to