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
301. If the platform is C99 compliant, then the native floating point
31classification functions are used. However, note that we must only
32define the functions which call std::fpclassify etc if that function
33really does exist: otherwise a compiler may reject the code even though
34the template is never instantiated.
35
362. If the platform is not C99 compliant, and the binary format for
37a floating point type (float, double or long double) can be determined
38at 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
733. If the platform is not C99 compliant, and the binary format for
74a floating point type (float, double or long double) can not be determined
75at compile time, then comparison with std::numeric_limits values
76is used.
77
78*/
79
80#if defined(_MSC_VER) || defined(__BORLANDC__)
81#include <float.h>
82#endif
83#ifdef BOOST_MATH_USE_FLOAT128
84#ifdef __has_include
85#if __has_include("quadmath.h")
86#include "quadmath.h"
87#define BOOST_MATH_HAS_QUADMATH_H
88#endif
89#endif
90#endif
91
92#ifdef BOOST_NO_STDC_NAMESPACE
93 namespace std{ using ::abs; using ::fabs; }
94#endif
95
96namespace boost{
97
98//
99// This must not be located in any namespace under boost::math
100// otherwise we can get into an infinite loop if isnan is
101// a #define for "isnan" !
102//
103namespace math_detail{
104
105#ifdef BOOST_MSVC
106#pragma warning(push)
107#pragma warning(disable:4800)
108#endif
109
110template <class T>
111inline bool is_nan_helper(T t, const boost::true_type&)
112{
113#ifdef isnan
114 return isnan(t);
115#elif defined(BOOST_MATH_DISABLE_STD_FPCLASSIFY) || !defined(BOOST_HAS_FPCLASSIFY)
116 (void)t;
117 return false;
118#else // BOOST_HAS_FPCLASSIFY
119 return (BOOST_FPCLASSIFY_PREFIX fpclassify(t) == (int)FP_NAN);
120#endif
121}
122
123#ifdef BOOST_MSVC
124#pragma warning(pop)
125#endif
126
127template <class T>
128inline bool is_nan_helper(T, const boost::false_type&)
129{
130 return false;
131}
132#if defined(BOOST_MATH_USE_FLOAT128)
133#if defined(BOOST_MATH_HAS_QUADMATH_H)
134inline bool is_nan_helper(__float128 f, const boost::true_type&) { return ::isnanq(f); }
135inline bool is_nan_helper(__float128 f, const boost::false_type&) { return ::isnanq(f); }
136#elif defined(BOOST_GNU_STDLIB) && BOOST_GNU_STDLIB && \
137 _GLIBCXX_USE_C99_MATH && !_GLIBCXX_USE_C99_FP_MACROS_DYNAMIC
138inline bool is_nan_helper(__float128 f, const boost::true_type&) { return std::isnan(static_cast<double>(f)); }
139inline bool is_nan_helper(__float128 f, const boost::false_type&) { return std::isnan(static_cast<double>(f)); }
140#else
141inline bool is_nan_helper(__float128 f, const boost::true_type&) { return ::isnan(static_cast<double>(f)); }
142inline bool is_nan_helper(__float128 f, const boost::false_type&) { return ::isnan(static_cast<double>(f)); }
143#endif
144#endif
145}
146
147namespace math{
148
149namespace detail{
150
151#ifdef BOOST_MATH_USE_STD_FPCLASSIFY
152template <class T>
153inline int fpclassify_imp BOOST_NO_MACRO_EXPAND(T t, const native_tag&)
154{
155 return (std::fpclassify)(t);
156}
157#endif
158
159template <class T>
160inline int fpclassify_imp BOOST_NO_MACRO_EXPAND(T t, const generic_tag<true>&)
161{
162 BOOST_MATH_INSTRUMENT_VARIABLE(t);
163
164 // whenever possible check for Nan's first:
165#if defined(BOOST_HAS_FPCLASSIFY) && !defined(BOOST_MATH_DISABLE_STD_FPCLASSIFY)
166 if(::boost::math_detail::is_nan_helper(t, ::boost::is_floating_point<T>()))
167 return FP_NAN;
168#elif defined(isnan)
169 if(boost::math_detail::is_nan_helper(t, ::boost::is_floating_point<T>()))
170 return FP_NAN;
171#elif defined(_MSC_VER) || defined(__BORLANDC__)
172 if(::_isnan(boost::math::tools::real_cast<double>(t)))
173 return FP_NAN;
174#endif
175 // std::fabs broken on a few systems especially for long long!!!!
176 T at = (t < T(0)) ? -t : t;
177
178 // Use a process of exclusion to figure out
179 // what kind of type we have, this relies on
180 // IEEE conforming reals that will treat
181 // Nan's as unordered. Some compilers
182 // don't do this once optimisations are
183 // turned on, hence the check for nan's above.
184 if(at <= (std::numeric_limits<T>::max)())
185 {
186 if(at >= (std::numeric_limits<T>::min)())
187 return FP_NORMAL;
188 return (at != 0) ? FP_SUBNORMAL : FP_ZERO;
189 }
190 else if(at > (std::numeric_limits<T>::max)())
191 return FP_INFINITE;
192 return FP_NAN;
193}
194
195template <class T>
196inline int fpclassify_imp BOOST_NO_MACRO_EXPAND(T t, const generic_tag<false>&)
197{
198#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
199 if(std::numeric_limits<T>::is_specialized)
200 return fpclassify_imp(t, generic_tag<true>());
201#endif
202 //
203 // An unknown type with no numeric_limits support,
204 // so what are we supposed to do we do here?
205 //
206 BOOST_MATH_INSTRUMENT_VARIABLE(t);
207
208 return t == 0 ? FP_ZERO : FP_NORMAL;
209}
210
211template<class T>
212int fpclassify_imp BOOST_NO_MACRO_EXPAND(T x, ieee_copy_all_bits_tag)
213{
214 typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
215
216 BOOST_MATH_INSTRUMENT_VARIABLE(x);
217
218 BOOST_DEDUCED_TYPENAME traits::bits a;
219 traits::get_bits(x,a);
220 BOOST_MATH_INSTRUMENT_VARIABLE(a);
221 a &= traits::exponent | traits::flag | traits::significand;
222 BOOST_MATH_INSTRUMENT_VARIABLE((traits::exponent | traits::flag | traits::significand));
223 BOOST_MATH_INSTRUMENT_VARIABLE(a);
224
225 if(a <= traits::significand) {
226 if(a == 0)
227 return FP_ZERO;
228 else
229 return FP_SUBNORMAL;
230 }
231
232 if(a < traits::exponent) return FP_NORMAL;
233
234 a &= traits::significand;
235 if(a == 0) return FP_INFINITE;
236
237 return FP_NAN;
238}
239
240template<class T>
241int fpclassify_imp BOOST_NO_MACRO_EXPAND(T x, ieee_copy_leading_bits_tag)
242{
243 typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
244
245 BOOST_MATH_INSTRUMENT_VARIABLE(x);
246
247 BOOST_DEDUCED_TYPENAME traits::bits a;
248 traits::get_bits(x,a);
249 a &= traits::exponent | traits::flag | traits::significand;
250
251 if(a <= traits::significand) {
252 if(x == 0)
253 return FP_ZERO;
254 else
255 return FP_SUBNORMAL;
256 }
257
258 if(a < traits::exponent) return FP_NORMAL;
259
260 a &= traits::significand;
261 traits::set_bits(x,a);
262 if(x == 0) return FP_INFINITE;
263
264 return FP_NAN;
265}
266
267#if defined(BOOST_MATH_USE_STD_FPCLASSIFY) && (defined(BOOST_MATH_NO_NATIVE_LONG_DOUBLE_FP_CLASSIFY) || defined(BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS))
268inline int fpclassify_imp BOOST_NO_MACRO_EXPAND(long double t, const native_tag&)
269{
270 return boost::math::detail::fpclassify_imp(t, generic_tag<true>());
271}
272#endif
273
274} // namespace detail
275
276template <class T>
277inline int fpclassify BOOST_NO_MACRO_EXPAND(T t)
278{
279 typedef typename detail::fp_traits<T>::type traits;
280 typedef typename traits::method method;
281 typedef typename tools::promote_args_permissive<T>::type value_type;
282#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
283 if(std::numeric_limits<T>::is_specialized && detail::is_generic_tag_false(static_cast<method*>(0)))
284 return detail::fpclassify_imp(static_cast<value_type>(t), detail::generic_tag<true>());
285 return detail::fpclassify_imp(static_cast<value_type>(t), method());
286#else
287 return detail::fpclassify_imp(static_cast<value_type>(t), method());
288#endif
289}
290
291#ifdef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
292template <>
293inline int fpclassify<long double> BOOST_NO_MACRO_EXPAND(long double t)
294{
295 typedef detail::fp_traits<long double>::type traits;
296 typedef traits::method method;
297 typedef long double value_type;
298#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
299 if(std::numeric_limits<long double>::is_specialized && detail::is_generic_tag_false(static_cast<method*>(0)))
300 return detail::fpclassify_imp(static_cast<value_type>(t), detail::generic_tag<true>());
301 return detail::fpclassify_imp(static_cast<value_type>(t), method());
302#else
303 return detail::fpclassify_imp(static_cast<value_type>(t), method());
304#endif
305}
306#endif
307
308namespace detail {
309
310#ifdef BOOST_MATH_USE_STD_FPCLASSIFY
311 template<class T>
312 inline bool isfinite_impl(T x, native_tag const&)
313 {
314 return (std::isfinite)(x);
315 }
316#endif
317
318 template<class T>
319 inline bool isfinite_impl(T x, generic_tag<true> const&)
320 {
321 return x >= -(std::numeric_limits<T>::max)()
322 && x <= (std::numeric_limits<T>::max)();
323 }
324
325 template<class T>
326 inline bool isfinite_impl(T x, generic_tag<false> const&)
327 {
328#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
329 if(std::numeric_limits<T>::is_specialized)
330 return isfinite_impl(x, generic_tag<true>());
331#endif
332 (void)x; // warning suppression.
333 return true;
334 }
335
336 template<class T>
337 inline bool isfinite_impl(T x, ieee_tag const&)
338 {
339 typedef BOOST_DEDUCED_TYPENAME detail::fp_traits<T>::type traits;
340 BOOST_DEDUCED_TYPENAME traits::bits a;
341 traits::get_bits(x,a);
342 a &= traits::exponent;
343 return a != traits::exponent;
344 }
345
346#if defined(BOOST_MATH_USE_STD_FPCLASSIFY) && defined(BOOST_MATH_NO_NATIVE_LONG_DOUBLE_FP_CLASSIFY)
347inline bool isfinite_impl BOOST_NO_MACRO_EXPAND(long double t, const native_tag&)
348{
349 return boost::math::detail::isfinite_impl(t, generic_tag<true>());
350}
351#endif
352
353}
354
355template<class T>
356inline bool (isfinite)(T x)
357{ //!< \brief return true if floating-point type t is finite.
358 typedef typename detail::fp_traits<T>::type traits;
359 typedef typename traits::method method;
360 // typedef typename boost::is_floating_point<T>::type fp_tag;
361 typedef typename tools::promote_args_permissive<T>::type value_type;
362 return detail::isfinite_impl(static_cast<value_type>(x), method());
363}
364
365#ifdef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
366template<>
367inline bool (isfinite)(long double x)
368{ //!< \brief return true if floating-point type t is finite.
369 typedef detail::fp_traits<long double>::type traits;
370 typedef traits::method method;
371 //typedef boost::is_floating_point<long double>::type fp_tag;
372 typedef long double value_type;
373 return detail::isfinite_impl(static_cast<value_type>(x), method());
374}
375#endif
376
377//------------------------------------------------------------------------------
378
379namespace detail {
380
381#ifdef BOOST_MATH_USE_STD_FPCLASSIFY
382 template<class T>
383 inline bool isnormal_impl(T x, native_tag const&)
384 {
385 return (std::isnormal)(x);
386 }
387#endif
388
389 template<class T>
390 inline bool isnormal_impl(T x, generic_tag<true> const&)
391 {
392 if(x < 0) x = -x;
393 return x >= (std::numeric_limits<T>::min)()
394 && x <= (std::numeric_limits<T>::max)();
395 }
396
397 template<class T>
398 inline bool isnormal_impl(T x, generic_tag<false> const&)
399 {
400#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
401 if(std::numeric_limits<T>::is_specialized)
402 return isnormal_impl(x, generic_tag<true>());
403#endif
404 return !(x == 0);
405 }
406
407 template<class T>
408 inline bool isnormal_impl(T x, ieee_tag const&)
409 {
410 typedef BOOST_DEDUCED_TYPENAME detail::fp_traits<T>::type traits;
411 BOOST_DEDUCED_TYPENAME traits::bits a;
412 traits::get_bits(x,a);
413 a &= traits::exponent | traits::flag;
414 return (a != 0) && (a < traits::exponent);
415 }
416
417#if defined(BOOST_MATH_USE_STD_FPCLASSIFY) && defined(BOOST_MATH_NO_NATIVE_LONG_DOUBLE_FP_CLASSIFY)
418inline bool isnormal_impl BOOST_NO_MACRO_EXPAND(long double t, const native_tag&)
419{
420 return boost::math::detail::isnormal_impl(t, generic_tag<true>());
421}
422#endif
423
424}
425
426template<class T>
427inline bool (isnormal)(T x)
428{
429 typedef typename detail::fp_traits<T>::type traits;
430 typedef typename traits::method method;
431 //typedef typename boost::is_floating_point<T>::type fp_tag;
432 typedef typename tools::promote_args_permissive<T>::type value_type;
433 return detail::isnormal_impl(static_cast<value_type>(x), method());
434}
435
436#ifdef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
437template<>
438inline bool (isnormal)(long double x)
439{
440 typedef detail::fp_traits<long double>::type traits;
441 typedef traits::method method;
442 //typedef boost::is_floating_point<long double>::type fp_tag;
443 typedef long double value_type;
444 return detail::isnormal_impl(static_cast<value_type>(x), method());
445}
446#endif
447
448//------------------------------------------------------------------------------
449
450namespace detail {
451
452#ifdef BOOST_MATH_USE_STD_FPCLASSIFY
453 template<class T>
454 inline bool isinf_impl(T x, native_tag const&)
455 {
456 return (std::isinf)(x);
457 }
458#endif
459
460 template<class T>
461 inline bool isinf_impl(T x, generic_tag<true> const&)
462 {
463 (void)x; // in case the compiler thinks that x is unused because std::numeric_limits<T>::has_infinity is false
464 return std::numeric_limits<T>::has_infinity
465 && ( x == std::numeric_limits<T>::infinity()
466 || x == -std::numeric_limits<T>::infinity());
467 }
468
469 template<class T>
470 inline bool isinf_impl(T x, generic_tag<false> const&)
471 {
472#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
473 if(std::numeric_limits<T>::is_specialized)
474 return isinf_impl(x, generic_tag<true>());
475#endif
476 (void)x; // warning suppression.
477 return false;
478 }
479
480 template<class T>
481 inline bool isinf_impl(T x, ieee_copy_all_bits_tag const&)
482 {
483 typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
484
485 BOOST_DEDUCED_TYPENAME traits::bits a;
486 traits::get_bits(x,a);
487 a &= traits::exponent | traits::significand;
488 return a == traits::exponent;
489 }
490
491 template<class T>
492 inline bool isinf_impl(T x, ieee_copy_leading_bits_tag const&)
493 {
494 typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
495
496 BOOST_DEDUCED_TYPENAME traits::bits a;
497 traits::get_bits(x,a);
498 a &= traits::exponent | traits::significand;
499 if(a != traits::exponent)
500 return false;
501
502 traits::set_bits(x,0);
503 return x == 0;
504 }
505
506#if defined(BOOST_MATH_USE_STD_FPCLASSIFY) && defined(BOOST_MATH_NO_NATIVE_LONG_DOUBLE_FP_CLASSIFY)
507inline bool isinf_impl BOOST_NO_MACRO_EXPAND(long double t, const native_tag&)
508{
509 return boost::math::detail::isinf_impl(t, generic_tag<true>());
510}
511#endif
512
513} // namespace detail
514
515template<class T>
516inline bool (isinf)(T x)
517{
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 typedef typename tools::promote_args_permissive<T>::type value_type;
522 return detail::isinf_impl(static_cast<value_type>(x), method());
523}
524
525#ifdef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
526template<>
527inline bool (isinf)(long double x)
528{
529 typedef detail::fp_traits<long double>::type traits;
530 typedef traits::method method;
531 //typedef boost::is_floating_point<long double>::type fp_tag;
532 typedef long double value_type;
533 return detail::isinf_impl(static_cast<value_type>(x), method());
534}
535#endif
536#if defined(BOOST_MATH_USE_FLOAT128) && defined(BOOST_MATH_HAS_QUADMATH_H)
537template<>
538inline bool (isinf)(__float128 x)
539{
540 return ::isinfq(x);
541}
542#endif
543
544//------------------------------------------------------------------------------
545
546namespace detail {
547
548#ifdef BOOST_MATH_USE_STD_FPCLASSIFY
549 template<class T>
550 inline bool isnan_impl(T x, native_tag const&)
551 {
552 return (std::isnan)(x);
553 }
554#endif
555
556 template<class T>
557 inline bool isnan_impl(T x, generic_tag<true> const&)
558 {
559 return std::numeric_limits<T>::has_infinity
560 ? !(x <= std::numeric_limits<T>::infinity())
561 : x != x;
562 }
563
564 template<class T>
565 inline bool isnan_impl(T x, generic_tag<false> const&)
566 {
567#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
568 if(std::numeric_limits<T>::is_specialized)
569 return isnan_impl(x, generic_tag<true>());
570#endif
571 (void)x; // warning suppression
572 return false;
573 }
574
575 template<class T>
576 inline bool isnan_impl(T x, ieee_copy_all_bits_tag const&)
577 {
578 typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
579
580 BOOST_DEDUCED_TYPENAME traits::bits a;
581 traits::get_bits(x,a);
582 a &= traits::exponent | traits::significand;
583 return a > traits::exponent;
584 }
585
586 template<class T>
587 inline bool isnan_impl(T x, ieee_copy_leading_bits_tag const&)
588 {
589 typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
590
591 BOOST_DEDUCED_TYPENAME traits::bits a;
592 traits::get_bits(x,a);
593
594 a &= traits::exponent | traits::significand;
595 if(a < traits::exponent)
596 return false;
597
598 a &= traits::significand;
599 traits::set_bits(x,a);
600 return x != 0;
601 }
602
603} // namespace detail
604
605template<class T>
606inline bool (isnan)(T x)
607{ //!< \brief return true if floating-point type t is NaN (Not A Number).
608 typedef typename detail::fp_traits<T>::type traits;
609 typedef typename traits::method method;
610 // typedef typename boost::is_floating_point<T>::type fp_tag;
611 return detail::isnan_impl(x, method());
612}
613
614#ifdef isnan
615template <> inline bool isnan BOOST_NO_MACRO_EXPAND<float>(float t){ return ::boost::math_detail::is_nan_helper(t, boost::true_type()); }
616template <> inline bool isnan BOOST_NO_MACRO_EXPAND<double>(double t){ return ::boost::math_detail::is_nan_helper(t, boost::true_type()); }
617template <> inline bool isnan BOOST_NO_MACRO_EXPAND<long double>(long double t){ return ::boost::math_detail::is_nan_helper(t, boost::true_type()); }
618#elif defined(BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS)
619template<>
620inline bool (isnan)(long double x)
621{ //!< \brief return true if floating-point type t is NaN (Not A Number).
622 typedef detail::fp_traits<long double>::type traits;
623 typedef traits::method method;
624 //typedef boost::is_floating_point<long double>::type fp_tag;
625 return detail::isnan_impl(x, method());
626}
627#endif
628#if defined(BOOST_MATH_USE_FLOAT128) && defined(BOOST_MATH_HAS_QUADMATH_H)
629template<>
630inline bool (isnan)(__float128 x)
631{
632 return ::isnanq(x);
633}
634#endif
635
636} // namespace math
637} // namespace boost
638
639#endif // BOOST_MATH_FPCLASSIFY_HPP
640
641

source code of include/boost/math/special_functions/fpclassify.hpp