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>
24
1. If the platform is C99 compliant, then the native floating point
25
classification functions are used. However, note that we must only
26
define the functions which call std::fpclassify etc if that function
27
really does exist: otherwise a compiler may reject the code even though
28
the template is never instantiated.
30
2. If the platform is not C99 compliant, and the binary format for
31
a floating point type (float, double or long double) can be determined
32
at compile time, then the following algorithm is used:
34
If all exponent bits, the flag bit (if there is one),
35
and all significand bits are 0, then the number is zero.
37
If all exponent bits and the flag bit (if there is one) are 0,
38
and at least one significand bit is 1, then the number is subnormal.
40
If all exponent bits are 1 and all significand bits are 0,
41
then the number is infinity.
43
If all exponent bits are 1 and at least one significand bit is 1,
44
then the number is a not-a-number.
46
Otherwise the number is normal.
48
This algorithm works for the IEEE 754 representation,
49
and also for several non IEEE 754 formats.
51
Most formats have the structure
52
sign bit + exponent bits + significand bits.
54
A few have the structure
55
sign bit + exponent bits + flag bit + significand bits.
56
The flag bit is 0 for zero and subnormal numbers,
57
and 1 for normal numbers and NaN.
58
It is 0 (Motorola 68K) or 1 (Intel) for infinity.
60
To get the bits, the four or eight most significant bytes are copied
61
into an uint32_t or uint64_t and bit masks are applied.
62
This covers all the exponent bits and the flag bit (if there is one),
63
but not always all the significand bits.
64
Some of the functions below have two implementations,
65
depending on whether all the significand bits are copied or not.
67
3. If the platform is not C99 compliant, and the binary format for
68
a floating point type (float, double or long double) can not be determined
69
at compile time, then comparison with std::numeric_limits values
74
#if defined(_MSC_VER) || defined(__BORLANDC__)
78
#ifdef BOOST_NO_STDC_NAMESPACE
79
namespace std{ using ::abs; using ::fabs; }
84
#if defined(BOOST_HAS_FPCLASSIFY) || defined(isnan)
86
// This must not be located in any namespace under boost::math
87
// otherwise we can get into an infinite loop if isnan is
88
// a #define for "isnan" !
90
namespace math_detail{
93
inline bool is_nan_helper(T t, const boost::true_type&)
97
#else // BOOST_HAS_FPCLASSIFY
98
return (BOOST_FPCLASSIFY_PREFIX fpclassify(t) == (int)FP_NAN);
103
inline bool is_nan_helper(T t, const boost::false_type&)
110
#endif // defined(BOOST_HAS_FPCLASSIFY) || defined(isnan)
116
#ifdef BOOST_MATH_USE_STD_FPCLASSIFY
118
inline int fpclassify_imp BOOST_NO_MACRO_EXPAND(T t, const native_tag&)
120
return (std::fpclassify)(t);
125
inline int fpclassify_imp BOOST_NO_MACRO_EXPAND(T t, const generic_tag<true>&)
127
BOOST_MATH_INSTRUMENT_VARIABLE(t);
129
// whenever possible check for Nan's first:
130
#ifdef BOOST_HAS_FPCLASSIFY
131
if(::boost::math_detail::is_nan_helper(t, ::boost::is_floating_point<T>()))
134
if(boost::math_detail::is_nan_helper(t, ::boost::is_floating_point<T>()))
136
#elif defined(_MSC_VER) || defined(__BORLANDC__)
137
if(::_isnan(boost::math::tools::real_cast<double>(t)))
140
// std::fabs broken on a few systems especially for long long!!!!
141
T at = (t < T(0)) ? -t : t;
143
// Use a process of exclusion to figure out
144
// what kind of type we have, this relies on
145
// IEEE conforming reals that will treat
146
// Nan's as unordered. Some compilers
147
// don't do this once optimisations are
148
// turned on, hence the check for nan's above.
149
if(at <= (std::numeric_limits<T>::max)())
151
if(at >= (std::numeric_limits<T>::min)())
153
return (at != 0) ? FP_SUBNORMAL : FP_ZERO;
155
else if(at > (std::numeric_limits<T>::max)())
161
inline int fpclassify_imp BOOST_NO_MACRO_EXPAND(T t, const generic_tag<false>&)
163
#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
164
if(std::numeric_limits<T>::is_specialized)
165
return fp_classify_imp(t, mpl::true_());
168
// An unknown type with no numeric_limits support,
169
// so what are we supposed to do we do here?
171
BOOST_MATH_INSTRUMENT_VARIABLE(t);
173
return t == 0 ? FP_ZERO : FP_NORMAL;
177
int fpclassify_imp BOOST_NO_MACRO_EXPAND(T x, ieee_copy_all_bits_tag)
179
typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
181
BOOST_MATH_INSTRUMENT_VARIABLE(x);
183
BOOST_DEDUCED_TYPENAME traits::bits a;
184
traits::get_bits(x,a);
185
BOOST_MATH_INSTRUMENT_VARIABLE(a);
186
a &= traits::exponent | traits::flag | traits::significand;
187
BOOST_MATH_INSTRUMENT_VARIABLE((traits::exponent | traits::flag | traits::significand));
188
BOOST_MATH_INSTRUMENT_VARIABLE(a);
190
if(a <= traits::significand) {
197
if(a < traits::exponent) return FP_NORMAL;
199
a &= traits::significand;
200
if(a == 0) return FP_INFINITE;
206
int fpclassify_imp BOOST_NO_MACRO_EXPAND(T x, ieee_copy_leading_bits_tag)
208
typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
210
BOOST_MATH_INSTRUMENT_VARIABLE(x);
212
BOOST_DEDUCED_TYPENAME traits::bits a;
213
traits::get_bits(x,a);
214
a &= traits::exponent | traits::flag | traits::significand;
216
if(a <= traits::significand) {
223
if(a < traits::exponent) return FP_NORMAL;
225
a &= traits::significand;
226
traits::set_bits(x,a);
227
if(x == 0) return FP_INFINITE;
232
#if defined(BOOST_MATH_USE_STD_FPCLASSIFY) && defined(BOOST_MATH_NO_NATIVE_LONG_DOUBLE_FP_CLASSIFY)
234
inline int fpclassify_imp<long double> BOOST_NO_MACRO_EXPAND(long double t, const native_tag&)
236
return boost::math::detail::fpclassify_imp(t, generic_tag<true>());
240
} // namespace detail
243
inline int fpclassify BOOST_NO_MACRO_EXPAND(T t)
245
typedef typename detail::fp_traits<T>::type traits;
246
typedef typename traits::method method;
247
#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
248
if(std::numeric_limits<T>::is_specialized && detail::is_generic_tag_false(method()))
249
return detail::fpclassify_imp(t, detail::generic_tag<true>());
250
return detail::fpclassify_imp(t, method());
252
return detail::fpclassify_imp(t, method());
258
#ifdef BOOST_MATH_USE_STD_FPCLASSIFY
260
inline bool isfinite_impl(T x, native_tag const&)
262
return (std::isfinite)(x);
267
inline bool isfinite_impl(T x, generic_tag<true> const&)
269
return x >= -(std::numeric_limits<T>::max)()
270
&& x <= (std::numeric_limits<T>::max)();
274
inline bool isfinite_impl(T x, generic_tag<false> const&)
276
#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
277
if(std::numeric_limits<T>::is_specialized)
278
return isfinite_impl(x, mpl::true_());
280
(void)x; // warning supression.
285
inline bool isfinite_impl(T x, ieee_tag const&)
287
typedef BOOST_DEDUCED_TYPENAME detail::fp_traits<T>::type traits;
288
BOOST_DEDUCED_TYPENAME traits::bits a;
289
traits::get_bits(x,a);
290
a &= traits::exponent;
291
return a != traits::exponent;
294
#if defined(BOOST_MATH_USE_STD_FPCLASSIFY) && defined(BOOST_MATH_NO_NATIVE_LONG_DOUBLE_FP_CLASSIFY)
296
inline bool isfinite_impl<long double> BOOST_NO_MACRO_EXPAND(long double t, const native_tag&)
298
return boost::math::detail::isfinite_impl(t, generic_tag<true>());
305
inline bool (isfinite)(T x)
307
typedef typename detail::fp_traits<T>::type traits;
308
typedef typename traits::method method;
309
typedef typename boost::is_floating_point<T>::type fp_tag;
310
return detail::isfinite_impl(x, method());
313
//------------------------------------------------------------------------------
317
#ifdef BOOST_MATH_USE_STD_FPCLASSIFY
319
inline bool isnormal_impl(T x, native_tag const&)
321
return (std::isnormal)(x);
326
inline bool isnormal_impl(T x, generic_tag<true> const&)
329
return x >= (std::numeric_limits<T>::min)()
330
&& x <= (std::numeric_limits<T>::max)();
334
inline bool isnormal_impl(T x, generic_tag<false> const&)
336
#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
337
if(std::numeric_limits<T>::is_specialized)
338
return isnormal_impl(x, mpl::true_());
344
inline bool isnormal_impl(T x, ieee_tag const&)
346
typedef BOOST_DEDUCED_TYPENAME detail::fp_traits<T>::type traits;
347
BOOST_DEDUCED_TYPENAME traits::bits a;
348
traits::get_bits(x,a);
349
a &= traits::exponent | traits::flag;
350
return (a != 0) && (a < traits::exponent);
353
#if defined(BOOST_MATH_USE_STD_FPCLASSIFY) && defined(BOOST_MATH_NO_NATIVE_LONG_DOUBLE_FP_CLASSIFY)
355
inline bool isnormal_impl<long double> BOOST_NO_MACRO_EXPAND(long double t, const native_tag&)
357
return boost::math::detail::isnormal_impl(t, generic_tag<true>());
364
inline bool (isnormal)(T x)
366
typedef typename detail::fp_traits<T>::type traits;
367
typedef typename traits::method method;
368
typedef typename boost::is_floating_point<T>::type fp_tag;
369
return detail::isnormal_impl(x, method());
372
//------------------------------------------------------------------------------
376
#ifdef BOOST_MATH_USE_STD_FPCLASSIFY
378
inline bool isinf_impl(T x, native_tag const&)
380
return (std::isinf)(x);
385
inline bool isinf_impl(T x, generic_tag<true> const&)
387
return std::numeric_limits<T>::has_infinity
388
&& ( x == std::numeric_limits<T>::infinity()
389
|| x == -std::numeric_limits<T>::infinity());
393
inline bool isinf_impl(T x, generic_tag<false> const&)
395
#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
396
if(std::numeric_limits<T>::is_specialized)
397
return isinf_impl(x, mpl::true_());
399
(void)x; // warning supression.
404
inline bool isinf_impl(T x, ieee_copy_all_bits_tag const&)
406
typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
408
BOOST_DEDUCED_TYPENAME traits::bits a;
409
traits::get_bits(x,a);
410
a &= traits::exponent | traits::significand;
411
return a == traits::exponent;
415
inline bool isinf_impl(T x, ieee_copy_leading_bits_tag const&)
417
typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
419
BOOST_DEDUCED_TYPENAME traits::bits a;
420
traits::get_bits(x,a);
421
a &= traits::exponent | traits::significand;
422
if(a != traits::exponent)
425
traits::set_bits(x,0);
429
#if defined(BOOST_MATH_USE_STD_FPCLASSIFY) && defined(BOOST_MATH_NO_NATIVE_LONG_DOUBLE_FP_CLASSIFY)
431
inline bool isinf_impl<long double> BOOST_NO_MACRO_EXPAND(long double t, const native_tag&)
433
return boost::math::detail::isinf_impl(t, generic_tag<true>());
437
} // namespace detail
440
inline bool (isinf)(T x)
442
typedef typename detail::fp_traits<T>::type traits;
443
typedef typename traits::method method;
444
typedef typename boost::is_floating_point<T>::type fp_tag;
445
return detail::isinf_impl(x, method());
448
//------------------------------------------------------------------------------
452
#ifdef BOOST_MATH_USE_STD_FPCLASSIFY
454
inline bool isnan_impl(T x, native_tag const&)
456
return (std::isnan)(x);
461
inline bool isnan_impl(T x, generic_tag<true> const&)
463
return std::numeric_limits<T>::has_infinity
464
? !(x <= std::numeric_limits<T>::infinity())
469
inline bool isnan_impl(T x, generic_tag<false> const&)
471
#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
472
if(std::numeric_limits<T>::is_specialized)
473
return isnan_impl(x, mpl::true_());
475
(void)x; // warning supression
480
inline bool isnan_impl(T x, ieee_copy_all_bits_tag const&)
482
typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
484
BOOST_DEDUCED_TYPENAME traits::bits a;
485
traits::get_bits(x,a);
486
a &= traits::exponent | traits::significand;
487
return a > traits::exponent;
491
inline bool isnan_impl(T x, ieee_copy_leading_bits_tag const&)
493
typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
495
BOOST_DEDUCED_TYPENAME traits::bits a;
496
traits::get_bits(x,a);
498
a &= traits::exponent | traits::significand;
499
if(a < traits::exponent)
502
a &= traits::significand;
503
traits::set_bits(x,a);
507
} // namespace detail
509
template<class T> bool (isnan)(T x)
511
typedef typename detail::fp_traits<T>::type traits;
512
typedef typename traits::method method;
513
typedef typename boost::is_floating_point<T>::type fp_tag;
514
return detail::isnan_impl(x, method());
518
template <> inline bool isnan BOOST_NO_MACRO_EXPAND<float>(float t){ return ::boost::math_detail::is_nan_helper(t, boost::true_type()); }
519
template <> inline bool isnan BOOST_NO_MACRO_EXPAND<double>(double t){ return ::boost::math_detail::is_nan_helper(t, boost::true_type()); }
520
template <> inline bool isnan BOOST_NO_MACRO_EXPAND<long double>(long double t){ return ::boost::math_detail::is_nan_helper(t, boost::true_type()); }
526
#endif // BOOST_MATH_FPCLASSIFY_HPP