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 301. If the platform is C99 compliant, then the native floating point 31classification functions are used. However, note that we must only 32define the functions which call std::fpclassify etc if that function 33really does exist: otherwise a compiler may reject the code even though 34the template is never instantiated. 35 362. If the platform is not C99 compliant, and the binary format for 37a floating point type (float, double or long double) can be determined 38at 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 733. If the platform is not C99 compliant, and the binary format for 74a floating point type (float, double or long double) can not be determined 75at compile time, then comparison with std::numeric_limits values 76is used. 77 78*/ 79 80#if defined(_MSC_VER) || defined(__BORLANDC__) 81#include <float.h> 82#endif 83 84#ifdef BOOST_NO_STDC_NAMESPACE 85 namespace std{ using ::abs; using ::fabs; } 86#endif 87 88namespace boost{ 89 90// 91// This must not be located in any namespace under boost::math 92// otherwise we can get into an infinite loop if isnan is 93// a #define for "isnan" ! 94// 95namespace math_detail{ 96 97template <class T> 98inline bool is_nan_helper(T t, const boost::true_type&) 99{ 100#ifdef isnan 101 return isnan(t); 102#elif defined(BOOST_MATH_DISABLE_STD_FPCLASSIFY) || !defined(BOOST_HAS_FPCLASSIFY) 103 return false; 104#else // BOOST_HAS_FPCLASSIFY 105 return (BOOST_FPCLASSIFY_PREFIX fpclassify(t) == (int)FP_NAN); 106#endif 107} 108 109template <class T> 110inline bool is_nan_helper(T, const boost::false_type&) 111{ 112 return false; 113} 114 115} 116 117namespace math{ 118 119namespace detail{ 120 121#ifdef BOOST_MATH_USE_STD_FPCLASSIFY 122template <class T> 123inline int fpclassify_imp BOOST_NO_MACRO_EXPAND(T t, const native_tag&) 124{ 125 return (std::fpclassify)(t); 126} 127#endif 128 129template <class T> 130inline int fpclassify_imp BOOST_NO_MACRO_EXPAND(T t, const generic_tag<true>&) 131{ 132 BOOST_MATH_INSTRUMENT_VARIABLE(t); 133 134 // whenever possible check for Nan's first: 135#if defined(BOOST_HAS_FPCLASSIFY) && !defined(BOOST_MATH_DISABLE_STD_FPCLASSIFY) 136 if(::boost::math_detail::is_nan_helper(t, ::boost::is_floating_point<T>())) 137 return FP_NAN; 138#elif defined(isnan) 139 if(boost::math_detail::is_nan_helper(t, ::boost::is_floating_point<T>())) 140 return FP_NAN; 141#elif defined(_MSC_VER) || defined(__BORLANDC__) 142 if(::_isnan(boost::math::tools::real_cast<double>(t))) 143 return FP_NAN; 144#endif 145 // std::fabs broken on a few systems especially for long long!!!! 146 T at = (t < T(0)) ? -t : t; 147 148 // Use a process of exclusion to figure out 149 // what kind of type we have, this relies on 150 // IEEE conforming reals that will treat 151 // Nan's as unordered. Some compilers 152 // don't do this once optimisations are 153 // turned on, hence the check for nan's above. 154 if(at <= (std::numeric_limits<T>::max)()) 155 { 156 if(at >= (std::numeric_limits<T>::min)()) 157 return FP_NORMAL; 158 return (at != 0) ? FP_SUBNORMAL : FP_ZERO; 159 } 160 else if(at > (std::numeric_limits<T>::max)()) 161 return FP_INFINITE; 162 return FP_NAN; 163} 164 165template <class T> 166inline int fpclassify_imp BOOST_NO_MACRO_EXPAND(T t, const generic_tag<false>&) 167{ 168#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS 169 if(std::numeric_limits<T>::is_specialized) 170 return fpclassify_imp(t, generic_tag<true>()); 171#endif 172 // 173 // An unknown type with no numeric_limits support, 174 // so what are we supposed to do we do here? 175 // 176 BOOST_MATH_INSTRUMENT_VARIABLE(t); 177 178 return t == 0 ? FP_ZERO : FP_NORMAL; 179} 180 181template<class T> 182int fpclassify_imp BOOST_NO_MACRO_EXPAND(T x, ieee_copy_all_bits_tag) 183{ 184 typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits; 185 186 BOOST_MATH_INSTRUMENT_VARIABLE(x); 187 188 BOOST_DEDUCED_TYPENAME traits::bits a; 189 traits::get_bits(x,a); 190 BOOST_MATH_INSTRUMENT_VARIABLE(a); 191 a &= traits::exponent | traits::flag | traits::significand; 192 BOOST_MATH_INSTRUMENT_VARIABLE((traits::exponent | traits::flag | traits::significand)); 193 BOOST_MATH_INSTRUMENT_VARIABLE(a); 194 195 if(a <= traits::significand) { 196 if(a == 0) 197 return FP_ZERO; 198 else 199 return FP_SUBNORMAL; 200 } 201 202 if(a < traits::exponent) return FP_NORMAL; 203 204 a &= traits::significand; 205 if(a == 0) return FP_INFINITE; 206 207 return FP_NAN; 208} 209 210template<class T> 211int fpclassify_imp BOOST_NO_MACRO_EXPAND(T x, ieee_copy_leading_bits_tag) 212{ 213 typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits; 214 215 BOOST_MATH_INSTRUMENT_VARIABLE(x); 216 217 BOOST_DEDUCED_TYPENAME traits::bits a; 218 traits::get_bits(x,a); 219 a &= traits::exponent | traits::flag | traits::significand; 220 221 if(a <= traits::significand) { 222 if(x == 0) 223 return FP_ZERO; 224 else 225 return FP_SUBNORMAL; 226 } 227 228 if(a < traits::exponent) return FP_NORMAL; 229 230 a &= traits::significand; 231 traits::set_bits(x,a); 232 if(x == 0) return FP_INFINITE; 233 234 return FP_NAN; 235} 236 237#if defined(BOOST_MATH_USE_STD_FPCLASSIFY) && defined(BOOST_MATH_NO_NATIVE_LONG_DOUBLE_FP_CLASSIFY) 238template <> 239inline int fpclassify_imp<long double> BOOST_NO_MACRO_EXPAND(long double t, const native_tag&) 240{ 241 return boost::math::detail::fpclassify_imp(t, generic_tag<true>()); 242} 243#endif 244 245} // namespace detail 246 247template <class T> 248inline int fpclassify BOOST_NO_MACRO_EXPAND(T t) 249{ 250 typedef typename detail::fp_traits<T>::type traits; 251 typedef typename traits::method method; 252 typedef typename tools::promote_args<T>::type value_type; 253#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS 254 if(std::numeric_limits<T>::is_specialized && detail::is_generic_tag_false(static_cast<method*>(0))) 255 return detail::fpclassify_imp(static_cast<value_type>(t), detail::generic_tag<true>()); 256 return detail::fpclassify_imp(static_cast<value_type>(t), method()); 257#else 258 return detail::fpclassify_imp(static_cast<value_type>(t), method()); 259#endif 260} 261 262namespace detail { 263 264#ifdef BOOST_MATH_USE_STD_FPCLASSIFY 265 template<class T> 266 inline bool isfinite_impl(T x, native_tag const&) 267 { 268 return (std::isfinite)(x); 269 } 270#endif 271 272 template<class T> 273 inline bool isfinite_impl(T x, generic_tag<true> const&) 274 { 275 return x >= -(std::numeric_limits<T>::max)() 276 && x <= (std::numeric_limits<T>::max)(); 277 } 278 279 template<class T> 280 inline bool isfinite_impl(T x, generic_tag<false> const&) 281 { 282#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS 283 if(std::numeric_limits<T>::is_specialized) 284 return isfinite_impl(x, generic_tag<true>()); 285#endif 286 (void)x; // warning supression. 287 return true; 288 } 289 290 template<class T> 291 inline bool isfinite_impl(T x, ieee_tag const&) 292 { 293 typedef BOOST_DEDUCED_TYPENAME detail::fp_traits<T>::type traits; 294 BOOST_DEDUCED_TYPENAME traits::bits a; 295 traits::get_bits(x,a); 296 a &= traits::exponent; 297 return a != traits::exponent; 298 } 299 300#if defined(BOOST_MATH_USE_STD_FPCLASSIFY) && defined(BOOST_MATH_NO_NATIVE_LONG_DOUBLE_FP_CLASSIFY) 301template <> 302inline bool isfinite_impl<long double> BOOST_NO_MACRO_EXPAND(long double t, const native_tag&) 303{ 304 return boost::math::detail::isfinite_impl(t, generic_tag<true>()); 305} 306#endif 307 308} 309 310template<class T> 311inline bool (isfinite)(T x) 312{ //!< \brief return true if floating-point type t is finite. 313 typedef typename detail::fp_traits<T>::type traits; 314 typedef typename traits::method method; 315 typedef typename boost::is_floating_point<T>::type fp_tag; 316 typedef typename tools::promote_args<T>::type value_type; 317 return detail::isfinite_impl(static_cast<value_type>(x), method()); 318} 319 320//------------------------------------------------------------------------------ 321 322namespace detail { 323 324#ifdef BOOST_MATH_USE_STD_FPCLASSIFY 325 template<class T> 326 inline bool isnormal_impl(T x, native_tag const&) 327 { 328 return (std::isnormal)(x); 329 } 330#endif 331 332 template<class T> 333 inline bool isnormal_impl(T x, generic_tag<true> const&) 334 { 335 if(x < 0) x = -x; 336 return x >= (std::numeric_limits<T>::min)() 337 && x <= (std::numeric_limits<T>::max)(); 338 } 339 340 template<class T> 341 inline bool isnormal_impl(T x, generic_tag<false> const&) 342 { 343#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS 344 if(std::numeric_limits<T>::is_specialized) 345 return isnormal_impl(x, generic_tag<true>()); 346#endif 347 return !(x == 0); 348 } 349 350 template<class T> 351 inline bool isnormal_impl(T x, ieee_tag const&) 352 { 353 typedef BOOST_DEDUCED_TYPENAME detail::fp_traits<T>::type traits; 354 BOOST_DEDUCED_TYPENAME traits::bits a; 355 traits::get_bits(x,a); 356 a &= traits::exponent | traits::flag; 357 return (a != 0) && (a < traits::exponent); 358 } 359 360#if defined(BOOST_MATH_USE_STD_FPCLASSIFY) && defined(BOOST_MATH_NO_NATIVE_LONG_DOUBLE_FP_CLASSIFY) 361template <> 362inline bool isnormal_impl<long double> BOOST_NO_MACRO_EXPAND(long double t, const native_tag&) 363{ 364 return boost::math::detail::isnormal_impl(t, generic_tag<true>()); 365} 366#endif 367 368} 369 370template<class T> 371inline bool (isnormal)(T x) 372{ 373 typedef typename detail::fp_traits<T>::type traits; 374 typedef typename traits::method method; 375 typedef typename boost::is_floating_point<T>::type fp_tag; 376 typedef typename tools::promote_args<T>::type value_type; 377 return detail::isnormal_impl(static_cast<value_type>(x), method()); 378} 379 380//------------------------------------------------------------------------------ 381 382namespace detail { 383 384#ifdef BOOST_MATH_USE_STD_FPCLASSIFY 385 template<class T> 386 inline bool isinf_impl(T x, native_tag const&) 387 { 388 return (std::isinf)(x); 389 } 390#endif 391 392 template<class T> 393 inline bool isinf_impl(T x, generic_tag<true> const&) 394 { 395 (void)x; // in case the compiler thinks that x is unused because std::numeric_limits<T>::has_infinity is false 396 return std::numeric_limits<T>::has_infinity 397 && ( x == std::numeric_limits<T>::infinity() 398 || x == -std::numeric_limits<T>::infinity()); 399 } 400 401 template<class T> 402 inline bool isinf_impl(T x, generic_tag<false> const&) 403 { 404#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS 405 if(std::numeric_limits<T>::is_specialized) 406 return isinf_impl(x, generic_tag<true>()); 407#endif 408 (void)x; // warning supression. 409 return false; 410 } 411 412 template<class T> 413 inline bool isinf_impl(T x, ieee_copy_all_bits_tag const&) 414 { 415 typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits; 416 417 BOOST_DEDUCED_TYPENAME traits::bits a; 418 traits::get_bits(x,a); 419 a &= traits::exponent | traits::significand; 420 return a == traits::exponent; 421 } 422 423 template<class T> 424 inline bool isinf_impl(T x, ieee_copy_leading_bits_tag const&) 425 { 426 typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits; 427 428 BOOST_DEDUCED_TYPENAME traits::bits a; 429 traits::get_bits(x,a); 430 a &= traits::exponent | traits::significand; 431 if(a != traits::exponent) 432 return false; 433 434 traits::set_bits(x,0); 435 return x == 0; 436 } 437 438#if defined(BOOST_MATH_USE_STD_FPCLASSIFY) && defined(BOOST_MATH_NO_NATIVE_LONG_DOUBLE_FP_CLASSIFY) 439template <> 440inline bool isinf_impl<long double> BOOST_NO_MACRO_EXPAND(long double t, const native_tag&) 441{ 442 return boost::math::detail::isinf_impl(t, generic_tag<true>()); 443} 444#endif 445 446} // namespace detail 447 448template<class T> 449inline bool (isinf)(T x) 450{ 451 typedef typename detail::fp_traits<T>::type traits; 452 typedef typename traits::method method; 453 typedef typename boost::is_floating_point<T>::type fp_tag; 454 typedef typename tools::promote_args<T>::type value_type; 455 return detail::isinf_impl(static_cast<value_type>(x), method()); 456} 457 458//------------------------------------------------------------------------------ 459 460namespace detail { 461 462#ifdef BOOST_MATH_USE_STD_FPCLASSIFY 463 template<class T> 464 inline bool isnan_impl(T x, native_tag const&) 465 { 466 return (std::isnan)(x); 467 } 468#endif 469 470 template<class T> 471 inline bool isnan_impl(T x, generic_tag<true> const&) 472 { 473 return std::numeric_limits<T>::has_infinity 474 ? !(x <= std::numeric_limits<T>::infinity()) 475 : x != x; 476 } 477 478 template<class T> 479 inline bool isnan_impl(T x, generic_tag<false> const&) 480 { 481#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS 482 if(std::numeric_limits<T>::is_specialized) 483 return isnan_impl(x, generic_tag<true>()); 484#endif 485 (void)x; // warning supression 486 return false; 487 } 488 489 template<class T> 490 inline bool isnan_impl(T x, ieee_copy_all_bits_tag const&) 491 { 492 typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits; 493 494 BOOST_DEDUCED_TYPENAME traits::bits a; 495 traits::get_bits(x,a); 496 a &= traits::exponent | traits::significand; 497 return a > traits::exponent; 498 } 499 500 template<class T> 501 inline bool isnan_impl(T x, ieee_copy_leading_bits_tag const&) 502 { 503 typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits; 504 505 BOOST_DEDUCED_TYPENAME traits::bits a; 506 traits::get_bits(x,a); 507 508 a &= traits::exponent | traits::significand; 509 if(a < traits::exponent) 510 return false; 511 512 a &= traits::significand; 513 traits::set_bits(x,a); 514 return x != 0; 515 } 516 517} // namespace detail 518 519template<class T> bool (isnan)(T x) 520{ //!< \brief return true if floating-point type t is NaN (Not A Number). 521 typedef typename detail::fp_traits<T>::type traits; 522 typedef typename traits::method method; 523 typedef typename boost::is_floating_point<T>::type fp_tag; 524 return detail::isnan_impl(x, method()); 525} 526 527#ifdef isnan 528template <> inline bool isnan BOOST_NO_MACRO_EXPAND<float>(float t){ return ::boost::math_detail::is_nan_helper(t, boost::true_type()); } 529template <> inline bool isnan BOOST_NO_MACRO_EXPAND<double>(double t){ return ::boost::math_detail::is_nan_helper(t, boost::true_type()); } 530template <> inline bool isnan BOOST_NO_MACRO_EXPAND<long double>(long double t){ return ::boost::math_detail::is_nan_helper(t, boost::true_type()); } 531#endif 532 533} // namespace math 534} // namespace boost 535 536#endif // BOOST_MATH_FPCLASSIFY_HPP 537 538