1 // fpclassify.hpp
2 
3 #ifndef BOOST_SPIRIT_MATH_FPCLASSIFY_HPP
4 #define BOOST_SPIRIT_MATH_FPCLASSIFY_HPP
5 
6 // Copyright (c) 2006 Johan Rade
7 
8 // Distributed under the Boost Software License, Version 1.0.
9 // (See accompanying file LICENSE_1_0.txt
10 // or copy at http://www.boost.org/LICENSE_1_0.txt)
11 
12 /*
13 The following algorithm is used:
14 
15   If all exponent bits, the flag bit (if there is one),
16   and all mantissa bits are 0, then the number is zero.
17 
18   If all exponent bits and the flag bit (if there is one) are 0,
19   and at least one mantissa bit is 1, then the number is subnormal.
20 
21   If all exponent bits are 1 and all mantissa bits are 0,
22   then the number is infinity.
23 
24   If all exponent bits are 1 and at least one mantissa bit is 1,
25   then the number is a not-a-number.
26 
27   Otherwise the number is normal.
28 
29 (Note that the binary representation of infinity
30 has flag bit 0 for Motorola 68K extended double precision,
31 and flag bit 1 for Intel extended double precision.)
32 
33 To get the bits, the four or eight most significant bytes are copied
34 into an uint32_t or uint64_t and bit masks are applied.
35 This covers all the exponent bits and the flag bit (if there is one),
36 but not always all the mantissa bits.
37 Some of the functions below have two implementations,
38 depending on whether all the mantissa bits are copied or not.
39 */
40 
41 #if defined(_MSC_VER)
42 #pragma once
43 #endif
44 
45 #include <cmath>
46 
47 #ifndef FP_INFINITE
48 #   define FP_INFINITE 0
49 #   define FP_NAN 1
50 #   define FP_NORMAL 2
51 #   define FP_SUBNORMAL 3
52 #   define FP_ZERO 4
53 #endif
54 
55 #include <boost/spirit/home/support/detail/math/detail/fp_traits.hpp>
56 
57 namespace boost {
58 namespace spirit {
59 namespace math {
60 
61 //------------------------------------------------------------------------------
62 
63 template<class T> bool (isfinite)(T x)
64 {
65     typedef BOOST_DEDUCED_TYPENAME detail::fp_traits<T>::type traits;
66     traits::init();
67 
68     BOOST_DEDUCED_TYPENAME traits::bits a;
69     traits::get_bits(x,a);
70     a &= traits::exponent;
71     return a != traits::exponent;
72 }
73 
74 //------------------------------------------------------------------------------
75 
76 template<class T> bool (isnormal)(T x)
77 {
78     typedef BOOST_DEDUCED_TYPENAME detail::fp_traits<T>::type traits;
79     traits::init();
80 
81     BOOST_DEDUCED_TYPENAME traits::bits a;
82     traits::get_bits(x,a);
83     a &= traits::exponent | traits::flag;
84     return (a != 0) && (a < traits::exponent);
85 }
86 
87 //------------------------------------------------------------------------------
88 
89 namespace detail {
90 
isinf_impl(T x,all_bits)91     template<class T> bool isinf_impl(T x, all_bits)
92     {
93         typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
94 
95         BOOST_DEDUCED_TYPENAME traits::bits a;
96         traits::get_bits(x,a);
97         a &= traits::exponent | traits::mantissa;
98         return a == traits::exponent;
99     }
100 
isinf_impl(T x,not_all_bits)101     template<class T> bool isinf_impl(T x, not_all_bits)
102     {
103         typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
104 
105         BOOST_DEDUCED_TYPENAME traits::bits a;
106         traits::get_bits(x,a);
107         a &= traits::exponent | traits::mantissa;
108         if(a != traits::exponent)
109             return false;
110 
111         traits::set_bits(x,0);
112         return x == 0;
113     }
114 
115 }   // namespace detail
116 
117 template<class T> bool (isinf)(T x)
118 {
119     typedef BOOST_DEDUCED_TYPENAME detail::fp_traits<T>::type traits;
120     traits::init();
121     return detail::isinf_impl(x, BOOST_DEDUCED_TYPENAME traits::coverage());
122 }
123 
124 //------------------------------------------------------------------------------
125 
126 namespace detail {
127 
isnan_impl(T x,all_bits)128     template<class T> bool isnan_impl(T x, all_bits)
129     {
130         typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
131         traits::init();
132 
133         BOOST_DEDUCED_TYPENAME traits::bits a;
134         traits::get_bits(x,a);
135         a &= traits::exponent | traits::mantissa;
136         return a > traits::exponent;
137     }
138 
isnan_impl(T x,not_all_bits)139     template<class T> bool isnan_impl(T x, not_all_bits)
140     {
141         typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
142         traits::init();
143 
144         BOOST_DEDUCED_TYPENAME traits::bits a;
145         traits::get_bits(x,a);
146 
147         a &= traits::exponent | traits::mantissa;
148         if(a < traits::exponent)
149             return false;
150 
151         a &= traits::mantissa;
152         traits::set_bits(x,a);
153         return x != 0;
154     }
155 
156 }   // namespace detail
157 
158 template<class T> bool (isnan)(T x)
159 {
160     typedef BOOST_DEDUCED_TYPENAME detail::fp_traits<T>::type traits;
161     traits::init();
162     return detail::isnan_impl(x, BOOST_DEDUCED_TYPENAME traits::coverage());
163 }
164 
165 //------------------------------------------------------------------------------
166 
167 namespace detail {
168 
fpclassify_impl(T x,all_bits)169     template<class T> int fpclassify_impl(T x, all_bits)
170     {
171         typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
172 
173         BOOST_DEDUCED_TYPENAME traits::bits a;
174         traits::get_bits(x,a);
175         a &= traits::exponent | traits::flag | traits::mantissa;
176 
177         if(a <= traits::mantissa) {
178             if(a == 0)
179                 return FP_ZERO;
180             else
181                 return FP_SUBNORMAL;
182         }
183 
184         if(a < traits::exponent)
185             return FP_NORMAL;
186 
187         a &= traits::mantissa;
188         if(a == 0)
189             return FP_INFINITE;
190 
191         return FP_NAN;
192     }
193 
fpclassify_impl(T x,not_all_bits)194     template<class T> int fpclassify_impl(T x, not_all_bits)
195     {
196         typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
197 
198         BOOST_DEDUCED_TYPENAME traits::bits a;
199         traits::get_bits(x,a);
200         a &= traits::exponent | traits::flag | traits::mantissa;
201 
202         if(a <= traits::mantissa) {
203             if(x == 0)
204                 return FP_ZERO;
205             else
206                 return FP_SUBNORMAL;
207         }
208 
209         if(a < traits::exponent)
210             return FP_NORMAL;
211 
212         a &= traits::mantissa;
213         traits::set_bits(x,a);
214         if(x == 0)
215             return FP_INFINITE;
216 
217         return FP_NAN;
218     }
219 
220 }   // namespace detail
221 
222 template<class T> int (fpclassify)(T x)
223 {
224     typedef BOOST_DEDUCED_TYPENAME detail::fp_traits<T>::type traits;
225     traits::init();
226     return detail::fpclassify_impl(x, BOOST_DEDUCED_TYPENAME traits::coverage());
227 }
228 
229 //------------------------------------------------------------------------------
230 
231 }   // namespace math
232 }   // namespace spirit
233 }   // namespace boost
234 
235 #endif
236