sign.hpp 5.5 KB

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