diff --git a/include/boost/math/ccmath/signbit.hpp b/include/boost/math/ccmath/signbit.hpp index 6fda4b71c..5e9449644 100644 --- a/include/boost/math/ccmath/signbit.hpp +++ b/include/boost/math/ccmath/signbit.hpp @@ -11,22 +11,27 @@ #include #include #include +#include #include #include #include -#if __cpp_lib_bit_cast >= 201806L -#include -# define BOOST_MATH_BIT_CAST(T, x) std::bit_cast(x) -#elif defined(__has_builtin) -# if __has_builtin(__builtin_bit_cast) -# define BOOST_MATH_BIT_CAST(T, x) __builtin_bit_cast(T, x) +#ifdef __has_include +# if __has_include() +# include +# if __cpp_lib_bit_cast >= 201806L +# define BOOST_MATH_BIT_CAST(T, x) std::bit_cast(x) +# endif +# elif defined(__has_builtin) +# if __has_builtin(__builtin_bit_cast) +# define BOOST_MATH_BIT_CAST(T, x) __builtin_bit_cast(T, x) +# endif # endif #endif /* -The following error is given using Apple Clang version 13.1.6 -TODO: Remove the following undef when Clang supports +The following error is given using Apple Clang version 13.1.6, and Clang 13, and 14 on Ubuntu 22.04.01 +TODO: Remove the following undef when Apple Clang supports ccmath_signbit_test.cpp:32:19: error: static_assert expression is not an integral constant expression static_assert(boost::math::ccmath::signbit(T(-1)) == true); @@ -159,11 +164,9 @@ constexpr bool signbit_impl(T arg) #endif else { - if (boost::math::ccmath::isnan(arg)) - { - return false; - } - + BOOST_MATH_ASSERT_MSG(!boost::math::ccmath::isnan(arg), "NAN is not supported with this type or platform"); + BOOST_MATH_ASSERT_MSG(boost::math::ccmath::abs(arg) != 0, "Signed 0 is not support with this type or platform"); + return arg < static_cast(0); } } @@ -173,16 +176,14 @@ constexpr bool signbit_impl(T arg) // Typical implementations of signbit involve type punning via union and manipulating // overflow (see libc++ or musl). Neither of these are allowed in constexpr contexts // (technically type punning via union in general is UB in c++ but well defined in C) -// therefore NANs and 0s are treated as positive if bit cast is unavailable +// therefore we static assert these cases. template constexpr bool signbit_impl(T arg) { - if (boost::math::ccmath::isnan(arg)) - { - return false; - } - + BOOST_MATH_ASSERT_MSG(!boost::math::ccmath::isnan(arg), "NAN is not supported without __builtin_bit_cast or std::bit_cast"); + BOOST_MATH_ASSERT_MSG(boost::math::ccmath::abs(arg) != 0, "Signed 0 is not support without __builtin_bit_cast or std::bit_cast"); + return arg < static_cast(0); } diff --git a/test/ccmath_signbit_test.cpp b/test/ccmath_signbit_test.cpp index 4c5e9f874..8985a5fb3 100644 --- a/test/ccmath_signbit_test.cpp +++ b/test/ccmath_signbit_test.cpp @@ -20,10 +20,6 @@ void test() static_assert(boost::math::ccmath::signbit(std::numeric_limits::signaling_NaN()) == false); static_assert(boost::math::ccmath::signbit(-std::numeric_limits::signaling_NaN()) == true); - #else - static_assert(boost::math::ccmath::signbit(T(0)) == false); - static_assert(boost::math::ccmath::signbit(std::numeric_limits::quiet_NaN()) == false); - static_assert(boost::math::ccmath::signbit(std::numeric_limits::signaling_NaN()) == false); #endif // Positive numbers