]> git.donarmstrong.com Git - rsem.git/blob - boost/math/special_functions/fpclassify.hpp
d3dc42b0caf6ba98fe4d6e51d6f09288b5745ecb
[rsem.git] / boost / math / special_functions / fpclassify.hpp
1 //  Copyright John Maddock 2005-2008.
2 //  Copyright (c) 2006-2008 Johan Rade
3 //  Use, modification and distribution are subject to the
4 //  Boost Software License, Version 1.0. (See accompanying file
5 //  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6
7 #ifndef BOOST_MATH_FPCLASSIFY_HPP
8 #define BOOST_MATH_FPCLASSIFY_HPP
9
10 #ifdef _MSC_VER
11 #pragma once
12 #endif
13
14 #include <math.h>
15 #include <boost/config/no_tr1/cmath.hpp>
16 #include <boost/limits.hpp>
17 #include <boost/math/tools/real_cast.hpp>
18 #include <boost/type_traits/is_floating_point.hpp>
19 #include <boost/math/special_functions/math_fwd.hpp>
20 #include <boost/math/special_functions/detail/fp_traits.hpp>
21 /*!
22   \file fpclassify.hpp
23   \brief Classify floating-point value as normal, subnormal, zero, infinite, or NaN.
24   \version 1.0
25   \author John Maddock
26  */
27
28 /*
29
30 1. If the platform is C99 compliant, then the native floating point
31 classification functions are used.  However, note that we must only
32 define the functions which call std::fpclassify etc if that function
33 really does exist: otherwise a compiler may reject the code even though
34 the template is never instantiated.
35
36 2. If the platform is not C99 compliant, and the binary format for
37 a floating point type (float, double or long double) can be determined
38 at compile time, then the following algorithm is used:
39
40         If all exponent bits, the flag bit (if there is one), 
41         and all significand bits are 0, then the number is zero.
42
43         If all exponent bits and the flag bit (if there is one) are 0, 
44         and at least one significand bit is 1, then the number is subnormal.
45
46         If all exponent bits are 1 and all significand bits are 0, 
47         then the number is infinity.
48
49         If all exponent bits are 1 and at least one significand bit is 1,
50         then the number is a not-a-number.
51
52         Otherwise the number is normal.
53
54         This algorithm works for the IEEE 754 representation,
55         and also for several non IEEE 754 formats.
56
57     Most formats have the structure
58         sign bit + exponent bits + significand bits.
59     
60     A few have the structure
61         sign bit + exponent bits + flag bit + significand bits.
62     The flag bit is 0 for zero and subnormal numbers,
63         and 1 for normal numbers and NaN.
64         It is 0 (Motorola 68K) or 1 (Intel) for infinity.
65
66     To get the bits, the four or eight most significant bytes are copied
67     into an uint32_t or uint64_t and bit masks are applied.
68     This covers all the exponent bits and the flag bit (if there is one),
69     but not always all the significand bits.
70     Some of the functions below have two implementations,
71     depending on whether all the significand bits are copied or not.
72
73 3. If the platform is not C99 compliant, and the binary format for
74 a floating point type (float, double or long double) can not be determined
75 at compile time, then comparison with std::numeric_limits values
76 is used.
77
78 */
79
80 #if defined(_MSC_VER) || defined(__BORLANDC__)
81 #include <float.h>
82 #endif
83
84 #ifdef BOOST_NO_STDC_NAMESPACE
85   namespace std{ using ::abs; using ::fabs; }
86 #endif
87
88 namespace boost{ 
89
90 #if defined(BOOST_HAS_FPCLASSIFY) || defined(isnan)
91 //
92 // This must not be located in any namespace under boost::math
93 // otherwise we can get into an infinite loop if isnan is
94 // a #define for "isnan" !
95 //
96 namespace math_detail{
97
98 template <class T>
99 inline bool is_nan_helper(T t, const boost::true_type&)
100 {
101 #ifdef isnan
102    return isnan(t);
103 #else // BOOST_HAS_FPCLASSIFY
104    return (BOOST_FPCLASSIFY_PREFIX fpclassify(t) == (int)FP_NAN);
105 #endif
106 }
107
108 template <class T>
109 inline bool is_nan_helper(T, const boost::false_type&)
110 {
111    return false;
112 }
113
114 }
115
116 #endif // defined(BOOST_HAS_FPCLASSIFY) || defined(isnan)
117
118 namespace math{
119
120 namespace detail{
121
122 #ifdef BOOST_MATH_USE_STD_FPCLASSIFY
123 template <class T>
124 inline int fpclassify_imp BOOST_NO_MACRO_EXPAND(T t, const native_tag&)
125 {
126    return (std::fpclassify)(t);
127 }
128 #endif
129
130 template <class T>
131 inline int fpclassify_imp BOOST_NO_MACRO_EXPAND(T t, const generic_tag<true>&)
132 {
133    BOOST_MATH_INSTRUMENT_VARIABLE(t);
134
135    // whenever possible check for Nan's first:
136 #ifdef BOOST_HAS_FPCLASSIFY
137    if(::boost::math_detail::is_nan_helper(t, ::boost::is_floating_point<T>()))
138       return FP_NAN;
139 #elif defined(isnan)
140    if(boost::math_detail::is_nan_helper(t, ::boost::is_floating_point<T>()))
141       return FP_NAN;
142 #elif defined(_MSC_VER) || defined(__BORLANDC__)
143    if(::_isnan(boost::math::tools::real_cast<double>(t)))
144       return FP_NAN;
145 #endif
146    // std::fabs broken on a few systems especially for long long!!!!
147    T at = (t < T(0)) ? -t : t;
148
149    // Use a process of exclusion to figure out
150    // what kind of type we have, this relies on
151    // IEEE conforming reals that will treat
152    // Nan's as unordered.  Some compilers
153    // don't do this once optimisations are
154    // turned on, hence the check for nan's above.
155    if(at <= (std::numeric_limits<T>::max)())
156    {
157       if(at >= (std::numeric_limits<T>::min)())
158          return FP_NORMAL;
159       return (at != 0) ? FP_SUBNORMAL : FP_ZERO;
160    }
161    else if(at > (std::numeric_limits<T>::max)())
162       return FP_INFINITE;
163    return FP_NAN;
164 }
165
166 template <class T>
167 inline int fpclassify_imp BOOST_NO_MACRO_EXPAND(T t, const generic_tag<false>&)
168 {
169 #ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
170    if(std::numeric_limits<T>::is_specialized)
171       return fp_classify_imp(t, mpl::true_());
172 #endif
173    // 
174    // An unknown type with no numeric_limits support,
175    // so what are we supposed to do we do here?
176    //
177    BOOST_MATH_INSTRUMENT_VARIABLE(t);
178
179    return t == 0 ? FP_ZERO : FP_NORMAL;
180 }
181
182 template<class T> 
183 int fpclassify_imp BOOST_NO_MACRO_EXPAND(T x, ieee_copy_all_bits_tag)
184 {
185    typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
186
187    BOOST_MATH_INSTRUMENT_VARIABLE(x);
188
189    BOOST_DEDUCED_TYPENAME traits::bits a;
190    traits::get_bits(x,a);
191    BOOST_MATH_INSTRUMENT_VARIABLE(a);
192    a &= traits::exponent | traits::flag | traits::significand;
193    BOOST_MATH_INSTRUMENT_VARIABLE((traits::exponent | traits::flag | traits::significand));
194    BOOST_MATH_INSTRUMENT_VARIABLE(a);
195
196    if(a <= traits::significand) {
197       if(a == 0)
198          return FP_ZERO;
199       else
200          return FP_SUBNORMAL;
201    }
202
203    if(a < traits::exponent) return FP_NORMAL;
204
205    a &= traits::significand;
206    if(a == 0) return FP_INFINITE;
207
208    return FP_NAN;
209 }
210
211 template<class T> 
212 int fpclassify_imp BOOST_NO_MACRO_EXPAND(T x, ieee_copy_leading_bits_tag)
213 {
214    typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
215
216    BOOST_MATH_INSTRUMENT_VARIABLE(x);
217
218    BOOST_DEDUCED_TYPENAME traits::bits a;
219    traits::get_bits(x,a); 
220    a &= traits::exponent | traits::flag | traits::significand;
221
222    if(a <= traits::significand) {
223       if(x == 0)
224          return FP_ZERO;
225       else
226          return FP_SUBNORMAL;
227    }
228
229    if(a < traits::exponent) return FP_NORMAL;
230
231    a &= traits::significand;
232    traits::set_bits(x,a);
233    if(x == 0) return FP_INFINITE;
234
235    return FP_NAN;
236 }
237
238 #if defined(BOOST_MATH_USE_STD_FPCLASSIFY) && defined(BOOST_MATH_NO_NATIVE_LONG_DOUBLE_FP_CLASSIFY)
239 template <>
240 inline int fpclassify_imp<long double> BOOST_NO_MACRO_EXPAND(long double t, const native_tag&)
241 {
242    return boost::math::detail::fpclassify_imp(t, generic_tag<true>());
243 }
244 #endif
245
246 }  // namespace detail
247
248 template <class T>
249 inline int fpclassify BOOST_NO_MACRO_EXPAND(T t)
250 {
251    typedef typename detail::fp_traits<T>::type traits;
252    typedef typename traits::method method;
253 #ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
254    if(std::numeric_limits<T>::is_specialized && detail::is_generic_tag_false(method()))
255       return detail::fpclassify_imp(t, detail::generic_tag<true>());
256    return detail::fpclassify_imp(t, method());
257 #else
258    return detail::fpclassify_imp(t, method());
259 #endif
260 }
261
262 namespace detail {
263
264 #ifdef BOOST_MATH_USE_STD_FPCLASSIFY
265     template<class T> 
266     inline bool isfinite_impl(T x, native_tag const&)
267     {
268         return (std::isfinite)(x);
269     }
270 #endif
271
272     template<class T> 
273     inline bool isfinite_impl(T x, generic_tag<true> const&)
274     {
275         return x >= -(std::numeric_limits<T>::max)()
276             && x <= (std::numeric_limits<T>::max)();
277     }
278
279     template<class T> 
280     inline bool isfinite_impl(T x, generic_tag<false> const&)
281     {
282 #ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
283       if(std::numeric_limits<T>::is_specialized)
284          return isfinite_impl(x, mpl::true_());
285 #endif
286        (void)x; // warning supression.
287        return true;
288     }
289
290     template<class T> 
291     inline bool isfinite_impl(T x, ieee_tag const&)
292     {
293         typedef BOOST_DEDUCED_TYPENAME detail::fp_traits<T>::type traits;
294         BOOST_DEDUCED_TYPENAME traits::bits a;
295         traits::get_bits(x,a);
296         a &= traits::exponent;
297         return a != traits::exponent;
298     }
299
300 #if defined(BOOST_MATH_USE_STD_FPCLASSIFY) && defined(BOOST_MATH_NO_NATIVE_LONG_DOUBLE_FP_CLASSIFY)
301 template <>
302 inline bool isfinite_impl<long double> BOOST_NO_MACRO_EXPAND(long double t, const native_tag&)
303 {
304    return boost::math::detail::isfinite_impl(t, generic_tag<true>());
305 }
306 #endif
307
308 }
309
310 template<class T> 
311 inline bool (isfinite)(T x)
312 { //!< \brief return true if floating-point type t is finite.
313    typedef typename detail::fp_traits<T>::type traits;
314    typedef typename traits::method method;
315    typedef typename boost::is_floating_point<T>::type fp_tag;
316    return detail::isfinite_impl(x, method());
317 }
318
319 //------------------------------------------------------------------------------
320
321 namespace detail {
322
323 #ifdef BOOST_MATH_USE_STD_FPCLASSIFY
324     template<class T> 
325     inline bool isnormal_impl(T x, native_tag const&)
326     {
327         return (std::isnormal)(x);
328     }
329 #endif
330
331     template<class T> 
332     inline bool isnormal_impl(T x, generic_tag<true> const&)
333     {
334         if(x < 0) x = -x;
335         return x >= (std::numeric_limits<T>::min)()
336             && x <= (std::numeric_limits<T>::max)();
337     }
338
339     template<class T> 
340     inline bool isnormal_impl(T x, generic_tag<false> const&)
341     {
342 #ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
343       if(std::numeric_limits<T>::is_specialized)
344          return isnormal_impl(x, mpl::true_());
345 #endif
346        return !(x == 0);
347     }
348
349     template<class T> 
350     inline bool isnormal_impl(T x, ieee_tag const&)
351     {
352         typedef BOOST_DEDUCED_TYPENAME detail::fp_traits<T>::type traits;
353         BOOST_DEDUCED_TYPENAME traits::bits a;
354         traits::get_bits(x,a);
355         a &= traits::exponent | traits::flag;
356         return (a != 0) && (a < traits::exponent);
357     }
358
359 #if defined(BOOST_MATH_USE_STD_FPCLASSIFY) && defined(BOOST_MATH_NO_NATIVE_LONG_DOUBLE_FP_CLASSIFY)
360 template <>
361 inline bool isnormal_impl<long double> BOOST_NO_MACRO_EXPAND(long double t, const native_tag&)
362 {
363    return boost::math::detail::isnormal_impl(t, generic_tag<true>());
364 }
365 #endif
366
367 }
368
369 template<class T> 
370 inline bool (isnormal)(T x)
371 {
372    typedef typename detail::fp_traits<T>::type traits;
373    typedef typename traits::method method;
374    typedef typename boost::is_floating_point<T>::type fp_tag;
375    return detail::isnormal_impl(x, method());
376 }
377
378 //------------------------------------------------------------------------------
379
380 namespace detail {
381
382 #ifdef BOOST_MATH_USE_STD_FPCLASSIFY
383     template<class T> 
384     inline bool isinf_impl(T x, native_tag const&)
385     {
386         return (std::isinf)(x);
387     }
388 #endif
389
390     template<class T> 
391     inline bool isinf_impl(T x, generic_tag<true> const&)
392     {
393         (void)x; // in case the compiler thinks that x is unused because std::numeric_limits<T>::has_infinity is false
394         return std::numeric_limits<T>::has_infinity 
395             && ( x == std::numeric_limits<T>::infinity()
396                  || x == -std::numeric_limits<T>::infinity());
397     }
398
399     template<class T> 
400     inline bool isinf_impl(T x, generic_tag<false> const&)
401     {
402 #ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
403       if(std::numeric_limits<T>::is_specialized)
404          return isinf_impl(x, mpl::true_());
405 #endif
406         (void)x; // warning supression.
407         return false;
408     }
409
410     template<class T> 
411     inline bool isinf_impl(T x, ieee_copy_all_bits_tag const&)
412     {
413         typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
414
415         BOOST_DEDUCED_TYPENAME traits::bits a;
416         traits::get_bits(x,a);
417         a &= traits::exponent | traits::significand;
418         return a == traits::exponent;
419     }
420
421     template<class T> 
422     inline bool isinf_impl(T x, ieee_copy_leading_bits_tag const&)
423     {
424         typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
425
426         BOOST_DEDUCED_TYPENAME traits::bits a;
427         traits::get_bits(x,a);
428         a &= traits::exponent | traits::significand;
429         if(a != traits::exponent)
430             return false;
431
432         traits::set_bits(x,0);
433         return x == 0;
434     }
435
436 #if defined(BOOST_MATH_USE_STD_FPCLASSIFY) && defined(BOOST_MATH_NO_NATIVE_LONG_DOUBLE_FP_CLASSIFY)
437 template <>
438 inline bool isinf_impl<long double> BOOST_NO_MACRO_EXPAND(long double t, const native_tag&)
439 {
440    return boost::math::detail::isinf_impl(t, generic_tag<true>());
441 }
442 #endif
443
444 }   // namespace detail
445
446 template<class T> 
447 inline bool (isinf)(T x)
448 {
449    typedef typename detail::fp_traits<T>::type traits;
450    typedef typename traits::method method;
451    typedef typename boost::is_floating_point<T>::type fp_tag;
452    return detail::isinf_impl(x, method());
453 }
454
455 //------------------------------------------------------------------------------
456
457 namespace detail {
458
459 #ifdef BOOST_MATH_USE_STD_FPCLASSIFY
460     template<class T> 
461     inline bool isnan_impl(T x, native_tag const&)
462     {
463         return (std::isnan)(x);
464     }
465 #endif
466
467     template<class T> 
468     inline bool isnan_impl(T x, generic_tag<true> const&)
469     {
470         return std::numeric_limits<T>::has_infinity
471             ? !(x <= std::numeric_limits<T>::infinity())
472             : x != x;
473     }
474
475     template<class T> 
476     inline bool isnan_impl(T x, generic_tag<false> const&)
477     {
478 #ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
479       if(std::numeric_limits<T>::is_specialized)
480          return isnan_impl(x, mpl::true_());
481 #endif
482         (void)x; // warning supression
483         return false;
484     }
485
486     template<class T> 
487     inline bool isnan_impl(T x, ieee_copy_all_bits_tag const&)
488     {
489         typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
490
491         BOOST_DEDUCED_TYPENAME traits::bits a;
492         traits::get_bits(x,a);
493         a &= traits::exponent | traits::significand;
494         return a > traits::exponent;
495     }
496
497     template<class T> 
498     inline bool isnan_impl(T x, ieee_copy_leading_bits_tag const&)
499     {
500         typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
501
502         BOOST_DEDUCED_TYPENAME traits::bits a;
503         traits::get_bits(x,a);
504
505         a &= traits::exponent | traits::significand;
506         if(a < traits::exponent)
507             return false;
508
509         a &= traits::significand;
510         traits::set_bits(x,a);
511         return x != 0;
512     }
513
514 }   // namespace detail
515
516 template<class T> bool (isnan)(T x)
517 { //!< \brief return true if floating-point type t is NaN (Not A Number).
518    typedef typename detail::fp_traits<T>::type traits;
519    typedef typename traits::method method;
520    typedef typename boost::is_floating_point<T>::type fp_tag;
521    return detail::isnan_impl(x, method());
522 }
523
524 #ifdef isnan
525 template <> inline bool isnan BOOST_NO_MACRO_EXPAND<float>(float t){ return ::boost::math_detail::is_nan_helper(t, boost::true_type()); }
526 template <> inline bool isnan BOOST_NO_MACRO_EXPAND<double>(double t){ return ::boost::math_detail::is_nan_helper(t, boost::true_type()); }
527 template <> inline bool isnan BOOST_NO_MACRO_EXPAND<long double>(long double t){ return ::boost::math_detail::is_nan_helper(t, boost::true_type()); }
528 #endif
529
530 } // namespace math
531 } // namespace boost
532
533 #endif // BOOST_MATH_FPCLASSIFY_HPP
534