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{
98 inline bool is_nan_helper(T t, const boost::true_type&)
102 #elif defined(BOOST_MATH_DISABLE_STD_FPCLASSIFY) || !defined(BOOST_HAS_FPCLASSIFY)
104 #else // BOOST_HAS_FPCLASSIFY
105 return (BOOST_FPCLASSIFY_PREFIX fpclassify(t) == (int)FP_NAN);
110 inline bool is_nan_helper(T, const boost::false_type&)
121 #ifdef BOOST_MATH_USE_STD_FPCLASSIFY
123 inline int fpclassify_imp BOOST_NO_MACRO_EXPAND(T t, const native_tag&)
125 return (std::fpclassify)(t);
130 inline int fpclassify_imp BOOST_NO_MACRO_EXPAND(T t, const generic_tag<true>&)
132 BOOST_MATH_INSTRUMENT_VARIABLE(t);
134 // whenever possible check for Nan's first:
135 #if defined(BOOST_HAS_FPCLASSIFY) && !defined(BOOST_MATH_DISABLE_STD_FPCLASSIFY)
136 if(::boost::math_detail::is_nan_helper(t, ::boost::is_floating_point<T>()))
139 if(boost::math_detail::is_nan_helper(t, ::boost::is_floating_point<T>()))
141 #elif defined(_MSC_VER) || defined(__BORLANDC__)
142 if(::_isnan(boost::math::tools::real_cast<double>(t)))
145 // std::fabs broken on a few systems especially for long long!!!!
146 T at = (t < T(0)) ? -t : t;
148 // Use a process of exclusion to figure out
149 // what kind of type we have, this relies on
150 // IEEE conforming reals that will treat
151 // Nan's as unordered. Some compilers
152 // don't do this once optimisations are
153 // turned on, hence the check for nan's above.
154 if(at <= (std::numeric_limits<T>::max)())
156 if(at >= (std::numeric_limits<T>::min)())
158 return (at != 0) ? FP_SUBNORMAL : FP_ZERO;
160 else if(at > (std::numeric_limits<T>::max)())
166 inline int fpclassify_imp BOOST_NO_MACRO_EXPAND(T t, const generic_tag<false>&)
168 #ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
169 if(std::numeric_limits<T>::is_specialized)
170 return fp_classify_imp(t, mpl::true_());
173 // An unknown type with no numeric_limits support,
174 // so what are we supposed to do we do here?
176 BOOST_MATH_INSTRUMENT_VARIABLE(t);
178 return t == 0 ? FP_ZERO : FP_NORMAL;
182 int fpclassify_imp BOOST_NO_MACRO_EXPAND(T x, ieee_copy_all_bits_tag)
184 typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
186 BOOST_MATH_INSTRUMENT_VARIABLE(x);
188 BOOST_DEDUCED_TYPENAME traits::bits a;
189 traits::get_bits(x,a);
190 BOOST_MATH_INSTRUMENT_VARIABLE(a);
191 a &= traits::exponent | traits::flag | traits::significand;
192 BOOST_MATH_INSTRUMENT_VARIABLE((traits::exponent | traits::flag | traits::significand));
193 BOOST_MATH_INSTRUMENT_VARIABLE(a);
195 if(a <= traits::significand) {
202 if(a < traits::exponent) return FP_NORMAL;
204 a &= traits::significand;
205 if(a == 0) return FP_INFINITE;
211 int fpclassify_imp BOOST_NO_MACRO_EXPAND(T x, ieee_copy_leading_bits_tag)
213 typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
215 BOOST_MATH_INSTRUMENT_VARIABLE(x);
217 BOOST_DEDUCED_TYPENAME traits::bits a;
218 traits::get_bits(x,a);
219 a &= traits::exponent | traits::flag | traits::significand;
221 if(a <= traits::significand) {
228 if(a < traits::exponent) return FP_NORMAL;
230 a &= traits::significand;
231 traits::set_bits(x,a);
232 if(x == 0) return FP_INFINITE;
237 #if defined(BOOST_MATH_USE_STD_FPCLASSIFY) && defined(BOOST_MATH_NO_NATIVE_LONG_DOUBLE_FP_CLASSIFY)
239 inline int fpclassify_imp<long double> BOOST_NO_MACRO_EXPAND(long double t, const native_tag&)
241 return boost::math::detail::fpclassify_imp(t, generic_tag<true>());
245 } // namespace detail
248 inline int fpclassify BOOST_NO_MACRO_EXPAND(T t)
250 typedef typename detail::fp_traits<T>::type traits;
251 typedef typename traits::method method;
252 #ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
253 if(std::numeric_limits<T>::is_specialized && detail::is_generic_tag_false(method()))
254 return detail::fpclassify_imp(t, detail::generic_tag<true>());
255 return detail::fpclassify_imp(t, method());
257 return detail::fpclassify_imp(t, method());
263 #ifdef BOOST_MATH_USE_STD_FPCLASSIFY
265 inline bool isfinite_impl(T x, native_tag const&)
267 return (std::isfinite)(x);
272 inline bool isfinite_impl(T x, generic_tag<true> const&)
274 return x >= -(std::numeric_limits<T>::max)()
275 && x <= (std::numeric_limits<T>::max)();
279 inline bool isfinite_impl(T x, generic_tag<false> const&)
281 #ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
282 if(std::numeric_limits<T>::is_specialized)
283 return isfinite_impl(x, mpl::true_());
285 (void)x; // warning supression.
290 inline bool isfinite_impl(T x, ieee_tag const&)
292 typedef BOOST_DEDUCED_TYPENAME detail::fp_traits<T>::type traits;
293 BOOST_DEDUCED_TYPENAME traits::bits a;
294 traits::get_bits(x,a);
295 a &= traits::exponent;
296 return a != traits::exponent;
299 #if defined(BOOST_MATH_USE_STD_FPCLASSIFY) && defined(BOOST_MATH_NO_NATIVE_LONG_DOUBLE_FP_CLASSIFY)
301 inline bool isfinite_impl<long double> BOOST_NO_MACRO_EXPAND(long double t, const native_tag&)
303 return boost::math::detail::isfinite_impl(t, generic_tag<true>());
310 inline bool (isfinite)(T x)
311 { //!< \brief return true if floating-point type t is finite.
312 typedef typename detail::fp_traits<T>::type traits;
313 typedef typename traits::method method;
314 typedef typename boost::is_floating_point<T>::type fp_tag;
315 return detail::isfinite_impl(x, method());
318 //------------------------------------------------------------------------------
322 #ifdef BOOST_MATH_USE_STD_FPCLASSIFY
324 inline bool isnormal_impl(T x, native_tag const&)
326 return (std::isnormal)(x);
331 inline bool isnormal_impl(T x, generic_tag<true> const&)
334 return x >= (std::numeric_limits<T>::min)()
335 && x <= (std::numeric_limits<T>::max)();
339 inline bool isnormal_impl(T x, generic_tag<false> const&)
341 #ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
342 if(std::numeric_limits<T>::is_specialized)
343 return isnormal_impl(x, mpl::true_());
349 inline bool isnormal_impl(T x, ieee_tag const&)
351 typedef BOOST_DEDUCED_TYPENAME detail::fp_traits<T>::type traits;
352 BOOST_DEDUCED_TYPENAME traits::bits a;
353 traits::get_bits(x,a);
354 a &= traits::exponent | traits::flag;
355 return (a != 0) && (a < traits::exponent);
358 #if defined(BOOST_MATH_USE_STD_FPCLASSIFY) && defined(BOOST_MATH_NO_NATIVE_LONG_DOUBLE_FP_CLASSIFY)
360 inline bool isnormal_impl<long double> BOOST_NO_MACRO_EXPAND(long double t, const native_tag&)
362 return boost::math::detail::isnormal_impl(t, generic_tag<true>());
369 inline bool (isnormal)(T x)
371 typedef typename detail::fp_traits<T>::type traits;
372 typedef typename traits::method method;
373 typedef typename boost::is_floating_point<T>::type fp_tag;
374 return detail::isnormal_impl(x, method());
377 //------------------------------------------------------------------------------
381 #ifdef BOOST_MATH_USE_STD_FPCLASSIFY
383 inline bool isinf_impl(T x, native_tag const&)
385 return (std::isinf)(x);
390 inline bool isinf_impl(T x, generic_tag<true> const&)
392 (void)x; // in case the compiler thinks that x is unused because std::numeric_limits<T>::has_infinity is false
393 return std::numeric_limits<T>::has_infinity
394 && ( x == std::numeric_limits<T>::infinity()
395 || x == -std::numeric_limits<T>::infinity());
399 inline bool isinf_impl(T x, generic_tag<false> const&)
401 #ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
402 if(std::numeric_limits<T>::is_specialized)
403 return isinf_impl(x, mpl::true_());
405 (void)x; // warning supression.
410 inline bool isinf_impl(T x, ieee_copy_all_bits_tag const&)
412 typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
414 BOOST_DEDUCED_TYPENAME traits::bits a;
415 traits::get_bits(x,a);
416 a &= traits::exponent | traits::significand;
417 return a == traits::exponent;
421 inline bool isinf_impl(T x, ieee_copy_leading_bits_tag const&)
423 typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
425 BOOST_DEDUCED_TYPENAME traits::bits a;
426 traits::get_bits(x,a);
427 a &= traits::exponent | traits::significand;
428 if(a != traits::exponent)
431 traits::set_bits(x,0);
435 #if defined(BOOST_MATH_USE_STD_FPCLASSIFY) && defined(BOOST_MATH_NO_NATIVE_LONG_DOUBLE_FP_CLASSIFY)
437 inline bool isinf_impl<long double> BOOST_NO_MACRO_EXPAND(long double t, const native_tag&)
439 return boost::math::detail::isinf_impl(t, generic_tag<true>());
443 } // namespace detail
446 inline bool (isinf)(T x)
448 typedef typename detail::fp_traits<T>::type traits;
449 typedef typename traits::method method;
450 typedef typename boost::is_floating_point<T>::type fp_tag;
451 return detail::isinf_impl(x, method());
454 //------------------------------------------------------------------------------
458 #ifdef BOOST_MATH_USE_STD_FPCLASSIFY
460 inline bool isnan_impl(T x, native_tag const&)
462 return (std::isnan)(x);
467 inline bool isnan_impl(T x, generic_tag<true> const&)
469 return std::numeric_limits<T>::has_infinity
470 ? !(x <= std::numeric_limits<T>::infinity())
475 inline bool isnan_impl(T x, generic_tag<false> const&)
477 #ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
478 if(std::numeric_limits<T>::is_specialized)
479 return isnan_impl(x, mpl::true_());
481 (void)x; // warning supression
486 inline bool isnan_impl(T x, ieee_copy_all_bits_tag const&)
488 typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
490 BOOST_DEDUCED_TYPENAME traits::bits a;
491 traits::get_bits(x,a);
492 a &= traits::exponent | traits::significand;
493 return a > traits::exponent;
497 inline bool isnan_impl(T x, ieee_copy_leading_bits_tag const&)
499 typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
501 BOOST_DEDUCED_TYPENAME traits::bits a;
502 traits::get_bits(x,a);
504 a &= traits::exponent | traits::significand;
505 if(a < traits::exponent)
508 a &= traits::significand;
509 traits::set_bits(x,a);
513 } // namespace detail
515 template<class T> bool (isnan)(T x)
516 { //!< \brief return true if floating-point type t is NaN (Not A Number).
517 typedef typename detail::fp_traits<T>::type traits;
518 typedef typename traits::method method;
519 typedef typename boost::is_floating_point<T>::type fp_tag;
520 return detail::isnan_impl(x, method());
524 template <> inline bool isnan BOOST_NO_MACRO_EXPAND<float>(float t){ return ::boost::math_detail::is_nan_helper(t, boost::true_type()); }
525 template <> inline bool isnan BOOST_NO_MACRO_EXPAND<double>(double t){ return ::boost::math_detail::is_nan_helper(t, boost::true_type()); }
526 template <> inline bool isnan BOOST_NO_MACRO_EXPAND<long double>(long double t){ return ::boost::math_detail::is_nan_helper(t, boost::true_type()); }
532 #endif // BOOST_MATH_FPCLASSIFY_HPP