#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 Peter Dimov // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt #include #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 // #ifndef BOOST_CORE_CMATH_HPP_INCLUDED