cmath.hpp 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. #ifndef BOOST_CORE_CMATH_HPP_INCLUDED
  2. #define BOOST_CORE_CMATH_HPP_INCLUDED
  3. // MS compatible compilers support #pragma once
  4. #if defined(_MSC_VER) && (_MSC_VER >= 1020)
  5. # pragma once
  6. #endif
  7. // boost/core/cmath.hpp
  8. //
  9. // Floating point classification and sign manipulation functions
  10. // Extracted from https://github.com/boostorg/lexical_cast/pull/37
  11. //
  12. // Copyright 2020, 2021 Peter Dimov
  13. // Distributed under the Boost Software License, Version 1.0.
  14. // https://www.boost.org/LICENSE_1_0.txt
  15. #include <cmath>
  16. #if defined(BOOST_CORE_USE_GENERIC_CMATH) || (!defined(_MSC_VER) && !defined(FP_SUBNORMAL))
  17. #include <boost/cstdint.hpp>
  18. #include <boost/static_assert.hpp>
  19. #include <limits>
  20. #include <cstring>
  21. namespace boost
  22. {
  23. namespace core
  24. {
  25. // fpclassify return values
  26. int const fp_zero = 0;
  27. int const fp_subnormal = 1;
  28. int const fp_normal = 2;
  29. int const fp_infinite = 3;
  30. int const fp_nan = 4;
  31. // Classification functions
  32. template<class T> bool isfinite( T x )
  33. {
  34. return x <= (std::numeric_limits<T>::max)() && x >= -(std::numeric_limits<T>::max)();
  35. }
  36. template<class T> bool isinf( T x )
  37. {
  38. return x > (std::numeric_limits<T>::max)() || x < -(std::numeric_limits<T>::max)();
  39. }
  40. template<class T> bool isnan( T x )
  41. {
  42. return !isfinite( x ) && !isinf( x );
  43. }
  44. template<class T> bool isnormal( T x )
  45. {
  46. return isfinite( x ) && ( x >= (std::numeric_limits<T>::min)() || x <= -(std::numeric_limits<T>::min)() );
  47. }
  48. template<class T> int fpclassify( T x )
  49. {
  50. if( x == 0 ) return fp_zero;
  51. if( x < 0 ) x = -x;
  52. if( x > (std::numeric_limits<T>::max)() ) return fp_infinite;
  53. if( x >= (std::numeric_limits<T>::min)() ) return fp_normal;
  54. if( x < (std::numeric_limits<T>::min)() ) return fp_subnormal;
  55. return fp_nan;
  56. }
  57. // Sign manipulation functions
  58. inline bool signbit( float x )
  59. {
  60. boost::int32_t y;
  61. BOOST_STATIC_ASSERT( sizeof( x ) == sizeof( y ) );
  62. std::memcpy( &y, &x, sizeof( y ) );
  63. return y < 0;
  64. }
  65. inline bool signbit( double x )
  66. {
  67. boost::int64_t y;
  68. BOOST_STATIC_ASSERT( sizeof( x ) == sizeof( y ) );
  69. std::memcpy( &y, &x, sizeof( y ) );
  70. return y < 0;
  71. }
  72. inline bool signbit( long double x )
  73. {
  74. return signbit( static_cast<double>( x ) );
  75. }
  76. template<class T> T copysign( T x, T y )
  77. {
  78. return signbit( x ) == signbit( y )? x: -x;
  79. }
  80. } // namespace core
  81. } // namespace boost
  82. #else // defined(BOOST_CORE_USE_GENERIC_CMATH)
  83. #if defined(_MSC_VER) && _MSC_VER < 1800
  84. # include <float.h>
  85. #endif
  86. namespace boost
  87. {
  88. namespace core
  89. {
  90. #if defined(_MSC_VER) && _MSC_VER < 1800
  91. template<class T> T copysign( T x, T y )
  92. {
  93. return static_cast<T>( _copysign( static_cast<double>( x ), static_cast<double>( y ) ) );
  94. }
  95. template<class T> bool isnan( T x )
  96. {
  97. return _isnan( static_cast<double>( x ) ) != 0;
  98. }
  99. template<class T> bool isfinite( T x )
  100. {
  101. return _finite( static_cast<double>( x ) ) != 0;
  102. }
  103. template<class T> bool isinf( T x )
  104. {
  105. return ( _fpclass( static_cast<double>( x ) ) & ( _FPCLASS_PINF | _FPCLASS_NINF ) ) != 0;
  106. }
  107. inline bool isnormal( float x )
  108. {
  109. // no _fpclassf in 32 bit mode
  110. unsigned y = reinterpret_cast< unsigned const& >( x );
  111. unsigned exp = ( y >> 23 ) & 0xFF;
  112. return exp != 0 && exp != 0xFF;
  113. }
  114. inline bool isnormal( double x )
  115. {
  116. return ( _fpclass( x ) & ( _FPCLASS_PN | _FPCLASS_NN ) ) != 0;
  117. }
  118. inline bool isnormal( long double x )
  119. {
  120. return boost::core::isnormal( static_cast<double>( x ) );
  121. }
  122. template<class T> bool signbit( T x )
  123. {
  124. return _copysign( 1.0, static_cast<double>( x ) ) < 0.0;
  125. }
  126. int const fp_zero = 0;
  127. int const fp_subnormal = 1;
  128. int const fp_normal = 2;
  129. int const fp_infinite = 3;
  130. int const fp_nan = 4;
  131. inline int fpclassify( float x )
  132. {
  133. switch( _fpclass( x ) )
  134. {
  135. case _FPCLASS_SNAN:
  136. case _FPCLASS_QNAN:
  137. return fp_nan;
  138. case _FPCLASS_NINF:
  139. case _FPCLASS_PINF:
  140. return fp_infinite;
  141. case _FPCLASS_NZ:
  142. case _FPCLASS_PZ:
  143. return fp_zero;
  144. default:
  145. return boost::core::isnormal( x )? fp_normal: fp_subnormal;
  146. }
  147. }
  148. inline int fpclassify( double x )
  149. {
  150. switch( _fpclass( x ) )
  151. {
  152. case _FPCLASS_SNAN:
  153. case _FPCLASS_QNAN:
  154. return fp_nan;
  155. case _FPCLASS_NINF:
  156. case _FPCLASS_PINF:
  157. return fp_infinite;
  158. case _FPCLASS_NZ:
  159. case _FPCLASS_PZ:
  160. return fp_zero;
  161. case _FPCLASS_ND:
  162. case _FPCLASS_PD:
  163. return fp_subnormal;
  164. default:
  165. return fp_normal;
  166. }
  167. }
  168. inline int fpclassify( long double x )
  169. {
  170. return boost::core::fpclassify( static_cast<double>( x ) );
  171. }
  172. #else
  173. using std::isfinite;
  174. using std::isnan;
  175. using std::isinf;
  176. using std::isnormal;
  177. using std::fpclassify;
  178. int const fp_zero = FP_ZERO;
  179. int const fp_subnormal = FP_SUBNORMAL;
  180. int const fp_normal = FP_NORMAL;
  181. int const fp_infinite = FP_INFINITE;
  182. int const fp_nan = FP_NAN;
  183. using std::signbit;
  184. // std::copysign doesn't exist in libstdc++ under -std=c++03
  185. #if !defined(__GNUC__)
  186. template<class T> T copysign( T x, T y )
  187. {
  188. return std::copysign( x, y );
  189. }
  190. #else
  191. namespace detail
  192. {
  193. // ::copysignl is unreliable, use the built-ins
  194. inline float copysign_impl( float x, float y )
  195. {
  196. return __builtin_copysignf( x, y );
  197. }
  198. inline double copysign_impl( double x, double y )
  199. {
  200. return __builtin_copysign( x, y );
  201. }
  202. inline long double copysign_impl( long double x, long double y )
  203. {
  204. return __builtin_copysignl( x, y );
  205. }
  206. } // namespace detail
  207. template<class T> T copysign( T x, T y )
  208. {
  209. return boost::core::detail::copysign_impl( x, y );
  210. }
  211. #endif // !defined(__GNUC__)
  212. #endif // #if defined(_MSC_VER) && _MSC_VER < 1800
  213. } // namespace core
  214. } // namespace boost
  215. #endif // defined(BOOST_CORE_USE_GENERIC_CMATH)
  216. #endif // #ifndef BOOST_CORE_CMATH_HPP_INCLUDED