Add core/cmath.hpp

This commit is contained in:
Peter Dimov 2020-12-24 00:19:20 +02:00
parent 0364b64927
commit c307f86520
3 changed files with 394 additions and 0 deletions

View File

@ -0,0 +1,126 @@
#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 <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;
}
#else
using std::isfinite;
using std::isnan;
using std::isinf;
using std::isnormal;
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 // #ifndef BOOST_CORE_CMATH_HPP_INCLUDED

View File

@ -220,5 +220,7 @@ run uncaught_exceptions_np.cpp
run no_exceptions_support_test.cpp ;
run no_exceptions_support_test.cpp : : : <exception-handling>off : no_exceptions_support_test_nx ;
run cmath_test.cpp ;
use-project /boost/core/swap : ./swap ;
build-project ./swap ;

266
test/cmath_test.cpp Normal file
View File

@ -0,0 +1,266 @@
// Test for boost/core/cmath.hpp
//
// Copyright 2020 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/core/cmath.hpp>
#include <boost/core/lightweight_test.hpp>
#include <limits>
#include <cfloat>
template<class T> void test_positive_normal( T x )
{
BOOST_TEST( boost::core::isfinite( x ) );
BOOST_TEST( !boost::core::isinf( x ) );
BOOST_TEST( !boost::core::isnan( x ) );
BOOST_TEST( boost::core::isnormal( x ) );
BOOST_TEST( !boost::core::signbit( x ) );
BOOST_TEST_EQ( boost::core::copysign( T(+2), x ), T(+2) );
BOOST_TEST_EQ( boost::core::copysign( T(-2), x ), T(+2) );
}
template<class T> void test_negative_normal( T x )
{
BOOST_TEST( boost::core::isfinite( x ) );
BOOST_TEST( !boost::core::isinf( x ) );
BOOST_TEST( !boost::core::isnan( x ) );
BOOST_TEST( boost::core::isnormal( x ) );
BOOST_TEST( boost::core::signbit( x ) );
BOOST_TEST_EQ( boost::core::copysign( T(+2), x ), T(-2) );
BOOST_TEST_EQ( boost::core::copysign( T(-2), x ), T(-2) );
}
template<class T> void test_positive_zero( T x )
{
BOOST_TEST( boost::core::isfinite( x ) );
BOOST_TEST( !boost::core::isinf( x ) );
BOOST_TEST( !boost::core::isnan( x ) );
BOOST_TEST( !boost::core::isnormal( x ) );
BOOST_TEST( !boost::core::signbit( x ) );
BOOST_TEST_EQ( boost::core::copysign( T(+2), x ), T(+2) );
BOOST_TEST_EQ( boost::core::copysign( T(-2), x ), T(+2) );
}
template<class T> void test_negative_zero( T x )
{
BOOST_TEST( boost::core::isfinite( x ) );
BOOST_TEST( !boost::core::isinf( x ) );
BOOST_TEST( !boost::core::isnan( x ) );
BOOST_TEST( !boost::core::isnormal( x ) );
BOOST_TEST( boost::core::signbit( x ) );
BOOST_TEST_EQ( boost::core::copysign( T(+2), x ), T(-2) );
BOOST_TEST_EQ( boost::core::copysign( T(-2), x ), T(-2) );
}
template<class T> void test_positive_infinity( T x )
{
BOOST_TEST( !boost::core::isfinite( x ) );
BOOST_TEST( boost::core::isinf( x ) );
BOOST_TEST( !boost::core::isnan( x ) );
BOOST_TEST( !boost::core::isnormal( x ) );
BOOST_TEST( !boost::core::signbit( x ) );
BOOST_TEST_EQ( boost::core::copysign( T(+2), x ), T(+2) );
BOOST_TEST_EQ( boost::core::copysign( T(-2), x ), T(+2) );
}
template<class T> void test_negative_infinity( T x )
{
BOOST_TEST( !boost::core::isfinite( x ) );
BOOST_TEST( boost::core::isinf( x ) );
BOOST_TEST( !boost::core::isnan( x ) );
BOOST_TEST( !boost::core::isnormal( x ) );
BOOST_TEST( boost::core::signbit( x ) );
BOOST_TEST_EQ( boost::core::copysign( T(+2), x ), T(-2) );
BOOST_TEST_EQ( boost::core::copysign( T(-2), x ), T(-2) );
}
template<class T> void test_positive_nan( T x )
{
BOOST_TEST( !boost::core::isfinite( x ) );
BOOST_TEST( !boost::core::isinf( x ) );
BOOST_TEST( boost::core::isnan( x ) );
BOOST_TEST( !boost::core::isnormal( x ) );
BOOST_TEST( !boost::core::signbit( x ) );
BOOST_TEST_EQ( boost::core::copysign( T(+2), x ), T(+2) );
BOOST_TEST_EQ( boost::core::copysign( T(-2), x ), T(+2) );
}
template<class T> void test_negative_nan( T x )
{
BOOST_TEST( !boost::core::isfinite( x ) );
BOOST_TEST( !boost::core::isinf( x ) );
BOOST_TEST( boost::core::isnan( x ) );
BOOST_TEST( !boost::core::isnormal( x ) );
BOOST_TEST( boost::core::signbit( x ) );
BOOST_TEST_EQ( boost::core::copysign( T(+2), x ), T(-2) );
BOOST_TEST_EQ( boost::core::copysign( T(-2), x ), T(-2) );
}
template<class T> void test_positive_subnormal( T x )
{
BOOST_TEST( boost::core::isfinite( x ) );
BOOST_TEST( !boost::core::isinf( x ) );
BOOST_TEST( !boost::core::isnan( x ) );
BOOST_TEST( !boost::core::isnormal( x ) );
BOOST_TEST( !boost::core::signbit( x ) );
BOOST_TEST_EQ( boost::core::copysign( T(+2), x ), T(+2) );
BOOST_TEST_EQ( boost::core::copysign( T(-2), x ), T(+2) );
}
template<class T> void test_negative_subnormal( T x )
{
BOOST_TEST( boost::core::isfinite( x ) );
BOOST_TEST( !boost::core::isinf( x ) );
BOOST_TEST( !boost::core::isnan( x ) );
BOOST_TEST( !boost::core::isnormal( x ) );
BOOST_TEST( boost::core::signbit( x ) );
BOOST_TEST_EQ( boost::core::copysign( T(+2), x ), T(-2) );
BOOST_TEST_EQ( boost::core::copysign( T(-2), x ), T(-2) );
}
template<class T> void test_positive_normal_( T x )
{
test_positive_normal( x );
test_positive_normal( boost::core::copysign( x, T(+1) ) );
test_negative_normal( boost::core::copysign( x, T(-1) ) );
}
template<class T> void test_negative_normal_( T x )
{
test_negative_normal( x );
test_positive_normal( boost::core::copysign( x, T(+1) ) );
test_negative_normal( boost::core::copysign( x, T(-1) ) );
}
template<class T> void test_positive_zero_( T x )
{
test_positive_zero( x );
test_positive_zero( boost::core::copysign( x, T(+1) ) );
test_negative_zero( boost::core::copysign( x, T(-1) ) );
}
template<class T> void test_negative_zero_( T x )
{
test_negative_zero( x );
test_positive_zero( boost::core::copysign( x, T(+1) ) );
test_negative_zero( boost::core::copysign( x, T(-1) ) );
}
template<class T> void test_positive_infinity_( T x )
{
test_positive_infinity( x );
test_positive_infinity( boost::core::copysign( x, T(+1) ) );
test_negative_infinity( boost::core::copysign( x, T(-1) ) );
}
template<class T> void test_negative_infinity_( T x )
{
test_negative_infinity( x );
test_positive_infinity( boost::core::copysign( x, T(+1) ) );
test_negative_infinity( boost::core::copysign( x, T(-1) ) );
}
template<class T> void test_positive_nan_( T x )
{
test_positive_nan( x );
test_positive_nan( boost::core::copysign( x, T(+1) ) );
test_negative_nan( boost::core::copysign( x, T(-1) ) );
}
template<class T> void test_negative_nan_( T x )
{
test_negative_nan( x );
test_positive_nan( boost::core::copysign( x, T(+1) ) );
test_negative_nan( boost::core::copysign( x, T(-1) ) );
}
template<class T> void test_positive_subnormal_( T x )
{
test_positive_subnormal( x );
test_positive_subnormal( boost::core::copysign( x, T(+1) ) );
test_negative_subnormal( boost::core::copysign( x, T(-1) ) );
}
template<class T> void test_negative_subnormal_( T x )
{
test_negative_subnormal( x );
test_positive_subnormal( boost::core::copysign( x, T(+1) ) );
test_negative_subnormal( boost::core::copysign( x, T(-1) ) );
}
int main()
{
// float
test_positive_normal_( +1.0f );
test_negative_normal_( -1.0f );
test_positive_normal_( FLT_MIN );
test_negative_normal_( -FLT_MIN );
test_positive_normal_( FLT_MAX );
test_negative_normal_( -FLT_MAX );
test_positive_zero_( +0.0f );
test_negative_zero_( -0.0f );
test_positive_infinity_( std::numeric_limits<float>::infinity() );
test_negative_infinity_( -std::numeric_limits<float>::infinity() );
test_positive_nan_( std::numeric_limits<float>::quiet_NaN() );
test_negative_nan_( boost::core::copysign( std::numeric_limits<float>::quiet_NaN(), -1.0f ) );
test_positive_subnormal_( FLT_MIN / 2 );
test_negative_subnormal_( -FLT_MIN / 2 );
// double
test_positive_normal_( +1.0 );
test_negative_normal_( -1.0 );
test_positive_normal_( DBL_MIN );
test_negative_normal_( -DBL_MIN );
test_positive_normal_( DBL_MAX );
test_negative_normal_( -DBL_MAX );
test_positive_zero_( +0.0 );
test_negative_zero_( -0.0 );
test_positive_infinity_( std::numeric_limits<double>::infinity() );
test_negative_infinity_( -std::numeric_limits<double>::infinity() );
test_positive_nan_( std::numeric_limits<double>::quiet_NaN() );
test_negative_nan_( boost::core::copysign( std::numeric_limits<double>::quiet_NaN(), -1.0 ) );
test_positive_subnormal_( DBL_MIN / 2 );
test_negative_subnormal_( -DBL_MIN / 2 );
// long double
test_positive_normal_( +1.0l );
test_negative_normal_( -1.0l );
test_positive_normal_( LDBL_MIN );
test_negative_normal_( -LDBL_MIN );
test_positive_normal_( LDBL_MAX );
test_negative_normal_( -LDBL_MAX );
test_positive_zero_( +0.0l );
test_negative_zero_( -0.0l );
test_positive_infinity_( std::numeric_limits<long double>::infinity() );
test_negative_infinity_( -std::numeric_limits<long double>::infinity() );
test_positive_nan_( std::numeric_limits<long double>::quiet_NaN() );
test_negative_nan_( boost::core::copysign( std::numeric_limits<long double>::quiet_NaN(), -1.0l ) );
test_positive_subnormal_( LDBL_MIN / 2 );
test_negative_subnormal_( -LDBL_MIN / 2 );
return boost::report_errors();
}