1 #ifndef BOOST_CORE_CMATH_HPP_INCLUDED
2 #define BOOST_CORE_CMATH_HPP_INCLUDED
4 // MS compatible compilers support #pragma once
6 #if defined(_MSC_VER) && (_MSC_VER >= 1020)
10 // boost/core/cmath.hpp
12 // Floating point classification and sign manipulation functions
13 // Extracted from https://github.com/boostorg/lexical_cast/pull/37
15 // Copyright 2020, 2021 Peter Dimov
16 // Distributed under the Boost Software License, Version 1.0.
17 // https://www.boost.org/LICENSE_1_0.txt
21 #if defined(BOOST_CORE_USE_GENERIC_CMATH) || (!defined(_MSC_VER) && !defined(FP_SUBNORMAL))
23 #include <boost/cstdint.hpp>
24 #include <boost/static_assert.hpp>
33 // fpclassify return values
35 int const fp_zero = 0;
36 int const fp_subnormal = 1;
37 int const fp_normal = 2;
38 int const fp_infinite = 3;
41 // Classification functions
43 template<class T> bool isfinite( T x )
45 return x <= (std::numeric_limits<T>::max)() && x >= -(std::numeric_limits<T>::max)();
48 template<class T> bool isinf( T x )
50 return x > (std::numeric_limits<T>::max)() || x < -(std::numeric_limits<T>::max)();
53 template<class T> bool isnan( T x )
55 return !isfinite( x ) && !isinf( x );
58 template<class T> bool isnormal( T x )
60 return isfinite( x ) && ( x >= (std::numeric_limits<T>::min)() || x <= -(std::numeric_limits<T>::min)() );
63 template<class T> int fpclassify( T x )
65 if( x == 0 ) return fp_zero;
69 if( x > (std::numeric_limits<T>::max)() ) return fp_infinite;
71 if( x >= (std::numeric_limits<T>::min)() ) return fp_normal;
73 if( x < (std::numeric_limits<T>::min)() ) return fp_subnormal;
78 // Sign manipulation functions
80 inline bool signbit( float x )
84 BOOST_STATIC_ASSERT( sizeof( x ) == sizeof( y ) );
86 std::memcpy( &y, &x, sizeof( y ) );
91 inline bool signbit( double x )
95 BOOST_STATIC_ASSERT( sizeof( x ) == sizeof( y ) );
97 std::memcpy( &y, &x, sizeof( y ) );
102 inline bool signbit( long double x )
104 return signbit( static_cast<double>( x ) );
107 template<class T> T copysign( T x, T y )
109 return signbit( x ) == signbit( y )? x: -x;
115 #else // defined(BOOST_CORE_USE_GENERIC_CMATH)
117 #if defined(_MSC_VER) && _MSC_VER < 1800
125 #if defined(_MSC_VER) && _MSC_VER < 1800
127 template<class T> T copysign( T x, T y )
129 return static_cast<T>( _copysign( static_cast<double>( x ), static_cast<double>( y ) ) );
132 template<class T> bool isnan( T x )
134 return _isnan( static_cast<double>( x ) ) != 0;
137 template<class T> bool isfinite( T x )
139 return _finite( static_cast<double>( x ) ) != 0;
142 template<class T> bool isinf( T x )
144 return ( _fpclass( static_cast<double>( x ) ) & ( _FPCLASS_PINF | _FPCLASS_NINF ) ) != 0;
147 inline bool isnormal( float x )
149 // no _fpclassf in 32 bit mode
150 unsigned y = reinterpret_cast< unsigned const& >( x );
151 unsigned exp = ( y >> 23 ) & 0xFF;
152 return exp != 0 && exp != 0xFF;
155 inline bool isnormal( double x )
157 return ( _fpclass( x ) & ( _FPCLASS_PN | _FPCLASS_NN ) ) != 0;
160 inline bool isnormal( long double x )
162 return boost::core::isnormal( static_cast<double>( x ) );
165 template<class T> bool signbit( T x )
167 return _copysign( 1.0, static_cast<double>( x ) ) < 0.0;
170 int const fp_zero = 0;
171 int const fp_subnormal = 1;
172 int const fp_normal = 2;
173 int const fp_infinite = 3;
174 int const fp_nan = 4;
176 inline int fpclassify( float x )
178 switch( _fpclass( x ) )
197 return boost::core::isnormal( x )? fp_normal: fp_subnormal;
201 inline int fpclassify( double x )
203 switch( _fpclass( x ) )
231 inline int fpclassify( long double x )
233 return boost::core::fpclassify( static_cast<double>( x ) );
242 using std::fpclassify;
244 int const fp_zero = FP_ZERO;
245 int const fp_subnormal = FP_SUBNORMAL;
246 int const fp_normal = FP_NORMAL;
247 int const fp_infinite = FP_INFINITE;
248 int const fp_nan = FP_NAN;
252 // std::copysign doesn't exist in libstdc++ under -std=c++03
254 #if !defined(__GNUC__)
256 template<class T> T copysign( T x, T y )
258 return std::copysign( x, y );
266 // ::copysignl is unreliable, use the built-ins
268 inline float copysign_impl( float x, float y )
270 return __builtin_copysignf( x, y );
273 inline double copysign_impl( double x, double y )
275 return __builtin_copysign( x, y );
278 inline long double copysign_impl( long double x, long double y )
280 return __builtin_copysignl( x, y );
283 } // namespace detail
285 template<class T> T copysign( T x, T y )
287 return boost::core::detail::copysign_impl( x, y );
290 #endif // !defined(__GNUC__)
291 #endif // #if defined(_MSC_VER) && _MSC_VER < 1800
296 #endif // defined(BOOST_CORE_USE_GENERIC_CMATH)
298 #endif // #ifndef BOOST_CORE_CMATH_HPP_INCLUDED