我想检查一个long long变量是否可以安全地转换为double。 DBL_MAX
没有帮助,因为有一些整数小于不能用double表示的整数,而一些大于2^53
的整数仍然适合。
有可靠的方法吗? 编译器能否优化出类似下面的语句?
(long long)((double)a) == a
(其中a
是long long
)
这不要求一个可以表示为double的最大整数,我要求一个通用函数可以检查我是否可以完全转换任何 {{1值没有错误加倍。
答案 0 :(得分:1)
(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的目标。只需确保b
处于long long
范围内。 @gnasher729我们假设2补,double
使用FLT_RADIX != 10
。在这种情况下,最低long long
是2的幂,最高是2的幂减去1,并且通过仔细计算{{1}可以精确地转换为double
限制,如下。
long long
[编辑简化 - 更一般]
只有当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;
}
不使用2补码时才需要b
LLONG_MIN
附近的long long
测试
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
代码来防止这种情况发生。
答案 1 :(得分:0)
我不确定你可以在演员之前检查这个转换,但是fenv.h
似乎可以帮助你进行后投检查。 FE_INEXACT
可以让您检查您刚刚执行的操作是否无法准确存储。
http://www.cplusplus.com/reference/cfenv/FE_INEXACT/