]> git.lyx.org Git - features.git/blob - boost/boost/math/special_functions/fpclassify.hpp
190b73ff4470bcb6a07a79598a60ab2121af40d0
[features.git] / boost / boost / math / special_functions / fpclassify.hpp
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)
6
7 #ifndef BOOST_MATH_FPCLASSIFY_HPP
8 #define BOOST_MATH_FPCLASSIFY_HPP
9
10 #ifdef _MSC_VER
11 #pragma once
12 #endif
13
14 #include <math.h>
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>
21 /*!
22   \file fpclassify.hpp
23   \brief Classify floating-point value as normal, subnormal, zero, infinite, or NaN.
24   \version 1.0
25   \author John Maddock
26  */
27
28 /*
29
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.
35
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:
39
40         If all exponent bits, the flag bit (if there is one), 
41         and all significand bits are 0, then the number is zero.
42
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.
45
46         If all exponent bits are 1 and all significand bits are 0, 
47         then the number is infinity.
48
49         If all exponent bits are 1 and at least one significand bit is 1,
50         then the number is a not-a-number.
51
52         Otherwise the number is normal.
53
54         This algorithm works for the IEEE 754 representation,
55         and also for several non IEEE 754 formats.
56
57     Most formats have the structure
58         sign bit + exponent bits + significand bits.
59     
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.
65
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.
72
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
76 is used.
77
78 */
79
80 #if defined(_MSC_VER) || defined(__BORLANDC__)
81 #include <float.h>
82 #endif
83
84 #ifdef BOOST_NO_STDC_NAMESPACE
85   namespace std{ using ::abs; using ::fabs; }
86 #endif
87
88 namespace boost{ 
89
90 //
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" !
94 //
95 namespace math_detail{
96
97 template <class T>
98 inline bool is_nan_helper(T t, const boost::true_type&)
99 {
100 #ifdef isnan
101    return isnan(t);
102 #elif defined(BOOST_MATH_DISABLE_STD_FPCLASSIFY) || !defined(BOOST_HAS_FPCLASSIFY)
103    return false;
104 #else // BOOST_HAS_FPCLASSIFY
105    return (BOOST_FPCLASSIFY_PREFIX fpclassify(t) == (int)FP_NAN);
106 #endif
107 }
108
109 template <class T>
110 inline bool is_nan_helper(T, const boost::false_type&)
111 {
112    return false;
113 }
114
115 }
116
117 namespace math{
118
119 namespace detail{
120
121 #ifdef BOOST_MATH_USE_STD_FPCLASSIFY
122 template <class T>
123 inline int fpclassify_imp BOOST_NO_MACRO_EXPAND(T t, const native_tag&)
124 {
125    return (std::fpclassify)(t);
126 }
127 #endif
128
129 template <class T>
130 inline int fpclassify_imp BOOST_NO_MACRO_EXPAND(T t, const generic_tag<true>&)
131 {
132    BOOST_MATH_INSTRUMENT_VARIABLE(t);
133
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>()))
137       return FP_NAN;
138 #elif defined(isnan)
139    if(boost::math_detail::is_nan_helper(t, ::boost::is_floating_point<T>()))
140       return FP_NAN;
141 #elif defined(_MSC_VER) || defined(__BORLANDC__)
142    if(::_isnan(boost::math::tools::real_cast<double>(t)))
143       return FP_NAN;
144 #endif
145    // std::fabs broken on a few systems especially for long long!!!!
146    T at = (t < T(0)) ? -t : t;
147
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)())
155    {
156       if(at >= (std::numeric_limits<T>::min)())
157          return FP_NORMAL;
158       return (at != 0) ? FP_SUBNORMAL : FP_ZERO;
159    }
160    else if(at > (std::numeric_limits<T>::max)())
161       return FP_INFINITE;
162    return FP_NAN;
163 }
164
165 template <class T>
166 inline int fpclassify_imp BOOST_NO_MACRO_EXPAND(T t, const generic_tag<false>&)
167 {
168 #ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
169    if(std::numeric_limits<T>::is_specialized)
170       return fp_classify_imp(t, mpl::true_());
171 #endif
172    // 
173    // An unknown type with no numeric_limits support,
174    // so what are we supposed to do we do here?
175    //
176    BOOST_MATH_INSTRUMENT_VARIABLE(t);
177
178    return t == 0 ? FP_ZERO : FP_NORMAL;
179 }
180
181 template<class T> 
182 int fpclassify_imp BOOST_NO_MACRO_EXPAND(T x, ieee_copy_all_bits_tag)
183 {
184    typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
185
186    BOOST_MATH_INSTRUMENT_VARIABLE(x);
187
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);
194
195    if(a <= traits::significand) {
196       if(a == 0)
197          return FP_ZERO;
198       else
199          return FP_SUBNORMAL;
200    }
201
202    if(a < traits::exponent) return FP_NORMAL;
203
204    a &= traits::significand;
205    if(a == 0) return FP_INFINITE;
206
207    return FP_NAN;
208 }
209
210 template<class T> 
211 int fpclassify_imp BOOST_NO_MACRO_EXPAND(T x, ieee_copy_leading_bits_tag)
212 {
213    typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
214
215    BOOST_MATH_INSTRUMENT_VARIABLE(x);
216
217    BOOST_DEDUCED_TYPENAME traits::bits a;
218    traits::get_bits(x,a); 
219    a &= traits::exponent | traits::flag | traits::significand;
220
221    if(a <= traits::significand) {
222       if(x == 0)
223          return FP_ZERO;
224       else
225          return FP_SUBNORMAL;
226    }
227
228    if(a < traits::exponent) return FP_NORMAL;
229
230    a &= traits::significand;
231    traits::set_bits(x,a);
232    if(x == 0) return FP_INFINITE;
233
234    return FP_NAN;
235 }
236
237 #if defined(BOOST_MATH_USE_STD_FPCLASSIFY) && defined(BOOST_MATH_NO_NATIVE_LONG_DOUBLE_FP_CLASSIFY)
238 template <>
239 inline int fpclassify_imp<long double> BOOST_NO_MACRO_EXPAND(long double t, const native_tag&)
240 {
241    return boost::math::detail::fpclassify_imp(t, generic_tag<true>());
242 }
243 #endif
244
245 }  // namespace detail
246
247 template <class T>
248 inline int fpclassify BOOST_NO_MACRO_EXPAND(T t)
249 {
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());
256 #else
257    return detail::fpclassify_imp(t, method());
258 #endif
259 }
260
261 namespace detail {
262
263 #ifdef BOOST_MATH_USE_STD_FPCLASSIFY
264     template<class T> 
265     inline bool isfinite_impl(T x, native_tag const&)
266     {
267         return (std::isfinite)(x);
268     }
269 #endif
270
271     template<class T> 
272     inline bool isfinite_impl(T x, generic_tag<true> const&)
273     {
274         return x >= -(std::numeric_limits<T>::max)()
275             && x <= (std::numeric_limits<T>::max)();
276     }
277
278     template<class T> 
279     inline bool isfinite_impl(T x, generic_tag<false> const&)
280     {
281 #ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
282       if(std::numeric_limits<T>::is_specialized)
283          return isfinite_impl(x, mpl::true_());
284 #endif
285        (void)x; // warning supression.
286        return true;
287     }
288
289     template<class T> 
290     inline bool isfinite_impl(T x, ieee_tag const&)
291     {
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;
297     }
298
299 #if defined(BOOST_MATH_USE_STD_FPCLASSIFY) && defined(BOOST_MATH_NO_NATIVE_LONG_DOUBLE_FP_CLASSIFY)
300 template <>
301 inline bool isfinite_impl<long double> BOOST_NO_MACRO_EXPAND(long double t, const native_tag&)
302 {
303    return boost::math::detail::isfinite_impl(t, generic_tag<true>());
304 }
305 #endif
306
307 }
308
309 template<class T> 
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());
316 }
317
318 //------------------------------------------------------------------------------
319
320 namespace detail {
321
322 #ifdef BOOST_MATH_USE_STD_FPCLASSIFY
323     template<class T> 
324     inline bool isnormal_impl(T x, native_tag const&)
325     {
326         return (std::isnormal)(x);
327     }
328 #endif
329
330     template<class T> 
331     inline bool isnormal_impl(T x, generic_tag<true> const&)
332     {
333         if(x < 0) x = -x;
334         return x >= (std::numeric_limits<T>::min)()
335             && x <= (std::numeric_limits<T>::max)();
336     }
337
338     template<class T> 
339     inline bool isnormal_impl(T x, generic_tag<false> const&)
340     {
341 #ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
342       if(std::numeric_limits<T>::is_specialized)
343          return isnormal_impl(x, mpl::true_());
344 #endif
345        return !(x == 0);
346     }
347
348     template<class T> 
349     inline bool isnormal_impl(T x, ieee_tag const&)
350     {
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);
356     }
357
358 #if defined(BOOST_MATH_USE_STD_FPCLASSIFY) && defined(BOOST_MATH_NO_NATIVE_LONG_DOUBLE_FP_CLASSIFY)
359 template <>
360 inline bool isnormal_impl<long double> BOOST_NO_MACRO_EXPAND(long double t, const native_tag&)
361 {
362    return boost::math::detail::isnormal_impl(t, generic_tag<true>());
363 }
364 #endif
365
366 }
367
368 template<class T> 
369 inline bool (isnormal)(T x)
370 {
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());
375 }
376
377 //------------------------------------------------------------------------------
378
379 namespace detail {
380
381 #ifdef BOOST_MATH_USE_STD_FPCLASSIFY
382     template<class T> 
383     inline bool isinf_impl(T x, native_tag const&)
384     {
385         return (std::isinf)(x);
386     }
387 #endif
388
389     template<class T> 
390     inline bool isinf_impl(T x, generic_tag<true> const&)
391     {
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());
396     }
397
398     template<class T> 
399     inline bool isinf_impl(T x, generic_tag<false> const&)
400     {
401 #ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
402       if(std::numeric_limits<T>::is_specialized)
403          return isinf_impl(x, mpl::true_());
404 #endif
405         (void)x; // warning supression.
406         return false;
407     }
408
409     template<class T> 
410     inline bool isinf_impl(T x, ieee_copy_all_bits_tag const&)
411     {
412         typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
413
414         BOOST_DEDUCED_TYPENAME traits::bits a;
415         traits::get_bits(x,a);
416         a &= traits::exponent | traits::significand;
417         return a == traits::exponent;
418     }
419
420     template<class T> 
421     inline bool isinf_impl(T x, ieee_copy_leading_bits_tag const&)
422     {
423         typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
424
425         BOOST_DEDUCED_TYPENAME traits::bits a;
426         traits::get_bits(x,a);
427         a &= traits::exponent | traits::significand;
428         if(a != traits::exponent)
429             return false;
430
431         traits::set_bits(x,0);
432         return x == 0;
433     }
434
435 #if defined(BOOST_MATH_USE_STD_FPCLASSIFY) && defined(BOOST_MATH_NO_NATIVE_LONG_DOUBLE_FP_CLASSIFY)
436 template <>
437 inline bool isinf_impl<long double> BOOST_NO_MACRO_EXPAND(long double t, const native_tag&)
438 {
439    return boost::math::detail::isinf_impl(t, generic_tag<true>());
440 }
441 #endif
442
443 }   // namespace detail
444
445 template<class T> 
446 inline bool (isinf)(T x)
447 {
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());
452 }
453
454 //------------------------------------------------------------------------------
455
456 namespace detail {
457
458 #ifdef BOOST_MATH_USE_STD_FPCLASSIFY
459     template<class T> 
460     inline bool isnan_impl(T x, native_tag const&)
461     {
462         return (std::isnan)(x);
463     }
464 #endif
465
466     template<class T> 
467     inline bool isnan_impl(T x, generic_tag<true> const&)
468     {
469         return std::numeric_limits<T>::has_infinity
470             ? !(x <= std::numeric_limits<T>::infinity())
471             : x != x;
472     }
473
474     template<class T> 
475     inline bool isnan_impl(T x, generic_tag<false> const&)
476     {
477 #ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
478       if(std::numeric_limits<T>::is_specialized)
479          return isnan_impl(x, mpl::true_());
480 #endif
481         (void)x; // warning supression
482         return false;
483     }
484
485     template<class T> 
486     inline bool isnan_impl(T x, ieee_copy_all_bits_tag const&)
487     {
488         typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
489
490         BOOST_DEDUCED_TYPENAME traits::bits a;
491         traits::get_bits(x,a);
492         a &= traits::exponent | traits::significand;
493         return a > traits::exponent;
494     }
495
496     template<class T> 
497     inline bool isnan_impl(T x, ieee_copy_leading_bits_tag const&)
498     {
499         typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
500
501         BOOST_DEDUCED_TYPENAME traits::bits a;
502         traits::get_bits(x,a);
503
504         a &= traits::exponent | traits::significand;
505         if(a < traits::exponent)
506             return false;
507
508         a &= traits::significand;
509         traits::set_bits(x,a);
510         return x != 0;
511     }
512
513 }   // namespace detail
514
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());
521 }
522
523 #ifdef isnan
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()); }
527 #endif
528
529 } // namespace math
530 } // namespace boost
531
532 #endif // BOOST_MATH_FPCLASSIFY_HPP
533