如何编写可移植的constexpr std::copysign()?
How to write a portable constexpr std::copysign()?
特别是,它必须像 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 和其他编译器上编译。
如果可以使用std::bit_cast
,则可以操作转换为整数类型的浮点类型。可移植性仅限于 double
的表示,但如果您可以假定 IEEE 754 双精度二进制浮点格式,则转换为 uint64_t 并使用符号位应该可以。
__builtin...
的使用并不是真正的可移植,但在作为目标提到的编译器中有效。 __builtin_copysign
是 conexpr,但 __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() {}
P0533:现在接受 <cmath>
和 <cstdlib>
的 constexpr。
从 C++23 开始,您可以只使用 std::copysign
和 std::syncbit
。
特别是,它必须像 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 和其他编译器上编译。
如果可以使用std::bit_cast
,则可以操作转换为整数类型的浮点类型。可移植性仅限于 double
的表示,但如果您可以假定 IEEE 754 双精度二进制浮点格式,则转换为 uint64_t 并使用符号位应该可以。
__builtin...
的使用并不是真正的可移植,但在作为目标提到的编译器中有效。 __builtin_copysign
是 conexpr,但 __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() {}
P0533:现在接受 <cmath>
和 <cstdlib>
的 constexpr。
从 C++23 开始,您可以只使用 std::copysign
和 std::syncbit
。