]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 | ||
1e59de90 TL |
14 | #include <limits> |
15 | #include <type_traits> | |
16 | #include <cmath> | |
7c673cae | 17 | #include <boost/math/tools/real_cast.hpp> |
7c673cae FG |
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 | ||
20effc67 | 79 | #if defined(_MSC_VER) || defined(BOOST_BORLANDC) |
7c673cae FG |
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 | ||
1e59de90 | 104 | #ifdef _MSC_VER |
7c673cae FG |
105 | #pragma warning(push) |
106 | #pragma warning(disable:4800) | |
107 | #endif | |
108 | ||
109 | template <class T> | |
1e59de90 | 110 | inline bool is_nan_helper(T t, const std::true_type&) |
7c673cae FG |
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 | ||
1e59de90 | 122 | #ifdef _MSC_VER |
7c673cae FG |
123 | #pragma warning(pop) |
124 | #endif | |
125 | ||
126 | template <class T> | |
1e59de90 | 127 | inline bool is_nan_helper(T, const std::false_type&) |
7c673cae FG |
128 | { |
129 | return false; | |
130 | } | |
131 | #if defined(BOOST_MATH_USE_FLOAT128) | |
132 | #if defined(BOOST_MATH_HAS_QUADMATH_H) | |
1e59de90 TL |
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); } | |
7c673cae FG |
135 | #elif defined(BOOST_GNU_STDLIB) && BOOST_GNU_STDLIB && \ |
136 | _GLIBCXX_USE_C99_MATH && !_GLIBCXX_USE_C99_FP_MACROS_DYNAMIC | |
1e59de90 TL |
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)); } | |
7c673cae | 139 | #else |
1e59de90 TL |
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)); } | |
7c673cae FG |
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) | |
1e59de90 | 165 | if(::boost::math_detail::is_nan_helper(t, typename std::is_floating_point<T>::type())) |
7c673cae FG |
166 | return FP_NAN; |
167 | #elif defined(isnan) | |
1e59de90 | 168 | if(boost::math_detail::is_nan_helper(t, typename std::is_floating_point<T>::type())) |
7c673cae | 169 | return FP_NAN; |
20effc67 | 170 | #elif defined(_MSC_VER) || defined(BOOST_BORLANDC) |
7c673cae FG |
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 | { | |
1e59de90 | 213 | typedef typename fp_traits<T>::type traits; |
7c673cae FG |
214 | |
215 | BOOST_MATH_INSTRUMENT_VARIABLE(x); | |
216 | ||
1e59de90 | 217 | typename traits::bits a; |
7c673cae FG |
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 | { | |
1e59de90 | 242 | typedef typename fp_traits<T>::type traits; |
7c673cae FG |
243 | |
244 | BOOST_MATH_INSTRUMENT_VARIABLE(x); | |
245 | ||
1e59de90 | 246 | typename traits::bits a; |
7c673cae FG |
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 | { | |
1e59de90 TL |
338 | typedef typename detail::fp_traits<T>::type traits; |
339 | typename traits::bits a; | |
7c673cae FG |
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 | { | |
1e59de90 TL |
409 | typedef typename detail::fp_traits<T>::type traits; |
410 | typename traits::bits a; | |
7c673cae FG |
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 | { | |
1e59de90 | 482 | typedef typename fp_traits<T>::type traits; |
7c673cae | 483 | |
1e59de90 | 484 | typename traits::bits a; |
7c673cae FG |
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 | { | |
1e59de90 | 493 | typedef typename fp_traits<T>::type traits; |
7c673cae | 494 | |
1e59de90 | 495 | typename traits::bits a; |
7c673cae FG |
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 | { | |
1e59de90 | 577 | typedef typename fp_traits<T>::type traits; |
7c673cae | 578 | |
1e59de90 | 579 | typename traits::bits a; |
7c673cae FG |
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 | { | |
1e59de90 | 588 | typedef typename fp_traits<T>::type traits; |
7c673cae | 589 | |
1e59de90 | 590 | typename traits::bits a; |
7c673cae FG |
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 | |
1e59de90 TL |
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()); } | |
7c673cae FG |
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 | |
7c673cae FG |
637 | #endif // BOOST_MATH_FPCLASSIFY_HPP |
638 |