【问题标题】:How to write a portable constexpr std::copysign()?如何编写可移植的 constexpr std::copysign()?
【发布时间】:2021-11-14 11:46:22
【问题描述】:

特别是,它必须像 std::copysign 那样与 NaN 一起工作。同样,我需要一个 constexpr std::signbit

constexpr double copysign(double mag, double sgn)
{
    // how?
}

constexpr bool signbit(double arg)
{
    // how?
}

// produce the two types of NaNs
constexpr double nan_pos = copysign(std::numeric_limits<double>::quiet_NaN(), +1);
constexpr double nan_neg = copysign(std::numeric_limits<double>::quiet_NaN(), -1);

// must pass the checks
static_assert(signbit(nan_pos) == false);
static_assert(signbit(nan_neg) == true);

背后的故事是我在编译时需要两种类型的 NaN,以及区分它们的方法。我能想到的最直接的方法是操纵 NaN 的符号位。它确实在运行时工作;现在我只想将一些计算转移到编译时间,这是最后一个障碍。

注意:目前,我依赖 GCC,因为它具有这些函数的内置版本,它们确实是 constexpr,这很好。但我希望我的代码库也能在 Clang 和其他编译器上编译。

【问题讨论】:

  • 正负无穷对您来说是有效值吗?如果没有,您可以将它们用作您的两个哨兵值。
  • 我们考虑过无穷大,但它们不适合代码库。不幸的是,它必须是 NaN。
  • std::nan("1")std::nan("2") 有什么问题?
  • @Eljay 这些不是 constexpr。
  • @NathanOliver • 嗯...那很不幸!

标签: c++ math nan constexpr


【解决方案1】:

P0533:现在接受 &lt;cmath&gt;&lt;cstdlib&gt; 的 constexpr。

从 C++23 开始,您可以只使用 std::copysignstd::syncbit

【讨论】:

    【解决方案2】:

    __builtin... 的使用并不是真正的可移植,但可以在提到的目标编译器中使用。 __builtin_copysign 是contexpr,但__builtin_signbit 显然不在clang,所以signbit__builtin_copysign

    #include <limits>
    
    constexpr double copysign(double mag, double sgn)
    {
        return __builtin_copysign(mag, sgn);
    }
    
    constexpr bool signbit(double arg)
    {
        return __builtin_copysign(1, arg) <  0;
    }
    
    // produce the two types of NaNs
    constexpr double nan_pos = copysign(std::numeric_limits<double>::quiet_NaN(), +1);
    constexpr double nan_neg = copysign(std::numeric_limits<double>::quiet_NaN(), -1);
    
    // must pass the checks
    static_assert(signbit(nan_pos) == false);
    static_assert(signbit(nan_neg) == true);
    
    int main() {}
    

    https://godbolt.org/z/8Wafaj4a4

    【讨论】:

      【解决方案3】:

      如果您可以使用std::bit_cast,您可以将浮点类型转换为整数类型。可移植性仅限于 double 的表示形式,但如果您可以采用 IEEE 754 双精度二进制浮点格式,则转换为 uint64_t 并使用符号位应该可以工作。

      【讨论】:

      • 可能值得一提的是,std::bit_cast 仅在 c++20 中可用,根据组织和代码库的不同,不一定可用。
      • 感谢您带来bit_cast!目前我们使用的是 GCC 9 和 Clang 9;太糟糕了,我们还不能使用bit_cast。不过会记住这一点。
      猜你喜欢
      • 2020-01-12
      • 2011-05-02
      • 1970-01-01
      • 2021-07-06
      • 1970-01-01
      • 1970-01-01
      • 2013-01-10
      • 2023-01-24
      • 1970-01-01
      相关资源
      最近更新 更多