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)
7 #ifndef BOOST_MATH_FPCLASSIFY_HPP
8 #define BOOST_MATH_FPCLASSIFY_HPP
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>
23 \brief Classify floating-point value as normal, subnormal, zero, infinite, or NaN.
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.
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:
40 If all exponent bits, the flag bit (if there is one),
41 and all significand bits are 0, then the number is zero.
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.
46 If all exponent bits are 1 and all significand bits are 0,
47 then the number is infinity.
49 If all exponent bits are 1 and at least one significand bit is 1,
50 then the number is a not-a-number.
52 Otherwise the number is normal.
54 This algorithm works for the IEEE 754 representation,
55 and also for several non IEEE 754 formats.
57 Most formats have the structure
58 sign bit + exponent bits + significand bits.
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.
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.
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
80 #if defined(_MSC_VER) || defined(__BORLANDC__)
84 #ifdef BOOST_NO_STDC_NAMESPACE
85 namespace std{ using ::abs; using ::fabs; }
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" !
95 namespace math_detail{
99 #pragma warning(disable:4800)
103 inline bool is_nan_helper(T t, const boost::true_type&)
107 #elif defined(BOOST_MATH_DISABLE_STD_FPCLASSIFY) || !defined(BOOST_HAS_FPCLASSIFY)
110 #else // BOOST_HAS_FPCLASSIFY
111 return (BOOST_FPCLASSIFY_PREFIX fpclassify(t) == (int)FP_NAN);
120 inline bool is_nan_helper(T, const boost::false_type&)
131 #ifdef BOOST_MATH_USE_STD_FPCLASSIFY
133 inline int fpclassify_imp BOOST_NO_MACRO_EXPAND(T t, const native_tag&)
135 return (std::fpclassify)(t);
140 inline int fpclassify_imp BOOST_NO_MACRO_EXPAND(T t, const generic_tag<true>&)
142 BOOST_MATH_INSTRUMENT_VARIABLE(t);
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>()))
149 if(boost::math_detail::is_nan_helper(t, ::boost::is_floating_point<T>()))
151 #elif defined(_MSC_VER) || defined(__BORLANDC__)
152 if(::_isnan(boost::math::tools::real_cast<double>(t)))
155 // std::fabs broken on a few systems especially for long long!!!!
156 T at = (t < T(0)) ? -t : t;
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)())
166 if(at >= (std::numeric_limits<T>::min)())
168 return (at != 0) ? FP_SUBNORMAL : FP_ZERO;
170 else if(at > (std::numeric_limits<T>::max)())
176 inline int fpclassify_imp BOOST_NO_MACRO_EXPAND(T t, const generic_tag<false>&)
178 #ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
179 if(std::numeric_limits<T>::is_specialized)
180 return fpclassify_imp(t, generic_tag<true>());
183 // An unknown type with no numeric_limits support,
184 // so what are we supposed to do we do here?
186 BOOST_MATH_INSTRUMENT_VARIABLE(t);
188 return t == 0 ? FP_ZERO : FP_NORMAL;
192 int fpclassify_imp BOOST_NO_MACRO_EXPAND(T x, ieee_copy_all_bits_tag)
194 typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
196 BOOST_MATH_INSTRUMENT_VARIABLE(x);
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);
205 if(a <= traits::significand) {
212 if(a < traits::exponent) return FP_NORMAL;
214 a &= traits::significand;
215 if(a == 0) return FP_INFINITE;
221 int fpclassify_imp BOOST_NO_MACRO_EXPAND(T x, ieee_copy_leading_bits_tag)
223 typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
225 BOOST_MATH_INSTRUMENT_VARIABLE(x);
227 BOOST_DEDUCED_TYPENAME traits::bits a;
228 traits::get_bits(x,a);
229 a &= traits::exponent | traits::flag | traits::significand;
231 if(a <= traits::significand) {
238 if(a < traits::exponent) return FP_NORMAL;
240 a &= traits::significand;
241 traits::set_bits(x,a);
242 if(x == 0) return FP_INFINITE;
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&)
250 return boost::math::detail::fpclassify_imp(t, generic_tag<true>());
254 } // namespace detail
257 inline int fpclassify BOOST_NO_MACRO_EXPAND(T t)
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());
267 return detail::fpclassify_imp(static_cast<value_type>(t), method());
271 #ifdef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
273 inline int fpclassify<long double> BOOST_NO_MACRO_EXPAND(long double t)
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());
283 return detail::fpclassify_imp(static_cast<value_type>(t), method());
290 #ifdef BOOST_MATH_USE_STD_FPCLASSIFY
292 inline bool isfinite_impl(T x, native_tag const&)
294 return (std::isfinite)(x);
299 inline bool isfinite_impl(T x, generic_tag<true> const&)
301 return x >= -(std::numeric_limits<T>::max)()
302 && x <= (std::numeric_limits<T>::max)();
306 inline bool isfinite_impl(T x, generic_tag<false> const&)
308 #ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
309 if(std::numeric_limits<T>::is_specialized)
310 return isfinite_impl(x, generic_tag<true>());
312 (void)x; // warning supression.
317 inline bool isfinite_impl(T x, ieee_tag const&)
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;
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&)
329 return boost::math::detail::isfinite_impl(t, generic_tag<true>());
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());
345 #ifdef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
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());
357 //------------------------------------------------------------------------------
361 #ifdef BOOST_MATH_USE_STD_FPCLASSIFY
363 inline bool isnormal_impl(T x, native_tag const&)
365 return (std::isnormal)(x);
370 inline bool isnormal_impl(T x, generic_tag<true> const&)
373 return x >= (std::numeric_limits<T>::min)()
374 && x <= (std::numeric_limits<T>::max)();
378 inline bool isnormal_impl(T x, generic_tag<false> const&)
380 #ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
381 if(std::numeric_limits<T>::is_specialized)
382 return isnormal_impl(x, generic_tag<true>());
388 inline bool isnormal_impl(T x, ieee_tag const&)
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);
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&)
400 return boost::math::detail::isnormal_impl(t, generic_tag<true>());
407 inline bool (isnormal)(T x)
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());
416 #ifdef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
418 inline bool (isnormal)(long double x)
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());
428 //------------------------------------------------------------------------------
432 #ifdef BOOST_MATH_USE_STD_FPCLASSIFY
434 inline bool isinf_impl(T x, native_tag const&)
436 return (std::isinf)(x);
441 inline bool isinf_impl(T x, generic_tag<true> const&)
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());
450 inline bool isinf_impl(T x, generic_tag<false> const&)
452 #ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
453 if(std::numeric_limits<T>::is_specialized)
454 return isinf_impl(x, generic_tag<true>());
456 (void)x; // warning supression.
461 inline bool isinf_impl(T x, ieee_copy_all_bits_tag const&)
463 typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
465 BOOST_DEDUCED_TYPENAME traits::bits a;
466 traits::get_bits(x,a);
467 a &= traits::exponent | traits::significand;
468 return a == traits::exponent;
472 inline bool isinf_impl(T x, ieee_copy_leading_bits_tag const&)
474 typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
476 BOOST_DEDUCED_TYPENAME traits::bits a;
477 traits::get_bits(x,a);
478 a &= traits::exponent | traits::significand;
479 if(a != traits::exponent)
482 traits::set_bits(x,0);
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&)
489 return boost::math::detail::isinf_impl(t, generic_tag<true>());
493 } // namespace detail
496 inline bool (isinf)(T x)
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());
505 #ifdef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
507 inline bool (isinf)(long double x)
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());
517 //------------------------------------------------------------------------------
521 #ifdef BOOST_MATH_USE_STD_FPCLASSIFY
523 inline bool isnan_impl(T x, native_tag const&)
525 return (std::isnan)(x);
530 inline bool isnan_impl(T x, generic_tag<true> const&)
532 return std::numeric_limits<T>::has_infinity
533 ? !(x <= std::numeric_limits<T>::infinity())
538 inline bool isnan_impl(T x, generic_tag<false> const&)
540 #ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
541 if(std::numeric_limits<T>::is_specialized)
542 return isnan_impl(x, generic_tag<true>());
544 (void)x; // warning supression
549 inline bool isnan_impl(T x, ieee_copy_all_bits_tag const&)
551 typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
553 BOOST_DEDUCED_TYPENAME traits::bits a;
554 traits::get_bits(x,a);
555 a &= traits::exponent | traits::significand;
556 return a > traits::exponent;
560 inline bool isnan_impl(T x, ieee_copy_leading_bits_tag const&)
562 typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
564 BOOST_DEDUCED_TYPENAME traits::bits a;
565 traits::get_bits(x,a);
567 a &= traits::exponent | traits::significand;
568 if(a < traits::exponent)
571 a &= traits::significand;
572 traits::set_bits(x,a);
576 } // namespace detail
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());
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)
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());
605 #endif // BOOST_MATH_FPCLASSIFY_HPP