cmath.hpp 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  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 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(_MSC_VER) && _MSC_VER < 1800
  17. # include <float.h>
  18. #endif
  19. namespace boost
  20. {
  21. namespace core
  22. {
  23. #if defined(_MSC_VER) && _MSC_VER < 1800
  24. template<class T> T copysign( T x, T y )
  25. {
  26. return static_cast<T>( _copysign( static_cast<double>( x ), static_cast<double>( y ) ) );
  27. }
  28. template<class T> bool isnan( T x )
  29. {
  30. return _isnan( static_cast<double>( x ) ) != 0;
  31. }
  32. template<class T> bool isfinite( T x )
  33. {
  34. return _finite( static_cast<double>( x ) ) != 0;
  35. }
  36. template<class T> bool isinf( T x )
  37. {
  38. return ( _fpclass( static_cast<double>( x ) ) & ( _FPCLASS_PINF | _FPCLASS_NINF ) ) != 0;
  39. }
  40. inline bool isnormal( float x )
  41. {
  42. // no _fpclassf in 32 bit mode
  43. unsigned y = reinterpret_cast< unsigned const& >( x );
  44. unsigned exp = ( y >> 23 ) & 0xFF;
  45. return exp != 0 && exp != 0xFF;
  46. }
  47. inline bool isnormal( double x )
  48. {
  49. return ( _fpclass( x ) & ( _FPCLASS_PN | _FPCLASS_NN ) ) != 0;
  50. }
  51. inline bool isnormal( long double x )
  52. {
  53. return boost::core::isnormal( static_cast<double>( x ) );
  54. }
  55. template<class T> bool signbit( T x )
  56. {
  57. return _copysign( 1.0, static_cast<double>( x ) ) < 0.0;
  58. }
  59. int const fp_zero = 0;
  60. int const fp_subnormal = 1;
  61. int const fp_normal = 2;
  62. int const fp_infinite = 3;
  63. int const fp_nan = 4;
  64. inline int fpclassify( float x )
  65. {
  66. switch( _fpclass( x ) )
  67. {
  68. case _FPCLASS_SNAN:
  69. case _FPCLASS_QNAN:
  70. return fp_nan;
  71. case _FPCLASS_NINF:
  72. case _FPCLASS_PINF:
  73. return fp_infinite;
  74. case _FPCLASS_NZ:
  75. case _FPCLASS_PZ:
  76. return fp_zero;
  77. default:
  78. return boost::core::isnormal( x )? fp_normal: fp_subnormal;
  79. }
  80. }
  81. inline int fpclassify( double x )
  82. {
  83. switch( _fpclass( x ) )
  84. {
  85. case _FPCLASS_SNAN:
  86. case _FPCLASS_QNAN:
  87. return fp_nan;
  88. case _FPCLASS_NINF:
  89. case _FPCLASS_PINF:
  90. return fp_infinite;
  91. case _FPCLASS_NZ:
  92. case _FPCLASS_PZ:
  93. return fp_zero;
  94. case _FPCLASS_ND:
  95. case _FPCLASS_PD:
  96. return fp_subnormal;
  97. default:
  98. return fp_normal;
  99. }
  100. }
  101. inline int fpclassify( long double x )
  102. {
  103. return boost::core::fpclassify( static_cast<double>( x ) );
  104. }
  105. #else
  106. using std::isfinite;
  107. using std::isnan;
  108. using std::isinf;
  109. using std::isnormal;
  110. using std::fpclassify;
  111. int const fp_zero = FP_ZERO;
  112. int const fp_subnormal = FP_SUBNORMAL;
  113. int const fp_normal = FP_NORMAL;
  114. int const fp_infinite = FP_INFINITE;
  115. int const fp_nan = FP_NAN;
  116. using std::signbit;
  117. // std::copysign doesn't exist in libstdc++ under -std=c++03
  118. #if !defined(__GNUC__)
  119. template<class T> T copysign( T x, T y )
  120. {
  121. return std::copysign( x, y );
  122. }
  123. #else
  124. namespace detail
  125. {
  126. // ::copysignl is unreliable, use the built-ins
  127. inline float copysign_impl( float x, float y )
  128. {
  129. return __builtin_copysignf( x, y );
  130. }
  131. inline double copysign_impl( double x, double y )
  132. {
  133. return __builtin_copysign( x, y );
  134. }
  135. inline long double copysign_impl( long double x, long double y )
  136. {
  137. return __builtin_copysignl( x, y );
  138. }
  139. } // namespace detail
  140. template<class T> T copysign( T x, T y )
  141. {
  142. return boost::core::detail::copysign_impl( x, y );
  143. }
  144. #endif // !defined(__GNUC__)
  145. #endif // #if defined(_MSC_VER) && _MSC_VER < 1800
  146. } // namespace core
  147. } // namespace boost
  148. #endif // #ifndef BOOST_CORE_CMATH_HPP_INCLUDED