3

I'd like to check if a long long variable can be safely cast into a double. DBL_MAX doesn't help, because there are integers smaller than that which are not representable by double, while some of integers larger than 2^53 can still fit.

Is there a reliable way to do this? Can a compiler optimise out a statement like the one below?

(long long)((double)a) == a (where a is a long long)

This does not ask for a largest integer that can be represented as double, I ask for a general function that can check if I can exactly convert any long long value to double without errors.

Jongware
  • 22,200
  • 8
  • 54
  • 100
wesolyromek
  • 650
  • 1
  • 6
  • 17
  • Could you please define what "safely cast into a double" means? – jdarthenay Apr 18 '16 at 16:11
  • Test whether the last bits of `a` are zero if `a` is larger than pow(2, 53)? `clz(abs(a)) + ctz(abs(a)) > 64 - 53`? – EOF Apr 18 '16 at 16:12
  • 4
    I think the author is asking: "How can I ensure that there is no rounding error when I store a `long long` integer into a `double`, given there are integer values that a double cannot store?" – TezlaCoil Apr 18 '16 at 16:13
  • 1
    With the most common IEEE754 floating point implementations, this is not possible. – too honest for this site Apr 18 '16 at 16:14
  • @user3470630 That's what I was thinking, until I saw the last line. `(long long) (3.12) == 3` should be evaluated as true. – jdarthenay Apr 18 '16 at 16:16
  • @jdarthenay In the last line I assumed that a is `long long` – wesolyromek Apr 18 '16 at 16:17
  • Not the point. I mean if `(double) 3` is `3.12` your last test would say `3.12` is a safe cast for `3` as a double... – jdarthenay Apr 18 '16 at 16:19
  • 1
    I think your expression is fine, except for a large integer where (double) a equals 2^63, and you need to check whether the conversion back to long long might be undefined behaviour. – gnasher729 Apr 18 '16 at 16:21
  • Voted to re-open as this post and voted duplicate, although both about `long long` and `double` are asking fundamental different questions. – chux - Reinstate Monica Apr 18 '16 at 21:01

2 Answers2

1

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.

Community
  • 1
  • 1
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
0

I'm not sure you can check this conversion before you cast, but fenv.h seems like it can help you for after-cast checking. FE_INEXACT can allow you to check if the operation you just performed could not be exactly stored. http://www.cplusplus.com/reference/cfenv/FE_INEXACT/

TezlaCoil
  • 134
  • 8