9

我想检查给定的双精度/浮点变量是否具有实际的位模式 0x0。不要问为什么,它被用在qIsNull()我想成为的 Qt ()中的一个函数中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 中作为 a 起作用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; }
                                       ^

还有其他人有什么好主意吗?

4

3 回答 3

6

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

但如果是constexpr这样,它就不会检查任何变量,而是检查这个变量被静态确定持有的值。这就是为什么你不应该使用指针和联合技巧,“官方”没有任何内存可以指向。

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

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

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

于 2012-02-17T13:49:08.990 回答
5

似乎 clang++ 3.0 和 g++ 4.7(但不是 4.6)都std::signbitconstexpr.

return x == 0 && std::signbit(x) == 0;
于 2012-02-17T13:54:31.500 回答
4

It is not possible to look at the underlying bit pattern of a double from within a constant expression. There was a defect in the C++11 standard which allowed such inspection by casting via a void*, but that was addressed by C++ core issue 1312.

As "proof", clang's constexpr implementation (which is considered to be complete) has no mechanism for extracting the representation of a constant double value (other than via non-standard vector operations, and even then there is currently no way to inspect the result).

As others have suggested, if you know you will be targeting a platform which uses IEEE-754 floating point, 0x0 corresponds to the value positive zero. I believe the only way to detect this, that works inside a constant expression in both clang and g++, is to use __builtin_copysign:

constexpr bool isPosZero(double d) {
  return d == 0.0 && __builtin_copysign(1.0, d) == 1.0;
}
于 2012-03-02T06:06:05.387 回答