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 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
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