如何实现可移植的constexpr版std::copysign与std::signbit,兼容NaN场景
可移植constexpr版
copysign与signbit实现 实现思路
基于C++20标准提供的std::bit_cast直接操作IEEE 754双精度浮点数的符号位,不依赖特定编译器内置函数,可同时正确处理常规浮点数与NaN的符号:
- 双精度浮点数最高位(第63位)为符号位,掩码值为
0x8000000000000000ULL signbit直接判断符号位是否为1即可copysign将幅值参数的符号位清空后,或上符号参数的符号位即可实现符号拷贝
完整实现代码
#include <bit> #include <limits> #include <cstdint> constexpr bool signbit(double arg) noexcept { // 双精度浮点数转uint64后判断最高位 return (std::bit_cast<std::uint64_t>(arg) & 0x8000000000000000ULL) != 0; } constexpr double copysign(double mag, double sgn) noexcept { const std::uint64_t mag_bits = std::bit_cast<std::uint64_t>(mag) & 0x7FFFFFFFFFFFFFFFULL; const std::uint64_t sgn_bits = std::bit_cast<std::uint64_t>(sgn) & 0x8000000000000000ULL; return std::bit_cast<double>(mag_bits | sgn_bits); } // 正负NaN生成代码 constexpr double nan_pos = copysign(std::numeric_limits<double>::quiet_NaN(), +1); constexpr double nan_neg = copysign(std::numeric_limits<double>::quiet_NaN(), -1); // 校验代码 static_assert(signbit(nan_pos) == false); static_assert(signbit(nan_neg) == true);
以上实现在GCC 11+、Clang 13+版本上均可正常通过编译校验。
兼容降级方案
如果需要兼容C++20之前的标准,可使用编译器内置函数做兜底,GCC、Clang均支持以下内置函数的constexpr调用:
#if defined(__GNUC__) || defined(__clang__) constexpr bool signbit(double arg) noexcept { return __builtin_signbit(arg); } constexpr double copysign(double mag, double sgn) noexcept { return __builtin_copysign(mag, sgn); } #endif
内容的提问来源于stack exchange,提问作者Hank
相关产品推荐
相关产品推荐

