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 <cfloat> |
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*>(nullptr))) |
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*>(nullptr))) |
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 | |
639 | |