#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 #if defined(BOOST_CORE_USE_GENERIC_CMATH) || (!defined(_MSC_VER) && !defined(FP_SUBNORMAL)) #include #include #include #include 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 bool isfinite( T x ) { return x <= (std::numeric_limits::max)() && x >= -(std::numeric_limits::max)(); } template bool isinf( T x ) { return x > (std::numeric_limits::max)() || x < -(std::numeric_limits::max)(); } template bool isnan( T x ) { return !isfinite( x ) && !isinf( x ); } template bool isnormal( T x ) { return isfinite( x ) && ( x >= (std::numeric_limits::min)() || x <= -(std::numeric_limits::min)() ); } template int fpclassify( T x ) { if( x == 0 ) return fp_zero; if( x < 0 ) x = -x; if( x > (std::numeric_limits::max)() ) return fp_infinite; if( x >= (std::numeric_limits::min)() ) return fp_normal; if( x < (std::numeric_limits::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( x ) ); } template 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 #endif namespace boost { namespace core { #if defined(_MSC_VER) && _MSC_VER < 1800 template T copysign( T x, T y ) { return static_cast( _copysign( static_cast( x ), static_cast( y ) ) ); } template bool isnan( T x ) { return _isnan( static_cast( x ) ) != 0; } template bool isfinite( T x ) { return _finite( static_cast( x ) ) != 0; } template bool isinf( T x ) { return ( _fpclass( static_cast( 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( x ) ); } template bool signbit( T x ) { return _copysign( 1.0, static_cast( 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( 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 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 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