【问题标题】:How to check if a long long can fit into a double variable如何检查 long long 是否适合双变量
【发布时间】:2016-08-10 11:42:34
【问题描述】:

我想检查一个 long long 变量是否可以安全地转换为 double。 DBL_MAX 无济于事,因为有一些小于 double 的整数不能表示,而一些大于 2^53 的整数仍然可以适应。

有没有可靠的方法来做到这一点? 编译器可以优化如下语句吗?

(long long)((double)a) == a(其中along long

这不要求一个可以表示为双精度的最大整数,我要求一个通用函数来检查我是否可以精确地转换anylong long值翻倍而不会出错。

【问题讨论】:

  • 你能定义一下“安全地转换成双精度”是什么意思吗?
  • 如果a大于pow(2, 53),测试a的最后一位是否为零? clz(abs(a)) + ctz(abs(a)) > 64 - 53?
  • 我想作者是在问:“当我将 long long 整数存储到 double 时,我如何确保没有舍入错误,因为存在 double 无法存储的整数值?”
  • 使用最常见的 IEEE754 浮点实现,这是不可能的。
  • 我认为你的表达式很好,除了一个大整数,其中 (double) a 等于 2^63,你需要检查转换回 long long 是否可能是未定义的行为。

标签: c type-conversion floating-accuracy


【解决方案1】:

OP 的方法是一个好的开始。

(long long)((double)a) == a

还是有问题。例如。 long long a = LLONG_MAX; ((double)a) 结果是一个超过 LLONG_MAX 的舍入值。

下面肯定不会溢出double.
(病理异常:LLONG_MIN 超过-DBL_MAX)。

volatile double b = (double) a;

转换回long long 并针对a 进行测试足以满足OP 的目标。只需确保blong long 范围内。 @gnasher729 让我们假设 2 的补码,double 使用 FLT_RADIX != 10。在这种情况下,最低的 long long 是 2 的幂,最高的是 2 的幂减 1,并且可以通过仔细计算 long long 限制来精确转换为 double,如下所示.

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;
}

[编辑简化 - 更通用]

仅当 long long 不使用 2 的补码时,才需要在 LLONG_MIN 附近对 b 进行测试

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;
}

我不希望编译能够优化出(long long)((double)a) == a。 IAC,通过使用中间 volatile double,代码可以防止这种情况。

【讨论】:

    【解决方案2】:

    我不确定您是否可以在投射前检查此转换,但fenv.h 似乎可以帮助您进行投射后检查。 FE_INEXACT 可以让您检查您刚刚执行的操作是否无法准确存储。 http://www.cplusplus.com/reference/cfenv/FE_INEXACT/

    【讨论】:

      猜你喜欢
      • 2016-09-29
      • 2011-06-27
      • 1970-01-01
      • 1970-01-01
      • 2013-04-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多