Line data Source code
1 : // (C) Copyright John Maddock 2006. 2 : // (C) Copyright Johan Rade 2006. 3 : // (C) Copyright Paul A. Bristow 2011 (added changesign). 4 : 5 : // Use, modification and distribution are subject to the 6 : // Boost Software License, Version 1.0. (See accompanying file 7 : // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 8 : 9 : #ifndef BOOST_MATH_TOOLS_SIGN_HPP 10 : #define BOOST_MATH_TOOLS_SIGN_HPP 11 : 12 : #ifdef _MSC_VER 13 : #pragma once 14 : #endif 15 : 16 : #include <boost/math/tools/config.hpp> 17 : #include <boost/math/special_functions/math_fwd.hpp> 18 : #include <boost/math/special_functions/detail/fp_traits.hpp> 19 : 20 : namespace boost{ namespace math{ 21 : 22 : namespace detail { 23 : 24 : // signbit 25 : 26 : #ifdef BOOST_MATH_USE_STD_FPCLASSIFY 27 : template<class T> 28 0 : inline int signbit_impl(T x, native_tag const&) 29 : { 30 0 : return (std::signbit)(x) ? 1 : 0; 31 : } 32 : #endif 33 : 34 : // Generic versions first, note that these do not handle 35 : // signed zero or NaN. 36 : 37 : template<class T> 38 : inline int signbit_impl(T x, generic_tag<true> const&) 39 : { 40 : return x < 0; 41 : } 42 : 43 : template<class T> 44 : inline int signbit_impl(T x, generic_tag<false> const&) 45 : { 46 : return x < 0; 47 : } 48 : 49 : #if defined(__GNUC__) && (LDBL_MANT_DIG == 106) 50 : // 51 : // Special handling for GCC's "double double" type, 52 : // in this case the sign is the same as the sign we 53 : // get by casting to double, no overflow/underflow 54 : // can occur since the exponents are the same magnitude 55 : // for the two types: 56 : // 57 : inline int signbit_impl(long double x, generic_tag<true> const&) 58 : { 59 : return (boost::math::signbit)(static_cast<double>(x)); 60 : } 61 : inline int signbit_impl(long double x, generic_tag<false> const&) 62 : { 63 : return (boost::math::signbit)(static_cast<double>(x)); 64 : } 65 : #endif 66 : 67 : template<class T> 68 : inline int signbit_impl(T x, ieee_copy_all_bits_tag const&) 69 : { 70 : typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits; 71 : 72 : BOOST_DEDUCED_TYPENAME traits::bits a; 73 : traits::get_bits(x,a); 74 : return a & traits::sign ? 1 : 0; 75 : } 76 : 77 : template<class T> 78 : inline int signbit_impl(T x, ieee_copy_leading_bits_tag const&) 79 : { 80 : typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits; 81 : 82 : BOOST_DEDUCED_TYPENAME traits::bits a; 83 : traits::get_bits(x,a); 84 : 85 : return a & traits::sign ? 1 : 0; 86 : } 87 : 88 : // Changesign 89 : 90 : // Generic versions first, note that these do not handle 91 : // signed zero or NaN. 92 : 93 : template<class T> 94 : inline T (changesign_impl)(T x, generic_tag<true> const&) 95 : { 96 : return -x; 97 : } 98 : 99 : template<class T> 100 : inline T (changesign_impl)(T x, generic_tag<false> const&) 101 : { 102 : return -x; 103 : } 104 : #if defined(__GNUC__) && (LDBL_MANT_DIG == 106) 105 : // 106 : // Special handling for GCC's "double double" type, 107 : // in this case we need to change the sign of both 108 : // components of the "double double": 109 : // 110 : inline long double (changesign_impl)(long double x, generic_tag<true> const&) 111 : { 112 : double* pd = reinterpret_cast<double*>(&x); 113 : pd[0] = boost::math::changesign(pd[0]); 114 : pd[1] = boost::math::changesign(pd[1]); 115 : return x; 116 : } 117 : inline long double (changesign_impl)(long double x, generic_tag<false> const&) 118 : { 119 : double* pd = reinterpret_cast<double*>(&x); 120 : pd[0] = boost::math::changesign(pd[0]); 121 : pd[1] = boost::math::changesign(pd[1]); 122 : return x; 123 : } 124 : #endif 125 : 126 : template<class T> 127 : inline T changesign_impl(T x, ieee_copy_all_bits_tag const&) 128 : { 129 : typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::sign_change_type traits; 130 : 131 : BOOST_DEDUCED_TYPENAME traits::bits a; 132 : traits::get_bits(x,a); 133 : a ^= traits::sign; 134 : traits::set_bits(x,a); 135 : return x; 136 : } 137 : 138 : template<class T> 139 : inline T (changesign_impl)(T x, ieee_copy_leading_bits_tag const&) 140 : { 141 : typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::sign_change_type traits; 142 : 143 : BOOST_DEDUCED_TYPENAME traits::bits a; 144 : traits::get_bits(x,a); 145 : a ^= traits::sign; 146 : traits::set_bits(x,a); 147 : return x; 148 : } 149 : 150 : 151 : } // namespace detail 152 : 153 0 : template<class T> int (signbit)(T x) 154 : { 155 : typedef typename detail::fp_traits<T>::type traits; 156 : typedef typename traits::method method; 157 : // typedef typename boost::is_floating_point<T>::type fp_tag; 158 : typedef typename tools::promote_args_permissive<T>::type result_type; 159 0 : return detail::signbit_impl(static_cast<result_type>(x), method()); 160 : } 161 : 162 : template <class T> 163 : inline int sign BOOST_NO_MACRO_EXPAND(const T& z) 164 : { 165 : return (z == 0) ? 0 : (boost::math::signbit)(z) ? -1 : 1; 166 : } 167 : 168 : template <class T> typename tools::promote_args_permissive<T>::type (changesign)(const T& x) 169 : { //!< \brief return unchanged binary pattern of x, except for change of sign bit. 170 : typedef typename detail::fp_traits<T>::sign_change_type traits; 171 : typedef typename traits::method method; 172 : // typedef typename boost::is_floating_point<T>::type fp_tag; 173 : typedef typename tools::promote_args_permissive<T>::type result_type; 174 : 175 : return detail::changesign_impl(static_cast<result_type>(x), method()); 176 : } 177 : 178 : template <class T, class U> 179 : inline typename tools::promote_args_permissive<T, U>::type 180 : copysign BOOST_NO_MACRO_EXPAND(const T& x, const U& y) 181 : { 182 : BOOST_MATH_STD_USING 183 : typedef typename tools::promote_args_permissive<T, U>::type result_type; 184 : return (boost::math::signbit)(static_cast<result_type>(x)) != (boost::math::signbit)(static_cast<result_type>(y)) 185 : ? (boost::math::changesign)(static_cast<result_type>(x)) : static_cast<result_type>(x); 186 : } 187 : 188 : } // namespace math 189 : } // namespace boost 190 : 191 : 192 : #endif // BOOST_MATH_TOOLS_SIGN_HPP 193 : 194 :