798 lines · plain
1// Copyright John Maddock 2005-2008.2// Copyright (c) 2006-2008 Johan Rade3// Copyright (c) 2024 Matt Borland4// Use, modification and distribution are subject to the5// Boost Software License, Version 1.0. (See accompanying file6// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)7 8#ifndef BOOST_MATH_FPCLASSIFY_HPP9#define BOOST_MATH_FPCLASSIFY_HPP10 11#ifdef _MSC_VER12#pragma once13#endif14 15#include <boost/math/tools/config.hpp>16 17#ifndef BOOST_MATH_HAS_NVRTC18 19#include <boost/math/tools/real_cast.hpp>20#include <boost/math/special_functions/math_fwd.hpp>21#include <boost/math/special_functions/detail/fp_traits.hpp>22#include <limits>23#include <type_traits>24#include <cmath>25 26/*!27 \file fpclassify.hpp28 \brief Classify floating-point value as normal, subnormal, zero, infinite, or NaN.29 \version 1.030 \author John Maddock31 */32 33/*34 351. If the platform is C99 compliant, then the native floating point36classification functions are used. However, note that we must only37define the functions which call std::fpclassify etc if that function38really does exist: otherwise a compiler may reject the code even though39the template is never instantiated.40 412. If the platform is not C99 compliant, and the binary format for42a floating point type (float, double or long double) can be determined43at compile time, then the following algorithm is used:44 45 If all exponent bits, the flag bit (if there is one),46 and all significand bits are 0, then the number is zero.47 48 If all exponent bits and the flag bit (if there is one) are 0,49 and at least one significand bit is 1, then the number is subnormal.50 51 If all exponent bits are 1 and all significand bits are 0,52 then the number is infinity.53 54 If all exponent bits are 1 and at least one significand bit is 1,55 then the number is a not-a-number.56 57 Otherwise the number is normal.58 59 This algorithm works for the IEEE 754 representation,60 and also for several non IEEE 754 formats.61 62 Most formats have the structure63 sign bit + exponent bits + significand bits.64 65 A few have the structure66 sign bit + exponent bits + flag bit + significand bits.67 The flag bit is 0 for zero and subnormal numbers,68 and 1 for normal numbers and NaN.69 It is 0 (Motorola 68K) or 1 (Intel) for infinity.70 71 To get the bits, the four or eight most significant bytes are copied72 into an uint32_t or uint64_t and bit masks are applied.73 This covers all the exponent bits and the flag bit (if there is one),74 but not always all the significand bits.75 Some of the functions below have two implementations,76 depending on whether all the significand bits are copied or not.77 783. If the platform is not C99 compliant, and the binary format for79a floating point type (float, double or long double) can not be determined80at compile time, then comparison with std::numeric_limits values81is used.82 83*/84 85#ifdef BOOST_MATH_HAS_GPU_SUPPORT86 87namespace boost { namespace math {88 89template<> BOOST_MATH_GPU_ENABLED inline bool (isnan)(float x) { return x != x; }90template<> BOOST_MATH_GPU_ENABLED inline bool (isnan)(double x) { return x != x; }91 92template<> BOOST_MATH_GPU_ENABLED inline bool (isinf)(float x) { return x > FLT_MAX || x < -FLT_MAX; }93template<> BOOST_MATH_GPU_ENABLED inline bool (isinf)(double x) { return x > DBL_MAX || x < -DBL_MAX; }94 95template<> BOOST_MATH_GPU_ENABLED inline bool (isfinite)(float x) { return !isnan(x) && !isinf(x); }96template<> BOOST_MATH_GPU_ENABLED inline bool (isfinite)(double x) { return !isnan(x) && !isinf(x); }97 98template<> BOOST_MATH_GPU_ENABLED inline bool (isnormal)(float x)99{100 if(x < 0) x = -x;101 return (x >= FLT_MIN) && (x <= FLT_MAX);102}103template<> BOOST_MATH_GPU_ENABLED inline bool (isnormal)(double x)104{105 if(x < 0) x = -x;106 return (x >= DBL_MIN) && (x <= DBL_MAX);107}108 109template<> BOOST_MATH_GPU_ENABLED inline int (fpclassify)(float t)110{111 if((boost::math::isnan)(t))112 return FP_NAN;113 // std::fabs broken on a few systems especially for long long!!!!114 float at = (t < 0.0f) ? -t : t;115 116 // Use a process of exclusion to figure out117 // what kind of type we have, this relies on118 // IEEE conforming reals that will treat119 // Nan's as unordered. Some compilers120 // don't do this once optimisations are121 // turned on, hence the check for nan's above.122 if(at <= FLT_MAX)123 {124 if(at >= FLT_MIN)125 return FP_NORMAL;126 return (at != 0) ? FP_SUBNORMAL : FP_ZERO;127 }128 else if(at > FLT_MAX)129 return FP_INFINITE;130 return FP_NAN; // LCOV_EXCL_LINE should not normally be reachable.131}132 133template<> BOOST_MATH_GPU_ENABLED inline int (fpclassify)(double t)134{135 if((boost::math::isnan)(t))136 return FP_NAN;137 // std::fabs broken on a few systems especially for long long!!!!138 double at = (t < 0.0) ? -t : t;139 140 // Use a process of exclusion to figure out141 // what kind of type we have, this relies on142 // IEEE conforming reals that will treat143 // Nan's as unordered. Some compilers144 // don't do this once optimisations are145 // turned on, hence the check for nan's above.146 if(at <= DBL_MAX)147 {148 if(at >= DBL_MIN)149 return FP_NORMAL;150 return (at != 0) ? FP_SUBNORMAL : FP_ZERO;151 }152 else if(at > DBL_MAX)153 return FP_INFINITE;154 return FP_NAN;155}156 157#else158 159#if defined(_MSC_VER) || defined(BOOST_BORLANDC)160#include <cfloat>161#endif162#ifdef BOOST_MATH_USE_FLOAT128163#ifdef __has_include164#if __has_include("quadmath.h")165#include "quadmath.h"166#define BOOST_MATH_HAS_QUADMATH_H167#endif168#endif169#endif170 171#ifdef BOOST_NO_STDC_NAMESPACE172 namespace std{ using ::abs; using ::fabs; }173#endif174 175namespace boost{176 177//178// This must not be located in any namespace under boost::math179// otherwise we can get into an infinite loop if isnan is180// a #define for "isnan" !181//182namespace math_detail{183 184#ifdef _MSC_VER185#pragma warning(push)186#pragma warning(disable:4800)187#endif188 189template <class T>190inline bool is_nan_helper(T t, const std::true_type&)191{192#ifdef isnan193 return isnan(t);194#elif defined(BOOST_MATH_DISABLE_STD_FPCLASSIFY) || !defined(BOOST_HAS_FPCLASSIFY)195 (void)t;196 return false;197#else // BOOST_HAS_FPCLASSIFY198 return (BOOST_FPCLASSIFY_PREFIX fpclassify(t) == (int)FP_NAN);199#endif200}201 202#ifdef _MSC_VER203#pragma warning(pop)204#endif205 206template <class T>207inline bool is_nan_helper(T, const std::false_type&)208{209 return false;210}211#if defined(BOOST_MATH_USE_FLOAT128)212#if defined(BOOST_MATH_HAS_QUADMATH_H)213inline bool is_nan_helper(__float128 f, const std::true_type&) { return ::isnanq(f); }214inline bool is_nan_helper(__float128 f, const std::false_type&) { return ::isnanq(f); }215#elif defined(BOOST_GNU_STDLIB) && BOOST_GNU_STDLIB && \216 _GLIBCXX_USE_C99_MATH && !_GLIBCXX_USE_C99_FP_MACROS_DYNAMIC217inline bool is_nan_helper(__float128 f, const std::true_type&) { return std::isnan(static_cast<double>(f)); }218inline bool is_nan_helper(__float128 f, const std::false_type&) { return std::isnan(static_cast<double>(f)); }219#else220inline bool is_nan_helper(__float128 f, const std::true_type&) { return boost::math::isnan(static_cast<double>(f)); }221inline bool is_nan_helper(__float128 f, const std::false_type&) { return boost::math::isnan(static_cast<double>(f)); }222#endif223#endif224}225 226namespace math{227 228namespace detail{229 230#ifdef BOOST_MATH_USE_STD_FPCLASSIFY231template <class T>232inline int fpclassify_imp BOOST_NO_MACRO_EXPAND(T t, const native_tag&)233{234 return (std::fpclassify)(t);235}236#endif237 238template <class T>239inline int fpclassify_imp BOOST_NO_MACRO_EXPAND(T t, const generic_tag<true>&)240{241 BOOST_MATH_INSTRUMENT_VARIABLE(t);242 243 // whenever possible check for Nan's first:244#if defined(BOOST_HAS_FPCLASSIFY) && !defined(BOOST_MATH_DISABLE_STD_FPCLASSIFY)245 if(::boost::math_detail::is_nan_helper(t, typename std::is_floating_point<T>::type()))246 return FP_NAN; // LCOV_EXCL_LINE only called in UDT contexts (excluded from coverage checks).247#elif defined(isnan)248 if(boost::math_detail::is_nan_helper(t, typename std::is_floating_point<T>::type()))249 return FP_NAN;250#elif defined(_MSC_VER) || defined(BOOST_BORLANDC)251 if(::_isnan(boost::math::tools::real_cast<double>(t)))252 return FP_NAN;253#endif254 // std::fabs broken on a few systems especially for long long!!!!255 T at = (t < T(0)) ? -t : t;256 257 // Use a process of exclusion to figure out258 // what kind of type we have, this relies on259 // IEEE conforming reals that will treat260 // Nan's as unordered. Some compilers261 // don't do this once optimisations are262 // turned on, hence the check for nan's above.263 if(at <= (std::numeric_limits<T>::max)())264 {265 if(at >= (std::numeric_limits<T>::min)())266 return FP_NORMAL;267 return (at != 0) ? FP_SUBNORMAL : FP_ZERO;268 }269 else if(at > (std::numeric_limits<T>::max)())270 return FP_INFINITE;271 return FP_NAN;272}273 274template <class T>275inline int fpclassify_imp BOOST_NO_MACRO_EXPAND(T t, const generic_tag<false>&)276{277#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS278 if(std::numeric_limits<T>::is_specialized)279 return fpclassify_imp(t, generic_tag<true>());280#endif281 //282 // An unknown type with no numeric_limits support,283 // so what are we supposed to do we do here?284 //285 BOOST_MATH_INSTRUMENT_VARIABLE(t);286 287 return t == 0 ? FP_ZERO : FP_NORMAL;288}289 290template<class T>291int fpclassify_imp BOOST_NO_MACRO_EXPAND(T x, ieee_copy_all_bits_tag)292{293 typedef typename fp_traits<T>::type traits;294 295 BOOST_MATH_INSTRUMENT_VARIABLE(x);296 297 typename traits::bits a;298 traits::get_bits(x,a);299 BOOST_MATH_INSTRUMENT_VARIABLE(a);300 a &= traits::exponent | traits::flag | traits::significand;301 BOOST_MATH_INSTRUMENT_VARIABLE((traits::exponent | traits::flag | traits::significand));302 BOOST_MATH_INSTRUMENT_VARIABLE(a);303 304 if(a <= traits::significand) {305 if(a == 0)306 return FP_ZERO;307 else308 return FP_SUBNORMAL;309 }310 311 if(a < traits::exponent) return FP_NORMAL;312 313 a &= traits::significand;314 if(a == 0) return FP_INFINITE;315 316 return FP_NAN;317}318 319template<class T>320int fpclassify_imp BOOST_NO_MACRO_EXPAND(T x, ieee_copy_leading_bits_tag)321{322 typedef typename fp_traits<T>::type traits;323 324 BOOST_MATH_INSTRUMENT_VARIABLE(x);325 326 typename traits::bits a;327 traits::get_bits(x,a);328 a &= traits::exponent | traits::flag | traits::significand;329 330 if(a <= traits::significand) {331 if(x == 0)332 return FP_ZERO;333 else334 return FP_SUBNORMAL;335 }336 337 if(a < traits::exponent) return FP_NORMAL;338 339 a &= traits::significand;340 traits::set_bits(x,a);341 if(x == 0) return FP_INFINITE;342 343 return FP_NAN;344}345 346#if defined(BOOST_MATH_USE_STD_FPCLASSIFY) && (defined(BOOST_MATH_NO_NATIVE_LONG_DOUBLE_FP_CLASSIFY) || defined(BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS))347inline int fpclassify_imp BOOST_NO_MACRO_EXPAND(long double t, const native_tag&)348{349 return boost::math::detail::fpclassify_imp(t, generic_tag<true>());350}351#endif352 353} // namespace detail354 355template <class T>356inline int fpclassify BOOST_NO_MACRO_EXPAND(T t)357{358 typedef typename detail::fp_traits<T>::type traits;359 typedef typename traits::method method;360 typedef typename tools::promote_args_permissive<T>::type value_type;361#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS362 if(std::numeric_limits<T>::is_specialized && detail::is_generic_tag_false(static_cast<method*>(nullptr)))363 return detail::fpclassify_imp(static_cast<value_type>(t), detail::generic_tag<true>());364 return detail::fpclassify_imp(static_cast<value_type>(t), method());365#else366 return detail::fpclassify_imp(static_cast<value_type>(t), method());367#endif368}369 370#ifdef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS371template <>372inline int fpclassify<long double> BOOST_NO_MACRO_EXPAND(long double t)373{374 typedef detail::fp_traits<long double>::type traits;375 typedef traits::method method;376 typedef long double value_type;377#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS378 if(std::numeric_limits<long double>::is_specialized && detail::is_generic_tag_false(static_cast<method*>(nullptr)))379 return detail::fpclassify_imp(static_cast<value_type>(t), detail::generic_tag<true>());380 return detail::fpclassify_imp(static_cast<value_type>(t), method());381#else382 return detail::fpclassify_imp(static_cast<value_type>(t), method());383#endif384}385#endif386 387namespace detail {388 389#ifdef BOOST_MATH_USE_STD_FPCLASSIFY390 template<class T>391 inline bool isfinite_impl(T x, native_tag const&)392 {393 return (std::isfinite)(x);394 }395#endif396 397 template<class T>398 inline bool isfinite_impl(T x, generic_tag<true> const&)399 {400 return x >= -(std::numeric_limits<T>::max)()401 && x <= (std::numeric_limits<T>::max)();402 }403 404 template<class T>405 inline bool isfinite_impl(T x, generic_tag<false> const&)406 {407#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS408 if(std::numeric_limits<T>::is_specialized)409 return isfinite_impl(x, generic_tag<true>());410#endif411 (void)x; // warning suppression.412 return true;413 }414 415 template<class T>416 inline bool isfinite_impl(T x, ieee_tag const&)417 {418 typedef typename detail::fp_traits<T>::type traits;419 typename traits::bits a;420 traits::get_bits(x,a);421 a &= traits::exponent;422 return a != traits::exponent;423 }424 425#if defined(BOOST_MATH_USE_STD_FPCLASSIFY) && defined(BOOST_MATH_NO_NATIVE_LONG_DOUBLE_FP_CLASSIFY)426inline bool isfinite_impl BOOST_NO_MACRO_EXPAND(long double t, const native_tag&)427{428 return boost::math::detail::isfinite_impl(t, generic_tag<true>());429}430#endif431 432}433 434template<class T>435inline bool (isfinite)(T x)436{ //!< \brief return true if floating-point type t is finite.437 typedef typename detail::fp_traits<T>::type traits;438 typedef typename traits::method method;439 // typedef typename boost::is_floating_point<T>::type fp_tag;440 typedef typename tools::promote_args_permissive<T>::type value_type;441 return detail::isfinite_impl(static_cast<value_type>(x), method());442}443 444#ifdef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS445template<>446inline bool (isfinite)(long double x)447{ //!< \brief return true if floating-point type t is finite.448 typedef detail::fp_traits<long double>::type traits;449 typedef traits::method method;450 //typedef boost::is_floating_point<long double>::type fp_tag;451 typedef long double value_type;452 return detail::isfinite_impl(static_cast<value_type>(x), method());453}454#endif455 456//------------------------------------------------------------------------------457 458namespace detail {459 460#ifdef BOOST_MATH_USE_STD_FPCLASSIFY461 template<class T>462 inline bool isnormal_impl(T x, native_tag const&)463 {464 return (std::isnormal)(x);465 }466#endif467 468 template<class T>469 inline bool isnormal_impl(T x, generic_tag<true> const&)470 {471 if(x < 0) x = -x;472 return x >= (std::numeric_limits<T>::min)()473 && x <= (std::numeric_limits<T>::max)();474 }475 476 template<class T>477 inline bool isnormal_impl(T x, generic_tag<false> const&)478 {479#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS480 if(std::numeric_limits<T>::is_specialized)481 return isnormal_impl(x, generic_tag<true>());482#endif483 return !(x == 0);484 }485 486 template<class T>487 inline bool isnormal_impl(T x, ieee_tag const&)488 {489 typedef typename detail::fp_traits<T>::type traits;490 typename traits::bits a;491 traits::get_bits(x,a);492 a &= traits::exponent | traits::flag;493 return (a != 0) && (a < traits::exponent);494 }495 496#if defined(BOOST_MATH_USE_STD_FPCLASSIFY) && defined(BOOST_MATH_NO_NATIVE_LONG_DOUBLE_FP_CLASSIFY)497inline bool isnormal_impl BOOST_NO_MACRO_EXPAND(long double t, const native_tag&)498{499 return boost::math::detail::isnormal_impl(t, generic_tag<true>());500}501#endif502 503}504 505template<class T>506inline bool (isnormal)(T x)507{508 typedef typename detail::fp_traits<T>::type traits;509 typedef typename traits::method method;510 //typedef typename boost::is_floating_point<T>::type fp_tag;511 typedef typename tools::promote_args_permissive<T>::type value_type;512 return detail::isnormal_impl(static_cast<value_type>(x), method());513}514 515#ifdef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS516template<>517inline bool (isnormal)(long double x)518{519 typedef detail::fp_traits<long double>::type traits;520 typedef traits::method method;521 //typedef boost::is_floating_point<long double>::type fp_tag;522 typedef long double value_type;523 return detail::isnormal_impl(static_cast<value_type>(x), method());524}525#endif526 527//------------------------------------------------------------------------------528 529namespace detail {530 531#ifdef BOOST_MATH_USE_STD_FPCLASSIFY532 template<class T>533 inline bool isinf_impl(T x, native_tag const&)534 {535 return (std::isinf)(x);536 }537#endif538 539 template<class T>540 inline bool isinf_impl(T x, generic_tag<true> const&)541 {542 (void)x; // in case the compiler thinks that x is unused because std::numeric_limits<T>::has_infinity is false543 return std::numeric_limits<T>::has_infinity544 && ( x == std::numeric_limits<T>::infinity()545 || x == -std::numeric_limits<T>::infinity());546 }547 548 template<class T>549 inline bool isinf_impl(T x, generic_tag<false> const&)550 {551#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS552 if(std::numeric_limits<T>::is_specialized)553 return isinf_impl(x, generic_tag<true>());554#endif555 (void)x; // warning suppression.556 return false;557 }558 559 template<class T>560 inline bool isinf_impl(T x, ieee_copy_all_bits_tag const&)561 {562 typedef typename fp_traits<T>::type traits;563 564 typename traits::bits a;565 traits::get_bits(x,a);566 a &= traits::exponent | traits::significand;567 return a == traits::exponent;568 }569 570 template<class T>571 inline bool isinf_impl(T x, ieee_copy_leading_bits_tag const&)572 {573 typedef typename fp_traits<T>::type traits;574 575 typename traits::bits a;576 traits::get_bits(x,a);577 a &= traits::exponent | traits::significand;578 if(a != traits::exponent)579 return false;580 581 traits::set_bits(x,0);582 return x == 0;583 }584 585#if defined(BOOST_MATH_USE_STD_FPCLASSIFY) && defined(BOOST_MATH_NO_NATIVE_LONG_DOUBLE_FP_CLASSIFY)586inline bool isinf_impl BOOST_NO_MACRO_EXPAND(long double t, const native_tag&)587{588 return boost::math::detail::isinf_impl(t, generic_tag<true>());589}590#endif591 592} // namespace detail593 594template<class T>595inline bool (isinf)(T x)596{597 typedef typename detail::fp_traits<T>::type traits;598 typedef typename traits::method method;599 // typedef typename boost::is_floating_point<T>::type fp_tag;600 typedef typename tools::promote_args_permissive<T>::type value_type;601 return detail::isinf_impl(static_cast<value_type>(x), method());602}603 604#ifdef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS605template<>606inline bool (isinf)(long double x)607{608 typedef detail::fp_traits<long double>::type traits;609 typedef traits::method method;610 //typedef boost::is_floating_point<long double>::type fp_tag;611 typedef long double value_type;612 return detail::isinf_impl(static_cast<value_type>(x), method());613}614#endif615#if defined(BOOST_MATH_USE_FLOAT128) && defined(BOOST_MATH_HAS_QUADMATH_H)616template<>617inline bool (isinf)(__float128 x)618{619 return ::isinfq(x);620}621#endif622 623//------------------------------------------------------------------------------624 625namespace detail {626 627#ifdef BOOST_MATH_USE_STD_FPCLASSIFY628 template<class T>629 inline bool isnan_impl(T x, native_tag const&)630 {631 return (std::isnan)(x);632 }633#endif634 635 template<class T>636 inline bool isnan_impl(T x, generic_tag<true> const&)637 {638 return std::numeric_limits<T>::has_infinity639 ? !(x <= std::numeric_limits<T>::infinity())640 : x != x;641 }642 643 template<class T>644 inline bool isnan_impl(T x, generic_tag<false> const&)645 {646#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS647 if(std::numeric_limits<T>::is_specialized)648 return isnan_impl(x, generic_tag<true>());649#endif650 (void)x; // warning suppression651 return false;652 }653 654 template<class T>655 inline bool isnan_impl(T x, ieee_copy_all_bits_tag const&)656 {657 typedef typename fp_traits<T>::type traits;658 659 typename traits::bits a;660 traits::get_bits(x,a);661 a &= traits::exponent | traits::significand;662 return a > traits::exponent;663 }664 665 template<class T>666 inline bool isnan_impl(T x, ieee_copy_leading_bits_tag const&)667 {668 typedef typename fp_traits<T>::type traits;669 670 typename traits::bits a;671 traits::get_bits(x,a);672 673 a &= traits::exponent | traits::significand;674 if(a < traits::exponent)675 return false;676 677 a &= traits::significand;678 traits::set_bits(x,a);679 return x != 0;680 }681 682} // namespace detail683 684template<class T>685inline bool (isnan)(T x)686{ //!< \brief return true if floating-point type t is NaN (Not A Number).687 typedef typename detail::fp_traits<T>::type traits;688 typedef typename traits::method method;689 // typedef typename boost::is_floating_point<T>::type fp_tag;690 return detail::isnan_impl(x, method());691}692 693#ifdef isnan694template <> inline bool isnan BOOST_NO_MACRO_EXPAND<float>(float t){ return ::boost::math_detail::is_nan_helper(t, std::true_type()); }695template <> inline bool isnan BOOST_NO_MACRO_EXPAND<double>(double t){ return ::boost::math_detail::is_nan_helper(t, std::true_type()); }696template <> inline bool isnan BOOST_NO_MACRO_EXPAND<long double>(long double t){ return ::boost::math_detail::is_nan_helper(t, std::true_type()); }697#elif defined(BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS)698template<>699inline bool (isnan)(long double x)700{ //!< \brief return true if floating-point type t is NaN (Not A Number).701 typedef detail::fp_traits<long double>::type traits;702 typedef traits::method method;703 //typedef boost::is_floating_point<long double>::type fp_tag;704 return detail::isnan_impl(x, method());705}706#endif707#if defined(BOOST_MATH_USE_FLOAT128) && defined(BOOST_MATH_HAS_QUADMATH_H)708template<>709inline bool (isnan)(__float128 x)710{711 return ::isnanq(x);712}713#endif714 715#endif716 717} // namespace math718} // namespace boost719 720#else // Special handling generally using the CUDA library721 722#include <boost/math/tools/type_traits.hpp>723 724namespace boost {725namespace math {726 727template <typename T, boost::math::enable_if_t<boost::math::is_integral_v<T>, bool> = true>728BOOST_MATH_GPU_ENABLED inline bool isnan(T x)729{730 return false;731}732 733template <typename T, boost::math::enable_if_t<!boost::math::is_integral_v<T>, bool> = true>734BOOST_MATH_GPU_ENABLED inline bool isnan(T x)735{736 return ::isnan(x);737}738 739template <typename T, boost::math::enable_if_t<boost::math::is_integral_v<T>, bool> = true>740BOOST_MATH_GPU_ENABLED inline bool isinf(T x)741{742 return false;743}744 745template <typename T, boost::math::enable_if_t<!boost::math::is_integral_v<T>, bool> = true>746BOOST_MATH_GPU_ENABLED inline bool isinf(T x)747{748 return ::isinf(x);749}750 751template <typename T, boost::math::enable_if_t<boost::math::is_integral_v<T>, bool> = true>752BOOST_MATH_GPU_ENABLED inline bool isfinite(T x)753{754 return true;755}756 757template <typename T, boost::math::enable_if_t<!boost::math::is_integral_v<T>, bool> = true>758BOOST_MATH_GPU_ENABLED inline bool isfinite(T x)759{760 return ::isfinite(x);761}762 763template <typename T>764BOOST_MATH_GPU_ENABLED inline bool isnormal(T x)765{766 return x != static_cast<T>(0) && x != static_cast<T>(-0) && 767 !boost::math::isnan(x) && 768 !boost::math::isinf(x);769}770 771// We skip the check for FP_SUBNORMAL since they are not supported on these platforms772template <typename T>773BOOST_MATH_GPU_ENABLED inline int fpclassify(T x)774{775 if (boost::math::isnan(x))776 {777 return BOOST_MATH_FP_NAN;778 }779 else if (boost::math::isinf(x))780 {781 return BOOST_MATH_FP_INFINITE;782 }783 else if (x == static_cast<T>(0) || x == static_cast<T>(-0))784 {785 return BOOST_MATH_FP_ZERO;786 }787 788 return BOOST_MATH_FP_NORMAL;789}790 791} // Namespace math792} // Namespace boost793 794#endif // BOOST_MATH_HAS_NVRTC795 796#endif // BOOST_MATH_FPCLASSIFY_HPP797 798