123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298 |
- #ifndef BOOST_CORE_CMATH_HPP_INCLUDED
- #define BOOST_CORE_CMATH_HPP_INCLUDED
- // MS compatible compilers support #pragma once
- #if defined(_MSC_VER) && (_MSC_VER >= 1020)
- # pragma once
- #endif
- // boost/core/cmath.hpp
- //
- // Floating point classification and sign manipulation functions
- // Extracted from https://github.com/boostorg/lexical_cast/pull/37
- //
- // Copyright 2020, 2021 Peter Dimov
- // Distributed under the Boost Software License, Version 1.0.
- // https://www.boost.org/LICENSE_1_0.txt
- #include <cmath>
- #if defined(BOOST_CORE_USE_GENERIC_CMATH) || (!defined(_MSC_VER) && !defined(FP_SUBNORMAL))
- #include <boost/cstdint.hpp>
- #include <boost/static_assert.hpp>
- #include <limits>
- #include <cstring>
- namespace boost
- {
- namespace core
- {
- // fpclassify return values
- int const fp_zero = 0;
- int const fp_subnormal = 1;
- int const fp_normal = 2;
- int const fp_infinite = 3;
- int const fp_nan = 4;
- // Classification functions
- template<class T> bool isfinite( T x )
- {
- return x <= (std::numeric_limits<T>::max)() && x >= -(std::numeric_limits<T>::max)();
- }
- template<class T> bool isinf( T x )
- {
- return x > (std::numeric_limits<T>::max)() || x < -(std::numeric_limits<T>::max)();
- }
- template<class T> bool isnan( T x )
- {
- return !isfinite( x ) && !isinf( x );
- }
- template<class T> bool isnormal( T x )
- {
- return isfinite( x ) && ( x >= (std::numeric_limits<T>::min)() || x <= -(std::numeric_limits<T>::min)() );
- }
- template<class T> int fpclassify( T x )
- {
- if( x == 0 ) return fp_zero;
- if( x < 0 ) x = -x;
- if( x > (std::numeric_limits<T>::max)() ) return fp_infinite;
- if( x >= (std::numeric_limits<T>::min)() ) return fp_normal;
- if( x < (std::numeric_limits<T>::min)() ) return fp_subnormal;
- return fp_nan;
- }
- // Sign manipulation functions
- inline bool signbit( float x )
- {
- boost::int32_t y;
- BOOST_STATIC_ASSERT( sizeof( x ) == sizeof( y ) );
- std::memcpy( &y, &x, sizeof( y ) );
- return y < 0;
- }
- inline bool signbit( double x )
- {
- boost::int64_t y;
- BOOST_STATIC_ASSERT( sizeof( x ) == sizeof( y ) );
- std::memcpy( &y, &x, sizeof( y ) );
- return y < 0;
- }
- inline bool signbit( long double x )
- {
- return signbit( static_cast<double>( x ) );
- }
- template<class T> T copysign( T x, T y )
- {
- return signbit( x ) == signbit( y )? x: -x;
- }
- } // namespace core
- } // namespace boost
- #else // defined(BOOST_CORE_USE_GENERIC_CMATH)
- #if defined(_MSC_VER) && _MSC_VER < 1800
- # include <float.h>
- #endif
- namespace boost
- {
- namespace core
- {
- #if defined(_MSC_VER) && _MSC_VER < 1800
- template<class T> T copysign( T x, T y )
- {
- return static_cast<T>( _copysign( static_cast<double>( x ), static_cast<double>( y ) ) );
- }
- template<class T> bool isnan( T x )
- {
- return _isnan( static_cast<double>( x ) ) != 0;
- }
- template<class T> bool isfinite( T x )
- {
- return _finite( static_cast<double>( x ) ) != 0;
- }
- template<class T> bool isinf( T x )
- {
- return ( _fpclass( static_cast<double>( x ) ) & ( _FPCLASS_PINF | _FPCLASS_NINF ) ) != 0;
- }
- inline bool isnormal( float x )
- {
- // no _fpclassf in 32 bit mode
- unsigned y = reinterpret_cast< unsigned const& >( x );
- unsigned exp = ( y >> 23 ) & 0xFF;
- return exp != 0 && exp != 0xFF;
- }
- inline bool isnormal( double x )
- {
- return ( _fpclass( x ) & ( _FPCLASS_PN | _FPCLASS_NN ) ) != 0;
- }
- inline bool isnormal( long double x )
- {
- return boost::core::isnormal( static_cast<double>( x ) );
- }
- template<class T> bool signbit( T x )
- {
- return _copysign( 1.0, static_cast<double>( x ) ) < 0.0;
- }
- int const fp_zero = 0;
- int const fp_subnormal = 1;
- int const fp_normal = 2;
- int const fp_infinite = 3;
- int const fp_nan = 4;
- inline int fpclassify( float x )
- {
- switch( _fpclass( x ) )
- {
- case _FPCLASS_SNAN:
- case _FPCLASS_QNAN:
- return fp_nan;
- case _FPCLASS_NINF:
- case _FPCLASS_PINF:
- return fp_infinite;
- case _FPCLASS_NZ:
- case _FPCLASS_PZ:
- return fp_zero;
- default:
- return boost::core::isnormal( x )? fp_normal: fp_subnormal;
- }
- }
- inline int fpclassify( double x )
- {
- switch( _fpclass( x ) )
- {
- case _FPCLASS_SNAN:
- case _FPCLASS_QNAN:
- return fp_nan;
- case _FPCLASS_NINF:
- case _FPCLASS_PINF:
- return fp_infinite;
- case _FPCLASS_NZ:
- case _FPCLASS_PZ:
- return fp_zero;
- case _FPCLASS_ND:
- case _FPCLASS_PD:
- return fp_subnormal;
- default:
- return fp_normal;
- }
- }
- inline int fpclassify( long double x )
- {
- return boost::core::fpclassify( static_cast<double>( x ) );
- }
- #else
- using std::isfinite;
- using std::isnan;
- using std::isinf;
- using std::isnormal;
- using std::fpclassify;
- int const fp_zero = FP_ZERO;
- int const fp_subnormal = FP_SUBNORMAL;
- int const fp_normal = FP_NORMAL;
- int const fp_infinite = FP_INFINITE;
- int const fp_nan = FP_NAN;
- using std::signbit;
- // std::copysign doesn't exist in libstdc++ under -std=c++03
- #if !defined(__GNUC__)
- template<class T> T copysign( T x, T y )
- {
- return std::copysign( x, y );
- }
- #else
- namespace detail
- {
- // ::copysignl is unreliable, use the built-ins
- inline float copysign_impl( float x, float y )
- {
- return __builtin_copysignf( x, y );
- }
- inline double copysign_impl( double x, double y )
- {
- return __builtin_copysign( x, y );
- }
- inline long double copysign_impl( long double x, long double y )
- {
- return __builtin_copysignl( x, y );
- }
- } // namespace detail
- template<class T> T copysign( T x, T y )
- {
- return boost::core::detail::copysign_impl( x, y );
- }
- #endif // !defined(__GNUC__)
- #endif // #if defined(_MSC_VER) && _MSC_VER < 1800
- } // namespace core
- } // namespace boost
- #endif // defined(BOOST_CORE_USE_GENERIC_CMATH)
- #endif // #ifndef BOOST_CORE_CMATH_HPP_INCLUDED
|