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