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 | #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 | |
96 | namespace 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 | // |
103 | namespace math_detail{ |
104 | |
105 | #ifdef BOOST_MSVC |
106 | #pragma warning(push) |
107 | #pragma warning(disable:4800) |
108 | #endif |
109 | |
110 | template <class T> |
111 | inline 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 | |
127 | template <class T> |
128 | inline 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) |
134 | inline bool is_nan_helper(__float128 f, const boost::true_type&) { return ::isnanq(f); } |
135 | inline 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 |
138 | inline bool is_nan_helper(__float128 f, const boost::true_type&) { return std::isnan(static_cast<double>(f)); } |
139 | inline bool is_nan_helper(__float128 f, const boost::false_type&) { return std::isnan(static_cast<double>(f)); } |
140 | #else |
141 | inline bool is_nan_helper(__float128 f, const boost::true_type&) { return ::isnan(static_cast<double>(f)); } |
142 | inline bool is_nan_helper(__float128 f, const boost::false_type&) { return ::isnan(static_cast<double>(f)); } |
143 | #endif |
144 | #endif |
145 | } |
146 | |
147 | namespace math{ |
148 | |
149 | namespace detail{ |
150 | |
151 | #ifdef BOOST_MATH_USE_STD_FPCLASSIFY |
152 | template <class T> |
153 | inline int fpclassify_imp BOOST_NO_MACRO_EXPAND(T t, const native_tag&) |
154 | { |
155 | return (std::fpclassify)(t); |
156 | } |
157 | #endif |
158 | |
159 | template <class T> |
160 | inline 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 | |
195 | template <class T> |
196 | inline 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 | |
211 | template<class T> |
212 | int 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 | |
240 | template<class T> |
241 | int 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)) |
268 | inline 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 | |
276 | template <class T> |
277 | inline 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 |
292 | template <> |
293 | inline 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 | |
308 | namespace 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) |
347 | inline 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 | |
355 | template<class T> |
356 | inline 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 |
366 | template<> |
367 | inline 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 | |
379 | namespace 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) |
418 | inline 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 | |
426 | template<class T> |
427 | inline 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 |
437 | template<> |
438 | inline 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 | |
450 | namespace 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) |
507 | inline 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 | |
515 | template<class T> |
516 | inline 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 |
526 | template<> |
527 | inline 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) |
537 | template<> |
538 | inline bool (isinf)(__float128 x) |
539 | { |
540 | return ::isinfq(x); |
541 | } |
542 | #endif |
543 | |
544 | //------------------------------------------------------------------------------ |
545 | |
546 | namespace 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 | |
605 | template<class T> |
606 | inline 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 |
615 | template <> inline bool isnan BOOST_NO_MACRO_EXPAND<float>(float t){ return ::boost::math_detail::is_nan_helper(t, boost::true_type()); } |
616 | template <> inline bool isnan BOOST_NO_MACRO_EXPAND<double>(double t){ return ::boost::math_detail::is_nan_helper(t, boost::true_type()); } |
617 | template <> 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) |
619 | template<> |
620 | inline 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) |
629 | template<> |
630 | inline 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 | |