如何在 C++11 constexpr 中检查双精度位模式是否为 0x0?

问题描述 投票:0回答:4

我想检查给定的双精度/浮点变量是否具有实际的位模式 0x0。不要问为什么,它用在 Qt 中的一个函数中(

qIsNull()
),我想成为
constexpr

原始代码使用了联合:

union { double d; int64_t i; } u;
u.d = d;
return u.i == 0;

这当然不起作用

constexpr

下一次尝试是

reinterpret_cast

return *reinterpret_cast<int64_t*>(&d) == 0;

但是,虽然它在 GCC 4.7 中作为

constexpr
工作,但在 Clang 3.1 中却失败了(理所当然,指针操作的 b/c)。

最终的想法是去 Alexandrescuesque 并这样做:

template <typename T1, typename T2>
union Converter {
    T1 t1;
    T2 t2;
    explicit constexpr Converter( T1 t1 ) : t1(t1) {}
    constexpr operator T2() const { return t2; }
};

// in qIsNull():
return Converter<double,int64_t>(d);

但这对于 Clang 来说也不够聪明:

note: read of member 't2' of union with active member 't1' is not allowed in a constant expression
constexpr operator T2() const { return t2; }
                                       ^

还有其他人有好主意吗?

c++ casting c++11 floating-point constexpr
4个回答
6
投票

我想检查给定的双精度/浮点变量是否具有实际的位模式 0x0

但是如果它是

constexpr
,那么它不会检查任何变量,而是检查该变量静态确定保存的。这就是为什么你不应该使用指针和联合技巧,“正式”没有任何内存可以指向。

如果您可以说服您的实现执行非陷阱 IEEE 除零,那么您可以执行以下操作:

return (d == 0) && (1 / d > 0)

只有

+/-0
等于 0。
1/-0
-Inf
,不大于 0。
1/+0
+Inf
,不大于 0。但我不知道如何使非陷阱算术发生。


5
投票

似乎 clang++ 3.0 和 g++ 4.7(但不是 4.6)都将

std::signbit
视为
constexpr

return x == 0 && std::signbit(x) == 0;

4
投票

无法从常量表达式中查看

double
的基础位模式。 C++11 标准中存在一个缺陷,允许通过
void*
进行强制转换来进行此类检查,但这已由 C++ 核心问题 1312 解决。

作为“证明”,clang 的

constexpr
实现(被认为是完整的)没有用于提取常量
double
值表示的机制(除了通过非标准向量运算,即使这样,目前也没有检查结果的方法)。

正如其他人所建议的,如果您知道您将针对使用 IEEE-754 浮点的平台,则

0x0
对应于正零值。我相信检测这一点的唯一方法(在 clang 和 g++ 中的常量表达式中都有效)是使用
__builtin_copysign
:

constexpr bool isPosZero(double d) {
  return d == 0.0 && __builtin_copysign(1.0, d) == 1.0;
}

0
投票

在 c++20 中,可以使用 constexpr bit_cast,因此可以像这样检查无符号零:

std::bit_cast(d) == 0

© www.soinside.com 2019 - 2024. All rights reserved.