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