forked from boostorg/core
		
	
		
			
				
	
	
		
			299 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			299 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
#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
 |