]> git.donarmstrong.com Git - rsem.git/blob - boost/math/special_functions/fpclassify.hpp
Updated boost to v1.55.0
[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 //
91 // This must not be located in any namespace under boost::math
92 // otherwise we can get into an infinite loop if isnan is
93 // a #define for "isnan" !
94 //
95 namespace math_detail{
96
97 #ifdef BOOST_MSVC
98 #pragma warning(push)
99 #pragma warning(disable:4800)
100 #endif
101
102 template <class T>
103 inline bool is_nan_helper(T t, const boost::true_type&)
104 {
105 #ifdef isnan
106    return isnan(t);
107 #elif defined(BOOST_MATH_DISABLE_STD_FPCLASSIFY) || !defined(BOOST_HAS_FPCLASSIFY)
108    (void)t;
109    return false;
110 #else // BOOST_HAS_FPCLASSIFY
111    return (BOOST_FPCLASSIFY_PREFIX fpclassify(t) == (int)FP_NAN);
112 #endif
113 }
114
115 #ifdef BOOST_MSVC
116 #pragma warning(pop)
117 #endif
118
119 template <class T>
120 inline bool is_nan_helper(T, const boost::false_type&)
121 {
122    return false;
123 }
124
125 }
126
127 namespace math{
128
129 namespace detail{
130
131 #ifdef BOOST_MATH_USE_STD_FPCLASSIFY
132 template <class T>
133 inline int fpclassify_imp BOOST_NO_MACRO_EXPAND(T t, const native_tag&)
134 {
135    return (std::fpclassify)(t);
136 }
137 #endif
138
139 template <class T>
140 inline int fpclassify_imp BOOST_NO_MACRO_EXPAND(T t, const generic_tag<true>&)
141 {
142    BOOST_MATH_INSTRUMENT_VARIABLE(t);
143
144    // whenever possible check for Nan's first:
145 #if defined(BOOST_HAS_FPCLASSIFY)  && !defined(BOOST_MATH_DISABLE_STD_FPCLASSIFY)
146    if(::boost::math_detail::is_nan_helper(t, ::boost::is_floating_point<T>()))
147       return FP_NAN;
148 #elif defined(isnan)
149    if(boost::math_detail::is_nan_helper(t, ::boost::is_floating_point<T>()))
150       return FP_NAN;
151 #elif defined(_MSC_VER) || defined(__BORLANDC__)
152    if(::_isnan(boost::math::tools::real_cast<double>(t)))
153       return FP_NAN;
154 #endif
155    // std::fabs broken on a few systems especially for long long!!!!
156    T at = (t < T(0)) ? -t : t;
157
158    // Use a process of exclusion to figure out
159    // what kind of type we have, this relies on
160    // IEEE conforming reals that will treat
161    // Nan's as unordered.  Some compilers
162    // don't do this once optimisations are
163    // turned on, hence the check for nan's above.
164    if(at <= (std::numeric_limits<T>::max)())
165    {
166       if(at >= (std::numeric_limits<T>::min)())
167          return FP_NORMAL;
168       return (at != 0) ? FP_SUBNORMAL : FP_ZERO;
169    }
170    else if(at > (std::numeric_limits<T>::max)())
171       return FP_INFINITE;
172    return FP_NAN;
173 }
174
175 template <class T>
176 inline int fpclassify_imp BOOST_NO_MACRO_EXPAND(T t, const generic_tag<false>&)
177 {
178 #ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
179    if(std::numeric_limits<T>::is_specialized)
180       return fpclassify_imp(t, generic_tag<true>());
181 #endif
182    //
183    // An unknown type with no numeric_limits support,
184    // so what are we supposed to do we do here?
185    //
186    BOOST_MATH_INSTRUMENT_VARIABLE(t);
187
188    return t == 0 ? FP_ZERO : FP_NORMAL;
189 }
190
191 template<class T>
192 int fpclassify_imp BOOST_NO_MACRO_EXPAND(T x, ieee_copy_all_bits_tag)
193 {
194    typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
195
196    BOOST_MATH_INSTRUMENT_VARIABLE(x);
197
198    BOOST_DEDUCED_TYPENAME traits::bits a;
199    traits::get_bits(x,a);
200    BOOST_MATH_INSTRUMENT_VARIABLE(a);
201    a &= traits::exponent | traits::flag | traits::significand;
202    BOOST_MATH_INSTRUMENT_VARIABLE((traits::exponent | traits::flag | traits::significand));
203    BOOST_MATH_INSTRUMENT_VARIABLE(a);
204
205    if(a <= traits::significand) {
206       if(a == 0)
207          return FP_ZERO;
208       else
209          return FP_SUBNORMAL;
210    }
211
212    if(a < traits::exponent) return FP_NORMAL;
213
214    a &= traits::significand;
215    if(a == 0) return FP_INFINITE;
216
217    return FP_NAN;
218 }
219
220 template<class T>
221 int fpclassify_imp BOOST_NO_MACRO_EXPAND(T x, ieee_copy_leading_bits_tag)
222 {
223    typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
224
225    BOOST_MATH_INSTRUMENT_VARIABLE(x);
226
227    BOOST_DEDUCED_TYPENAME traits::bits a;
228    traits::get_bits(x,a);
229    a &= traits::exponent | traits::flag | traits::significand;
230
231    if(a <= traits::significand) {
232       if(x == 0)
233          return FP_ZERO;
234       else
235          return FP_SUBNORMAL;
236    }
237
238    if(a < traits::exponent) return FP_NORMAL;
239
240    a &= traits::significand;
241    traits::set_bits(x,a);
242    if(x == 0) return FP_INFINITE;
243
244    return FP_NAN;
245 }
246
247 #if defined(BOOST_MATH_USE_STD_FPCLASSIFY) && (defined(BOOST_MATH_NO_NATIVE_LONG_DOUBLE_FP_CLASSIFY) || defined(BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS))
248 inline int fpclassify_imp BOOST_NO_MACRO_EXPAND(long double t, const native_tag&)
249 {
250    return boost::math::detail::fpclassify_imp(t, generic_tag<true>());
251 }
252 #endif
253
254 }  // namespace detail
255
256 template <class T>
257 inline int fpclassify BOOST_NO_MACRO_EXPAND(T t)
258 {
259    typedef typename detail::fp_traits<T>::type traits;
260    typedef typename traits::method method;
261    typedef typename tools::promote_args_permissive<T>::type value_type;
262 #ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
263    if(std::numeric_limits<T>::is_specialized && detail::is_generic_tag_false(static_cast<method*>(0)))
264       return detail::fpclassify_imp(static_cast<value_type>(t), detail::generic_tag<true>());
265    return detail::fpclassify_imp(static_cast<value_type>(t), method());
266 #else
267    return detail::fpclassify_imp(static_cast<value_type>(t), method());
268 #endif
269 }
270
271 #ifdef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
272 template <>
273 inline int fpclassify<long double> BOOST_NO_MACRO_EXPAND(long double t)
274 {
275    typedef detail::fp_traits<long double>::type traits;
276    typedef traits::method method;
277    typedef long double value_type;
278 #ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
279    if(std::numeric_limits<long double>::is_specialized && detail::is_generic_tag_false(static_cast<method*>(0)))
280       return detail::fpclassify_imp(static_cast<value_type>(t), detail::generic_tag<true>());
281    return detail::fpclassify_imp(static_cast<value_type>(t), method());
282 #else
283    return detail::fpclassify_imp(static_cast<value_type>(t), method());
284 #endif
285 }
286 #endif
287
288 namespace detail {
289
290 #ifdef BOOST_MATH_USE_STD_FPCLASSIFY
291     template<class T>
292     inline bool isfinite_impl(T x, native_tag const&)
293     {
294         return (std::isfinite)(x);
295     }
296 #endif
297
298     template<class T>
299     inline bool isfinite_impl(T x, generic_tag<true> const&)
300     {
301         return x >= -(std::numeric_limits<T>::max)()
302             && x <= (std::numeric_limits<T>::max)();
303     }
304
305     template<class T>
306     inline bool isfinite_impl(T x, generic_tag<false> const&)
307     {
308 #ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
309       if(std::numeric_limits<T>::is_specialized)
310          return isfinite_impl(x, generic_tag<true>());
311 #endif
312        (void)x; // warning supression.
313        return true;
314     }
315
316     template<class T>
317     inline bool isfinite_impl(T x, ieee_tag const&)
318     {
319         typedef BOOST_DEDUCED_TYPENAME detail::fp_traits<T>::type traits;
320         BOOST_DEDUCED_TYPENAME traits::bits a;
321         traits::get_bits(x,a);
322         a &= traits::exponent;
323         return a != traits::exponent;
324     }
325
326 #if defined(BOOST_MATH_USE_STD_FPCLASSIFY) && defined(BOOST_MATH_NO_NATIVE_LONG_DOUBLE_FP_CLASSIFY)
327 inline bool isfinite_impl BOOST_NO_MACRO_EXPAND(long double t, const native_tag&)
328 {
329    return boost::math::detail::isfinite_impl(t, generic_tag<true>());
330 }
331 #endif
332
333 }
334
335 template<class T>
336 inline bool (isfinite)(T x)
337 { //!< \brief return true if floating-point type t is finite.
338    typedef typename detail::fp_traits<T>::type traits;
339    typedef typename traits::method method;
340    // typedef typename boost::is_floating_point<T>::type fp_tag;
341    typedef typename tools::promote_args_permissive<T>::type value_type;
342    return detail::isfinite_impl(static_cast<value_type>(x), method());
343 }
344
345 #ifdef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
346 template<>
347 inline bool (isfinite)(long double x)
348 { //!< \brief return true if floating-point type t is finite.
349    typedef detail::fp_traits<long double>::type traits;
350    typedef traits::method method;
351    typedef boost::is_floating_point<long double>::type fp_tag;
352    typedef long double value_type;
353    return detail::isfinite_impl(static_cast<value_type>(x), method());
354 }
355 #endif
356
357 //------------------------------------------------------------------------------
358
359 namespace detail {
360
361 #ifdef BOOST_MATH_USE_STD_FPCLASSIFY
362     template<class T>
363     inline bool isnormal_impl(T x, native_tag const&)
364     {
365         return (std::isnormal)(x);
366     }
367 #endif
368
369     template<class T>
370     inline bool isnormal_impl(T x, generic_tag<true> const&)
371     {
372         if(x < 0) x = -x;
373         return x >= (std::numeric_limits<T>::min)()
374             && x <= (std::numeric_limits<T>::max)();
375     }
376
377     template<class T>
378     inline bool isnormal_impl(T x, generic_tag<false> const&)
379     {
380 #ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
381       if(std::numeric_limits<T>::is_specialized)
382          return isnormal_impl(x, generic_tag<true>());
383 #endif
384        return !(x == 0);
385     }
386
387     template<class T>
388     inline bool isnormal_impl(T x, ieee_tag const&)
389     {
390         typedef BOOST_DEDUCED_TYPENAME detail::fp_traits<T>::type traits;
391         BOOST_DEDUCED_TYPENAME traits::bits a;
392         traits::get_bits(x,a);
393         a &= traits::exponent | traits::flag;
394         return (a != 0) && (a < traits::exponent);
395     }
396
397 #if defined(BOOST_MATH_USE_STD_FPCLASSIFY) && defined(BOOST_MATH_NO_NATIVE_LONG_DOUBLE_FP_CLASSIFY)
398 inline bool isnormal_impl BOOST_NO_MACRO_EXPAND(long double t, const native_tag&)
399 {
400    return boost::math::detail::isnormal_impl(t, generic_tag<true>());
401 }
402 #endif
403
404 }
405
406 template<class T>
407 inline bool (isnormal)(T x)
408 {
409    typedef typename detail::fp_traits<T>::type traits;
410    typedef typename traits::method method;
411    //typedef typename boost::is_floating_point<T>::type fp_tag;
412    typedef typename tools::promote_args_permissive<T>::type value_type;
413    return detail::isnormal_impl(static_cast<value_type>(x), method());
414 }
415
416 #ifdef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
417 template<>
418 inline bool (isnormal)(long double x)
419 {
420    typedef detail::fp_traits<long double>::type traits;
421    typedef traits::method method;
422    typedef boost::is_floating_point<long double>::type fp_tag;
423    typedef long double value_type;
424    return detail::isnormal_impl(static_cast<value_type>(x), method());
425 }
426 #endif
427
428 //------------------------------------------------------------------------------
429
430 namespace detail {
431
432 #ifdef BOOST_MATH_USE_STD_FPCLASSIFY
433     template<class T>
434     inline bool isinf_impl(T x, native_tag const&)
435     {
436         return (std::isinf)(x);
437     }
438 #endif
439
440     template<class T>
441     inline bool isinf_impl(T x, generic_tag<true> const&)
442     {
443         (void)x; // in case the compiler thinks that x is unused because std::numeric_limits<T>::has_infinity is false
444         return std::numeric_limits<T>::has_infinity
445             && ( x == std::numeric_limits<T>::infinity()
446                  || x == -std::numeric_limits<T>::infinity());
447     }
448
449     template<class T>
450     inline bool isinf_impl(T x, generic_tag<false> const&)
451     {
452 #ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
453       if(std::numeric_limits<T>::is_specialized)
454          return isinf_impl(x, generic_tag<true>());
455 #endif
456         (void)x; // warning supression.
457         return false;
458     }
459
460     template<class T>
461     inline bool isinf_impl(T x, ieee_copy_all_bits_tag const&)
462     {
463         typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
464
465         BOOST_DEDUCED_TYPENAME traits::bits a;
466         traits::get_bits(x,a);
467         a &= traits::exponent | traits::significand;
468         return a == traits::exponent;
469     }
470
471     template<class T>
472     inline bool isinf_impl(T x, ieee_copy_leading_bits_tag const&)
473     {
474         typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
475
476         BOOST_DEDUCED_TYPENAME traits::bits a;
477         traits::get_bits(x,a);
478         a &= traits::exponent | traits::significand;
479         if(a != traits::exponent)
480             return false;
481
482         traits::set_bits(x,0);
483         return x == 0;
484     }
485
486 #if defined(BOOST_MATH_USE_STD_FPCLASSIFY) && defined(BOOST_MATH_NO_NATIVE_LONG_DOUBLE_FP_CLASSIFY)
487 inline bool isinf_impl BOOST_NO_MACRO_EXPAND(long double t, const native_tag&)
488 {
489    return boost::math::detail::isinf_impl(t, generic_tag<true>());
490 }
491 #endif
492
493 }   // namespace detail
494
495 template<class T>
496 inline bool (isinf)(T x)
497 {
498    typedef typename detail::fp_traits<T>::type traits;
499    typedef typename traits::method method;
500    // typedef typename boost::is_floating_point<T>::type fp_tag;
501    typedef typename tools::promote_args_permissive<T>::type value_type;
502    return detail::isinf_impl(static_cast<value_type>(x), method());
503 }
504
505 #ifdef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
506 template<>
507 inline bool (isinf)(long double x)
508 {
509    typedef detail::fp_traits<long double>::type traits;
510    typedef traits::method method;
511    typedef boost::is_floating_point<long double>::type fp_tag;
512    typedef long double value_type;
513    return detail::isinf_impl(static_cast<value_type>(x), method());
514 }
515 #endif
516
517 //------------------------------------------------------------------------------
518
519 namespace detail {
520
521 #ifdef BOOST_MATH_USE_STD_FPCLASSIFY
522     template<class T>
523     inline bool isnan_impl(T x, native_tag const&)
524     {
525         return (std::isnan)(x);
526     }
527 #endif
528
529     template<class T>
530     inline bool isnan_impl(T x, generic_tag<true> const&)
531     {
532         return std::numeric_limits<T>::has_infinity
533             ? !(x <= std::numeric_limits<T>::infinity())
534             : x != x;
535     }
536
537     template<class T>
538     inline bool isnan_impl(T x, generic_tag<false> const&)
539     {
540 #ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
541       if(std::numeric_limits<T>::is_specialized)
542          return isnan_impl(x, generic_tag<true>());
543 #endif
544         (void)x; // warning supression
545         return false;
546     }
547
548     template<class T>
549     inline bool isnan_impl(T x, ieee_copy_all_bits_tag const&)
550     {
551         typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
552
553         BOOST_DEDUCED_TYPENAME traits::bits a;
554         traits::get_bits(x,a);
555         a &= traits::exponent | traits::significand;
556         return a > traits::exponent;
557     }
558
559     template<class T>
560     inline bool isnan_impl(T x, ieee_copy_leading_bits_tag const&)
561     {
562         typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
563
564         BOOST_DEDUCED_TYPENAME traits::bits a;
565         traits::get_bits(x,a);
566
567         a &= traits::exponent | traits::significand;
568         if(a < traits::exponent)
569             return false;
570
571         a &= traits::significand;
572         traits::set_bits(x,a);
573         return x != 0;
574     }
575
576 }   // namespace detail
577
578 template<class T>
579 inline bool (isnan)(T x)
580 { //!< \brief return true if floating-point type t is NaN (Not A Number).
581    typedef typename detail::fp_traits<T>::type traits;
582    typedef typename traits::method method;
583    // typedef typename boost::is_floating_point<T>::type fp_tag;
584    return detail::isnan_impl(x, method());
585 }
586
587 #ifdef isnan
588 template <> inline bool isnan BOOST_NO_MACRO_EXPAND<float>(float t){ return ::boost::math_detail::is_nan_helper(t, boost::true_type()); }
589 template <> inline bool isnan BOOST_NO_MACRO_EXPAND<double>(double t){ return ::boost::math_detail::is_nan_helper(t, boost::true_type()); }
590 template <> inline bool isnan BOOST_NO_MACRO_EXPAND<long double>(long double t){ return ::boost::math_detail::is_nan_helper(t, boost::true_type()); }
591 #elif defined(BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS)
592 template<>
593 inline bool (isnan)(long double x)
594 { //!< \brief return true if floating-point type t is NaN (Not A Number).
595    typedef detail::fp_traits<long double>::type traits;
596    typedef traits::method method;
597    typedef boost::is_floating_point<long double>::type fp_tag;
598    return detail::isnan_impl(x, method());
599 }
600 #endif
601
602 } // namespace math
603 } // namespace boost
604
605 #endif // BOOST_MATH_FPCLASSIFY_HPP
606