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

发布于 2025-01-06 04:30:37 字数 1064 浏览 2 评论 0原文

我想检查给定的双精度/浮点变量是否具有实际的位模式 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; }
                                       ^

还有其他人有好主意吗?

I want to check that a given double/float variable has the actual bit pattern 0x0. Don't ask why, it's used in a function in Qt (qIsNull()) that I'd like to be constexpr.

The original code used a union:

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

This doesn't work as a constexpr of course.

The next try was with reinterpret_cast:

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

But while that works as a constexpr in GCC 4.7, it fails (rightfully, b/c of pointer manipulation) in Clang 3.1.

The final idea was to go Alexandrescuesque and do this:

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

But that's not clever enough for Clang, either:

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

Does anyone else have a good idea?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

守护在此方 2025-01-13 04:30:37

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

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

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

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

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

I want to check that a given double/float variable has the actual bit pattern 0x0

But if it's constexpr then it's not checking any variable, it's checking the value that this variable is statically determined to hold. That's why you aren't supposed to pull pointer and union tricks, "officially" there isn't any memory to point at.

If you can persuade your implementation to do non-trapping IEEE division-by-zero, then you could do something like:

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

Only +/-0 are equal to 0. 1/-0 is -Inf, which isn't greater than 0. 1/+0 is +Inf, which is. But I don't know how to make that non-trapping arithmetic happen.

抠脚大汉 2025-01-13 04:30:37

似乎 clang++ 3.0 和 g++ 4.7(但不是 4.6)都将 std::signbit 视为 constexpr。

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

It seems both clang++ 3.0 and g++ 4.7 (but not 4.6) treats std::signbit as constexpr.

return x == 0 && std::signbit(x) == 0;
巷子口的你 2025-01-13 04:30:37

无法从常量表达式中查看 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;
}

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;
}
恰似旧人归 2025-01-13 04:30:37

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

std::bit_cast(d) == 0

In c++20 one can use constexpr bit_cast, and so the check for the unsigned zero can be done like this:

std::bit_cast<uint64_t, double>(d) == 0

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文