File indexing completed on 2025-01-30 09:45:15
0001
0002
0003
0004
0005
0006 #ifndef BOOST_MATH_CCMATH_SIGNBIT_HPP
0007 #define BOOST_MATH_CCMATH_SIGNBIT_HPP
0008
0009 #include <boost/math/ccmath/detail/config.hpp>
0010
0011 #ifdef BOOST_MATH_NO_CCMATH
0012 #error "The header <boost/math/signbit.hpp> can only be used in C++17 and later."
0013 #endif
0014
0015 #include <cstdint>
0016 #include <boost/math/tools/assert.hpp>
0017 #include <boost/math/special_functions/detail/fp_traits.hpp>
0018 #include <boost/math/ccmath/isnan.hpp>
0019 #include <boost/math/ccmath/abs.hpp>
0020
0021 #ifdef __has_include
0022 # if __has_include(<bit>)
0023 # include <bit>
0024 # if __cpp_lib_bit_cast >= 201806L
0025 # define BOOST_MATH_BIT_CAST(T, x) std::bit_cast<T>(x)
0026 # endif
0027 # elif defined(__has_builtin)
0028 # if __has_builtin(__builtin_bit_cast)
0029 # define BOOST_MATH_BIT_CAST(T, x) __builtin_bit_cast(T, x)
0030 # endif
0031 # endif
0032 #endif
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049 #if defined(__clang__) && defined(BOOST_MATH_BIT_CAST)
0050 # undef BOOST_MATH_BIT_CAST
0051 #endif
0052
0053 namespace boost::math::ccmath {
0054
0055 namespace detail {
0056
0057 #ifdef BOOST_MATH_BIT_CAST
0058
0059 struct IEEEf2bits
0060 {
0061 #if BOOST_MATH_ENDIAN_LITTLE_BYTE
0062 std::uint32_t mantissa : 23;
0063 std::uint32_t exponent : 8;
0064 std::uint32_t sign : 1;
0065 #else
0066 std::uint32_t sign : 1;
0067 std::uint32_t exponent : 8;
0068 std::uint32_t mantissa : 23;
0069 #endif
0070 };
0071
0072 struct IEEEd2bits
0073 {
0074 #if BOOST_MATH_ENDIAN_LITTLE_BYTE
0075 std::uint32_t mantissa_l : 32;
0076 std::uint32_t mantissa_h : 20;
0077 std::uint32_t exponent : 11;
0078 std::uint32_t sign : 1;
0079 #else
0080 std::uint32_t sign : 1;
0081 std::uint32_t exponent : 11;
0082 std::uint32_t mantissa_h : 20;
0083 std::uint32_t mantissa_l : 32;
0084 #endif
0085 };
0086
0087
0088 #if LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384
0089
0090 struct IEEEl2bits
0091 {
0092 #if BOOST_MATH_ENDIAN_LITTLE_BYTE
0093 std::uint32_t mantissa_l : 32;
0094 std::uint32_t mantissa_h : 32;
0095 std::uint32_t exponent : 15;
0096 std::uint32_t sign : 1;
0097 std::uint32_t pad : 32;
0098 #else
0099 std::uint32_t pad : 32;
0100 std::uint32_t sign : 1;
0101 std::uint32_t exponent : 15;
0102 std::uint32_t mantissa_h : 32;
0103 std::uint32_t mantissa_l : 32;
0104 #endif
0105 };
0106
0107
0108 #elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384
0109
0110 struct IEEEl2bits
0111 {
0112 #if BOOST_MATH_ENDIAN_LITTLE_BYTE
0113 std::uint64_t mantissa_l : 64;
0114 std::uint64_t mantissa_h : 48;
0115 std::uint32_t exponent : 15;
0116 std::uint32_t sign : 1;
0117 #else
0118 std::uint32_t sign : 1;
0119 std::uint32_t exponent : 15;
0120 std::uint64_t mantissa_h : 48;
0121 std::uint64_t mantissa_l : 64;
0122 #endif
0123 };
0124
0125
0126 #elif LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
0127
0128 struct IEEEl2bits
0129 {
0130 #if BOOST_MATH_ENDIAN_LITTLE_BYTE
0131 std::uint32_t mantissa_l : 32;
0132 std::uint32_t mantissa_h : 20;
0133 std::uint32_t exponent : 11;
0134 std::uint32_t sign : 1;
0135 #else
0136 std::uint32_t sign : 1;
0137 std::uint32_t exponent : 11;
0138 std::uint32_t mantissa_h : 20;
0139 std::uint32_t mantissa_l : 32;
0140 #endif
0141 };
0142
0143 #else
0144 # define BOOST_MATH_UNSUPPORTED_LONG_DOUBLE
0145 #endif
0146
0147 template <typename T>
0148 constexpr bool signbit_impl(T arg)
0149 {
0150 if constexpr (std::is_same_v<T, float>)
0151 {
0152 const auto u = BOOST_MATH_BIT_CAST(IEEEf2bits, arg);
0153 return u.sign;
0154 }
0155 else if constexpr (std::is_same_v<T, double>)
0156 {
0157 const auto u = BOOST_MATH_BIT_CAST(IEEEd2bits, arg);
0158 return u.sign;
0159 }
0160 #ifndef BOOST_MATH_UNSUPPORTED_LONG_DOUBLE
0161 else if constexpr (std::is_same_v<T, long double>)
0162 {
0163 const auto u = BOOST_MATH_BIT_CAST(IEEEl2bits, arg);
0164 return u.sign;
0165 }
0166 #endif
0167 else
0168 {
0169 BOOST_MATH_ASSERT_MSG(!boost::math::ccmath::isnan(arg), "NAN is not supported with this type or platform");
0170 BOOST_MATH_ASSERT_MSG(boost::math::ccmath::abs(arg) != 0, "Signed 0 is not support with this type or platform");
0171
0172 return arg < static_cast<T>(0);
0173 }
0174 }
0175
0176 #else
0177
0178
0179
0180
0181
0182
0183 template <typename T>
0184 constexpr bool signbit_impl(T arg)
0185 {
0186 BOOST_MATH_ASSERT_MSG(!boost::math::ccmath::isnan(arg), "NAN is not supported without __builtin_bit_cast or std::bit_cast");
0187 BOOST_MATH_ASSERT_MSG(boost::math::ccmath::abs(arg) != 0, "Signed 0 is not support without __builtin_bit_cast or std::bit_cast");
0188
0189 return arg < static_cast<T>(0);
0190 }
0191
0192 #endif
0193
0194 }
0195
0196
0197 template <typename Real, std::enable_if_t<!std::is_integral_v<Real>, bool> = true>
0198 constexpr bool signbit(Real arg)
0199 {
0200 if (BOOST_MATH_IS_CONSTANT_EVALUATED(arg))
0201 {
0202 return boost::math::ccmath::detail::signbit_impl(arg);
0203 }
0204 else
0205 {
0206 using std::signbit;
0207 return signbit(arg);
0208 }
0209 }
0210
0211 template <typename Z, std::enable_if_t<std::is_integral_v<Z>, bool> = true>
0212 constexpr bool signbit(Z arg)
0213 {
0214 return boost::math::ccmath::signbit(static_cast<double>(arg));
0215 }
0216
0217 }
0218
0219 #endif