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; }
90 #if defined(BOOST_HAS_FPCLASSIFY) || defined(isnan)
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" !
96 namespace math_detail{
99 inline bool is_nan_helper(T t, const boost::true_type&)
103 #else // BOOST_HAS_FPCLASSIFY
104 return (BOOST_FPCLASSIFY_PREFIX fpclassify(t) == (int)FP_NAN);
109 inline bool is_nan_helper(T, const boost::false_type&)
116 #endif // defined(BOOST_HAS_FPCLASSIFY) || defined(isnan)
122 #ifdef BOOST_MATH_USE_STD_FPCLASSIFY
124 inline int fpclassify_imp BOOST_NO_MACRO_EXPAND(T t, const native_tag&)
126 return (std::fpclassify)(t);
131 inline int fpclassify_imp BOOST_NO_MACRO_EXPAND(T t, const generic_tag<true>&)
133 BOOST_MATH_INSTRUMENT_VARIABLE(t);
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>()))
140 if(boost::math_detail::is_nan_helper(t, ::boost::is_floating_point<T>()))
142 #elif defined(_MSC_VER) || defined(__BORLANDC__)
143 if(::_isnan(boost::math::tools::real_cast<double>(t)))
146 // std::fabs broken on a few systems especially for long long!!!!
147 T at = (t < T(0)) ? -t : t;
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)())
157 if(at >= (std::numeric_limits<T>::min)())
159 return (at != 0) ? FP_SUBNORMAL : FP_ZERO;
161 else if(at > (std::numeric_limits<T>::max)())
167 inline int fpclassify_imp BOOST_NO_MACRO_EXPAND(T t, const generic_tag<false>&)
169 #ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
170 if(std::numeric_limits<T>::is_specialized)
171 return fp_classify_imp(t, mpl::true_());
174 // An unknown type with no numeric_limits support,
175 // so what are we supposed to do we do here?
177 BOOST_MATH_INSTRUMENT_VARIABLE(t);
179 return t == 0 ? FP_ZERO : FP_NORMAL;
183 int fpclassify_imp BOOST_NO_MACRO_EXPAND(T x, ieee_copy_all_bits_tag)
185 typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
187 BOOST_MATH_INSTRUMENT_VARIABLE(x);
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);
196 if(a <= traits::significand) {
203 if(a < traits::exponent) return FP_NORMAL;
205 a &= traits::significand;
206 if(a == 0) return FP_INFINITE;
212 int fpclassify_imp BOOST_NO_MACRO_EXPAND(T x, ieee_copy_leading_bits_tag)
214 typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
216 BOOST_MATH_INSTRUMENT_VARIABLE(x);
218 BOOST_DEDUCED_TYPENAME traits::bits a;
219 traits::get_bits(x,a);
220 a &= traits::exponent | traits::flag | traits::significand;
222 if(a <= traits::significand) {
229 if(a < traits::exponent) return FP_NORMAL;
231 a &= traits::significand;
232 traits::set_bits(x,a);
233 if(x == 0) return FP_INFINITE;
238 #if defined(BOOST_MATH_USE_STD_FPCLASSIFY) && defined(BOOST_MATH_NO_NATIVE_LONG_DOUBLE_FP_CLASSIFY)
240 inline int fpclassify_imp<long double> BOOST_NO_MACRO_EXPAND(long double t, const native_tag&)
242 return boost::math::detail::fpclassify_imp(t, generic_tag<true>());
246 } // namespace detail
249 inline int fpclassify BOOST_NO_MACRO_EXPAND(T t)
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());
258 return detail::fpclassify_imp(t, method());
264 #ifdef BOOST_MATH_USE_STD_FPCLASSIFY
266 inline bool isfinite_impl(T x, native_tag const&)
268 return (std::isfinite)(x);
273 inline bool isfinite_impl(T x, generic_tag<true> const&)
275 return x >= -(std::numeric_limits<T>::max)()
276 && x <= (std::numeric_limits<T>::max)();
280 inline bool isfinite_impl(T x, generic_tag<false> const&)
282 #ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
283 if(std::numeric_limits<T>::is_specialized)
284 return isfinite_impl(x, mpl::true_());
286 (void)x; // warning supression.
291 inline bool isfinite_impl(T x, ieee_tag const&)
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;
300 #if defined(BOOST_MATH_USE_STD_FPCLASSIFY) && defined(BOOST_MATH_NO_NATIVE_LONG_DOUBLE_FP_CLASSIFY)
302 inline bool isfinite_impl<long double> BOOST_NO_MACRO_EXPAND(long double t, const native_tag&)
304 return boost::math::detail::isfinite_impl(t, generic_tag<true>());
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());
319 //------------------------------------------------------------------------------
323 #ifdef BOOST_MATH_USE_STD_FPCLASSIFY
325 inline bool isnormal_impl(T x, native_tag const&)
327 return (std::isnormal)(x);
332 inline bool isnormal_impl(T x, generic_tag<true> const&)
335 return x >= (std::numeric_limits<T>::min)()
336 && x <= (std::numeric_limits<T>::max)();
340 inline bool isnormal_impl(T x, generic_tag<false> const&)
342 #ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
343 if(std::numeric_limits<T>::is_specialized)
344 return isnormal_impl(x, mpl::true_());
350 inline bool isnormal_impl(T x, ieee_tag const&)
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);
359 #if defined(BOOST_MATH_USE_STD_FPCLASSIFY) && defined(BOOST_MATH_NO_NATIVE_LONG_DOUBLE_FP_CLASSIFY)
361 inline bool isnormal_impl<long double> BOOST_NO_MACRO_EXPAND(long double t, const native_tag&)
363 return boost::math::detail::isnormal_impl(t, generic_tag<true>());
370 inline bool (isnormal)(T x)
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());
378 //------------------------------------------------------------------------------
382 #ifdef BOOST_MATH_USE_STD_FPCLASSIFY
384 inline bool isinf_impl(T x, native_tag const&)
386 return (std::isinf)(x);
391 inline bool isinf_impl(T x, generic_tag<true> const&)
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());
400 inline bool isinf_impl(T x, generic_tag<false> const&)
402 #ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
403 if(std::numeric_limits<T>::is_specialized)
404 return isinf_impl(x, mpl::true_());
406 (void)x; // warning supression.
411 inline bool isinf_impl(T x, ieee_copy_all_bits_tag const&)
413 typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
415 BOOST_DEDUCED_TYPENAME traits::bits a;
416 traits::get_bits(x,a);
417 a &= traits::exponent | traits::significand;
418 return a == traits::exponent;
422 inline bool isinf_impl(T x, ieee_copy_leading_bits_tag const&)
424 typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
426 BOOST_DEDUCED_TYPENAME traits::bits a;
427 traits::get_bits(x,a);
428 a &= traits::exponent | traits::significand;
429 if(a != traits::exponent)
432 traits::set_bits(x,0);
436 #if defined(BOOST_MATH_USE_STD_FPCLASSIFY) && defined(BOOST_MATH_NO_NATIVE_LONG_DOUBLE_FP_CLASSIFY)
438 inline bool isinf_impl<long double> BOOST_NO_MACRO_EXPAND(long double t, const native_tag&)
440 return boost::math::detail::isinf_impl(t, generic_tag<true>());
444 } // namespace detail
447 inline bool (isinf)(T x)
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());
455 //------------------------------------------------------------------------------
459 #ifdef BOOST_MATH_USE_STD_FPCLASSIFY
461 inline bool isnan_impl(T x, native_tag const&)
463 return (std::isnan)(x);
468 inline bool isnan_impl(T x, generic_tag<true> const&)
470 return std::numeric_limits<T>::has_infinity
471 ? !(x <= std::numeric_limits<T>::infinity())
476 inline bool isnan_impl(T x, generic_tag<false> const&)
478 #ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
479 if(std::numeric_limits<T>::is_specialized)
480 return isnan_impl(x, mpl::true_());
482 (void)x; // warning supression
487 inline bool isnan_impl(T x, ieee_copy_all_bits_tag const&)
489 typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
491 BOOST_DEDUCED_TYPENAME traits::bits a;
492 traits::get_bits(x,a);
493 a &= traits::exponent | traits::significand;
494 return a > traits::exponent;
498 inline bool isnan_impl(T x, ieee_copy_leading_bits_tag const&)
500 typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
502 BOOST_DEDUCED_TYPENAME traits::bits a;
503 traits::get_bits(x,a);
505 a &= traits::exponent | traits::significand;
506 if(a < traits::exponent)
509 a &= traits::significand;
510 traits::set_bits(x,a);
514 } // namespace detail
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());
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()); }
533 #endif // BOOST_MATH_FPCLASSIFY_HPP