Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-30 09:45:15

0001 //  (C) Copyright Matt Borland 2022.
0002 //  Use, modification and distribution are subject to the
0003 //  Boost Software License, Version 1.0. (See accompanying file
0004 //  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
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 The following error is given using Apple Clang version 13.1.6, and Clang 13, and 14 on Ubuntu 22.04.01
0036 TODO: Remove the following undef when Apple Clang supports
0037 
0038 ccmath_signbit_test.cpp:32:19: error: static_assert expression is not an integral constant expression
0039     static_assert(boost::math::ccmath::signbit(T(-1)) == true);
0040                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0041 ../../../boost/math/ccmath/signbit.hpp:62:24: note: constexpr bit_cast involving bit-field is not yet supported
0042         const auto u = BOOST_MATH_BIT_CAST(float_bits, arg);
0043                        ^
0044 ../../../boost/math/ccmath/signbit.hpp:20:37: note: expanded from macro 'BOOST_MATH_BIT_CAST'
0045 #  define BOOST_MATH_BIT_CAST(T, x) __builtin_bit_cast(T, x)
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 // Big endian
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 // Big endian
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 // 80 bit long double
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 // Big endian
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 // 128 bit long double
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 // Big endian
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 // 64 bit long double (double == long double on ARM)
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 // Big endian
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 // Unsupported long double representation
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 // Typical implementations of signbit involve type punning via union and manipulating
0179 // overflow (see libc++ or musl). Neither of these are allowed in constexpr contexts
0180 // (technically type punning via union in general is UB in c++ but well defined in C) 
0181 // therefore we static assert these cases.
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 // Return value: true if arg is negative, false if arg is 0, NAN, or positive
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 } // Namespaces
0218 
0219 #endif // BOOST_MATH_CCMATH_SIGNBIT_HPP