1 #ifndef BOOST_CORE_CMATH_HPP_INCLUDED
2 #define BOOST_CORE_CMATH_HPP_INCLUDED
3 
4 // MS compatible compilers support #pragma once
5 
6 #if defined(_MSC_VER) && (_MSC_VER >= 1020)
7 # pragma once
8 #endif
9 
10 // boost/core/cmath.hpp
11 //
12 // Floating point classification and sign manipulation functions
13 // Extracted from https://github.com/boostorg/lexical_cast/pull/37
14 //
15 // Copyright 2020 Peter Dimov
16 // Distributed under the Boost Software License, Version 1.0.
17 // https://www.boost.org/LICENSE_1_0.txt
18 
19 #include <cmath>
20 #if defined(_MSC_VER) && _MSC_VER < 1800
21 # include <float.h>
22 #endif
23 
24 namespace boost
25 {
26 namespace core
27 {
28 #if defined(_MSC_VER) && _MSC_VER < 1800
29 
copysign(T x,T y)30 template<class T> T copysign( T x, T y )
31 {
32     return static_cast<T>( _copysign( static_cast<double>( x ), static_cast<double>( y ) ) );
33 }
34 
isnan(T x)35 template<class T> bool isnan( T x )
36 {
37     return _isnan( static_cast<double>( x ) ) != 0;
38 }
39 
isfinite(T x)40 template<class T> bool isfinite( T x )
41 {
42     return _finite( static_cast<double>( x ) ) != 0;
43 }
44 
isinf(T x)45 template<class T> bool isinf( T x )
46 {
47     return ( _fpclass( static_cast<double>( x ) ) & ( _FPCLASS_PINF | _FPCLASS_NINF ) ) != 0;
48 }
49 
isnormal(float x)50 inline bool isnormal( float x )
51 {
52     // no _fpclassf in 32 bit mode
53     unsigned y = reinterpret_cast< unsigned const& >( x );
54     unsigned exp = ( y >> 23 ) & 0xFF;
55     return exp != 0 && exp != 0xFF;
56 }
57 
isnormal(double x)58 inline bool isnormal( double x )
59 {
60     return ( _fpclass( x ) & ( _FPCLASS_PN | _FPCLASS_NN ) ) != 0;
61 }
62 
isnormal(long double x)63 inline bool isnormal( long double x )
64 {
65     return boost::core::isnormal( static_cast<double>( x ) );
66 }
67 
signbit(T x)68 template<class T> bool signbit( T x )
69 {
70     return _copysign( 1.0, static_cast<double>( x ) ) < 0.0;
71 }
72 
73 int const fp_zero = 0;
74 int const fp_subnormal = 1;
75 int const fp_normal = 2;
76 int const fp_infinite = 3;
77 int const fp_nan = 4;
78 
fpclassify(float x)79 inline int fpclassify( float x )
80 {
81     switch( _fpclass( x ) )
82     {
83     case _FPCLASS_SNAN:
84     case _FPCLASS_QNAN:
85 
86         return fp_nan;
87 
88     case _FPCLASS_NINF:
89     case _FPCLASS_PINF:
90 
91         return fp_infinite;
92 
93     case _FPCLASS_NZ:
94     case _FPCLASS_PZ:
95 
96         return fp_zero;
97 
98     default:
99 
100         return boost::core::isnormal( x )? fp_normal: fp_subnormal;
101     }
102 }
103 
fpclassify(double x)104 inline int fpclassify( double x )
105 {
106     switch( _fpclass( x ) )
107     {
108     case _FPCLASS_SNAN:
109     case _FPCLASS_QNAN:
110 
111         return fp_nan;
112 
113     case _FPCLASS_NINF:
114     case _FPCLASS_PINF:
115 
116         return fp_infinite;
117 
118     case _FPCLASS_NZ:
119     case _FPCLASS_PZ:
120 
121         return fp_zero;
122 
123     case _FPCLASS_ND:
124     case _FPCLASS_PD:
125 
126         return fp_subnormal;
127 
128     default:
129 
130         return fp_normal;
131     }
132 }
133 
fpclassify(long double x)134 inline int fpclassify( long double x )
135 {
136     return boost::core::fpclassify( static_cast<double>( x ) );
137 }
138 
139 #else
140 
141 using std::isfinite;
142 using std::isnan;
143 using std::isinf;
144 using std::isnormal;
145 using std::fpclassify;
146 
147 int const fp_zero = FP_ZERO;
148 int const fp_subnormal = FP_SUBNORMAL;
149 int const fp_normal = FP_NORMAL;
150 int const fp_infinite = FP_INFINITE;
151 int const fp_nan = FP_NAN;
152 
153 using std::signbit;
154 
155 // std::copysign doesn't exist in libstdc++ under -std=c++03
156 
157 #if !defined(__GNUC__)
158 
159 template<class T> T copysign( T x, T y )
160 {
161     return std::copysign( x, y );
162 }
163 
164 #else
165 
166 namespace detail
167 {
168 
169 // ::copysignl is unreliable, use the built-ins
170 
171 inline float copysign_impl( float x, float y )
172 {
173     return __builtin_copysignf( x, y );
174 }
175 
176 inline double copysign_impl( double x, double y )
177 {
178     return __builtin_copysign( x, y );
179 }
180 
181 inline long double copysign_impl( long double x, long double y )
182 {
183     return __builtin_copysignl( x, y );
184 }
185 
186 } // namespace detail
187 
188 template<class T> T copysign( T x, T y )
189 {
190     return boost::core::detail::copysign_impl( x, y );
191 }
192 
193 #endif // !defined(__GNUC__)
194 #endif // #if defined(_MSC_VER) && _MSC_VER < 1800
195 
196 } // namespace core
197 } // namespace boost
198 
199 #endif  // #ifndef BOOST_CORE_CMATH_HPP_INCLUDED
200