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