blob: 0eeea57e844c9cc13f2f69efc2d6f260a18c5199 [file] [log] [blame]
Jeff Thompsonef2d5a42013-08-22 19:09:24 -07001// 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 <ndnboost/config/no_tr1/cmath.hpp>
16#include <ndnboost/limits.hpp>
17#include <ndnboost/math/tools/real_cast.hpp>
18#include <ndnboost/type_traits/is_floating_point.hpp>
19#include <ndnboost/math/special_functions/math_fwd.hpp>
20#include <ndnboost/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 ndnboost{
89
90//
91// This must not be located in any namespace under ndnboost::math
92// otherwise we can get into an infinite loop if isnan is
93// a #define for "isnan" !
94//
95namespace math_detail{
96
97#ifdef BOOST_MSVC
98#pragma warning(push)
99#pragma warning(disable:4800)
100#endif
101
102template <class T>
103inline bool is_nan_helper(T t, const ndnboost::true_type&)
104{
105#ifdef isnan
106 return isnan(t);
107#elif defined(BOOST_MATH_DISABLE_STD_FPCLASSIFY) || !defined(BOOST_HAS_FPCLASSIFY)
108 (void)t;
109 return false;
110#else // BOOST_HAS_FPCLASSIFY
111 return (BOOST_FPCLASSIFY_PREFIX fpclassify(t) == (int)FP_NAN);
112#endif
113}
114
115#ifdef BOOST_MSVC
116#pragma warning(pop)
117#endif
118
119template <class T>
120inline bool is_nan_helper(T, const ndnboost::false_type&)
121{
122 return false;
123}
124
125}
126
127namespace math{
128
129namespace detail{
130
131#ifdef BOOST_MATH_USE_STD_FPCLASSIFY
132template <class T>
133inline int fpclassify_imp BOOST_NO_MACRO_EXPAND(T t, const native_tag&)
134{
135 return (std::fpclassify)(t);
136}
137#endif
138
139template <class T>
140inline int fpclassify_imp BOOST_NO_MACRO_EXPAND(T t, const generic_tag<true>&)
141{
142 BOOST_MATH_INSTRUMENT_VARIABLE(t);
143
144 // whenever possible check for Nan's first:
145#if defined(BOOST_HAS_FPCLASSIFY) && !defined(BOOST_MATH_DISABLE_STD_FPCLASSIFY)
146 if(::ndnboost::math_detail::is_nan_helper(t, ::ndnboost::is_floating_point<T>()))
147 return FP_NAN;
148#elif defined(isnan)
149 if(ndnboost::math_detail::is_nan_helper(t, ::ndnboost::is_floating_point<T>()))
150 return FP_NAN;
151#elif defined(_MSC_VER) || defined(__BORLANDC__)
152 if(::_isnan(ndnboost::math::tools::real_cast<double>(t)))
153 return FP_NAN;
154#endif
155 // std::fabs broken on a few systems especially for long long!!!!
156 T at = (t < T(0)) ? -t : t;
157
158 // Use a process of exclusion to figure out
159 // what kind of type we have, this relies on
160 // IEEE conforming reals that will treat
161 // Nan's as unordered. Some compilers
162 // don't do this once optimisations are
163 // turned on, hence the check for nan's above.
164 if(at <= (std::numeric_limits<T>::max)())
165 {
166 if(at >= (std::numeric_limits<T>::min)())
167 return FP_NORMAL;
168 return (at != 0) ? FP_SUBNORMAL : FP_ZERO;
169 }
170 else if(at > (std::numeric_limits<T>::max)())
171 return FP_INFINITE;
172 return FP_NAN;
173}
174
175template <class T>
176inline int fpclassify_imp BOOST_NO_MACRO_EXPAND(T t, const generic_tag<false>&)
177{
178#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
179 if(std::numeric_limits<T>::is_specialized)
180 return fpclassify_imp(t, generic_tag<true>());
181#endif
182 //
183 // An unknown type with no numeric_limits support,
184 // so what are we supposed to do we do here?
185 //
186 BOOST_MATH_INSTRUMENT_VARIABLE(t);
187
188 return t == 0 ? FP_ZERO : FP_NORMAL;
189}
190
191template<class T>
192int fpclassify_imp BOOST_NO_MACRO_EXPAND(T x, ieee_copy_all_bits_tag)
193{
194 typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
195
196 BOOST_MATH_INSTRUMENT_VARIABLE(x);
197
198 BOOST_DEDUCED_TYPENAME traits::bits a;
199 traits::get_bits(x,a);
200 BOOST_MATH_INSTRUMENT_VARIABLE(a);
201 a &= traits::exponent | traits::flag | traits::significand;
202 BOOST_MATH_INSTRUMENT_VARIABLE((traits::exponent | traits::flag | traits::significand));
203 BOOST_MATH_INSTRUMENT_VARIABLE(a);
204
205 if(a <= traits::significand) {
206 if(a == 0)
207 return FP_ZERO;
208 else
209 return FP_SUBNORMAL;
210 }
211
212 if(a < traits::exponent) return FP_NORMAL;
213
214 a &= traits::significand;
215 if(a == 0) return FP_INFINITE;
216
217 return FP_NAN;
218}
219
220template<class T>
221int fpclassify_imp BOOST_NO_MACRO_EXPAND(T x, ieee_copy_leading_bits_tag)
222{
223 typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
224
225 BOOST_MATH_INSTRUMENT_VARIABLE(x);
226
227 BOOST_DEDUCED_TYPENAME traits::bits a;
228 traits::get_bits(x,a);
229 a &= traits::exponent | traits::flag | traits::significand;
230
231 if(a <= traits::significand) {
232 if(x == 0)
233 return FP_ZERO;
234 else
235 return FP_SUBNORMAL;
236 }
237
238 if(a < traits::exponent) return FP_NORMAL;
239
240 a &= traits::significand;
241 traits::set_bits(x,a);
242 if(x == 0) return FP_INFINITE;
243
244 return FP_NAN;
245}
246
247#if defined(BOOST_MATH_USE_STD_FPCLASSIFY) && (defined(BOOST_MATH_NO_NATIVE_LONG_DOUBLE_FP_CLASSIFY) || defined(BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS))
248inline int fpclassify_imp BOOST_NO_MACRO_EXPAND(long double t, const native_tag&)
249{
250 return ndnboost::math::detail::fpclassify_imp(t, generic_tag<true>());
251}
252#endif
253
254} // namespace detail
255
256template <class T>
257inline int fpclassify BOOST_NO_MACRO_EXPAND(T t)
258{
259 typedef typename detail::fp_traits<T>::type traits;
260 typedef typename traits::method method;
261 typedef typename tools::promote_args<T>::type value_type;
262#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
263 if(std::numeric_limits<T>::is_specialized && detail::is_generic_tag_false(static_cast<method*>(0)))
264 return detail::fpclassify_imp(static_cast<value_type>(t), detail::generic_tag<true>());
265 return detail::fpclassify_imp(static_cast<value_type>(t), method());
266#else
267 return detail::fpclassify_imp(static_cast<value_type>(t), method());
268#endif
269}
270
271#ifdef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
272template <>
273inline int fpclassify<long double> BOOST_NO_MACRO_EXPAND(long double t)
274{
275 typedef detail::fp_traits<long double>::type traits;
276 typedef traits::method method;
277 typedef long double value_type;
278#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
279 if(std::numeric_limits<long double>::is_specialized && detail::is_generic_tag_false(static_cast<method*>(0)))
280 return detail::fpclassify_imp(static_cast<value_type>(t), detail::generic_tag<true>());
281 return detail::fpclassify_imp(static_cast<value_type>(t), method());
282#else
283 return detail::fpclassify_imp(static_cast<value_type>(t), method());
284#endif
285}
286#endif
287
288namespace detail {
289
290#ifdef BOOST_MATH_USE_STD_FPCLASSIFY
291 template<class T>
292 inline bool isfinite_impl(T x, native_tag const&)
293 {
294 return (std::isfinite)(x);
295 }
296#endif
297
298 template<class T>
299 inline bool isfinite_impl(T x, generic_tag<true> const&)
300 {
301 return x >= -(std::numeric_limits<T>::max)()
302 && x <= (std::numeric_limits<T>::max)();
303 }
304
305 template<class T>
306 inline bool isfinite_impl(T x, generic_tag<false> const&)
307 {
308#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
309 if(std::numeric_limits<T>::is_specialized)
310 return isfinite_impl(x, generic_tag<true>());
311#endif
312 (void)x; // warning supression.
313 return true;
314 }
315
316 template<class T>
317 inline bool isfinite_impl(T x, ieee_tag const&)
318 {
319 typedef BOOST_DEDUCED_TYPENAME detail::fp_traits<T>::type traits;
320 BOOST_DEDUCED_TYPENAME traits::bits a;
321 traits::get_bits(x,a);
322 a &= traits::exponent;
323 return a != traits::exponent;
324 }
325
326#if defined(BOOST_MATH_USE_STD_FPCLASSIFY) && defined(BOOST_MATH_NO_NATIVE_LONG_DOUBLE_FP_CLASSIFY)
327inline bool isfinite_impl BOOST_NO_MACRO_EXPAND(long double t, const native_tag&)
328{
329 return ndnboost::math::detail::isfinite_impl(t, generic_tag<true>());
330}
331#endif
332
333}
334
335template<class T>
336inline bool (isfinite)(T x)
337{ //!< \brief return true if floating-point type t is finite.
338 typedef typename detail::fp_traits<T>::type traits;
339 typedef typename traits::method method;
340 // typedef typename ndnboost::is_floating_point<T>::type fp_tag;
341 typedef typename tools::promote_args<T>::type value_type;
342 return detail::isfinite_impl(static_cast<value_type>(x), method());
343}
344
345#ifdef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
346template<>
347inline bool (isfinite)(long double x)
348{ //!< \brief return true if floating-point type t is finite.
349 typedef detail::fp_traits<long double>::type traits;
350 typedef traits::method method;
351 typedef ndnboost::is_floating_point<long double>::type fp_tag;
352 typedef long double value_type;
353 return detail::isfinite_impl(static_cast<value_type>(x), method());
354}
355#endif
356
357//------------------------------------------------------------------------------
358
359namespace detail {
360
361#ifdef BOOST_MATH_USE_STD_FPCLASSIFY
362 template<class T>
363 inline bool isnormal_impl(T x, native_tag const&)
364 {
365 return (std::isnormal)(x);
366 }
367#endif
368
369 template<class T>
370 inline bool isnormal_impl(T x, generic_tag<true> const&)
371 {
372 if(x < 0) x = -x;
373 return x >= (std::numeric_limits<T>::min)()
374 && x <= (std::numeric_limits<T>::max)();
375 }
376
377 template<class T>
378 inline bool isnormal_impl(T x, generic_tag<false> const&)
379 {
380#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
381 if(std::numeric_limits<T>::is_specialized)
382 return isnormal_impl(x, generic_tag<true>());
383#endif
384 return !(x == 0);
385 }
386
387 template<class T>
388 inline bool isnormal_impl(T x, ieee_tag const&)
389 {
390 typedef BOOST_DEDUCED_TYPENAME detail::fp_traits<T>::type traits;
391 BOOST_DEDUCED_TYPENAME traits::bits a;
392 traits::get_bits(x,a);
393 a &= traits::exponent | traits::flag;
394 return (a != 0) && (a < traits::exponent);
395 }
396
397#if defined(BOOST_MATH_USE_STD_FPCLASSIFY) && defined(BOOST_MATH_NO_NATIVE_LONG_DOUBLE_FP_CLASSIFY)
398inline bool isnormal_impl BOOST_NO_MACRO_EXPAND(long double t, const native_tag&)
399{
400 return ndnboost::math::detail::isnormal_impl(t, generic_tag<true>());
401}
402#endif
403
404}
405
406template<class T>
407inline bool (isnormal)(T x)
408{
409 typedef typename detail::fp_traits<T>::type traits;
410 typedef typename traits::method method;
411 //typedef typename ndnboost::is_floating_point<T>::type fp_tag;
412 typedef typename tools::promote_args<T>::type value_type;
413 return detail::isnormal_impl(static_cast<value_type>(x), method());
414}
415
416#ifdef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
417template<>
418inline bool (isnormal)(long double x)
419{
420 typedef detail::fp_traits<long double>::type traits;
421 typedef traits::method method;
422 typedef ndnboost::is_floating_point<long double>::type fp_tag;
423 typedef long double value_type;
424 return detail::isnormal_impl(static_cast<value_type>(x), method());
425}
426#endif
427
428//------------------------------------------------------------------------------
429
430namespace detail {
431
432#ifdef BOOST_MATH_USE_STD_FPCLASSIFY
433 template<class T>
434 inline bool isinf_impl(T x, native_tag const&)
435 {
436 return (std::isinf)(x);
437 }
438#endif
439
440 template<class T>
441 inline bool isinf_impl(T x, generic_tag<true> const&)
442 {
443 (void)x; // in case the compiler thinks that x is unused because std::numeric_limits<T>::has_infinity is false
444 return std::numeric_limits<T>::has_infinity
445 && ( x == std::numeric_limits<T>::infinity()
446 || x == -std::numeric_limits<T>::infinity());
447 }
448
449 template<class T>
450 inline bool isinf_impl(T x, generic_tag<false> const&)
451 {
452#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
453 if(std::numeric_limits<T>::is_specialized)
454 return isinf_impl(x, generic_tag<true>());
455#endif
456 (void)x; // warning supression.
457 return false;
458 }
459
460 template<class T>
461 inline bool isinf_impl(T x, ieee_copy_all_bits_tag const&)
462 {
463 typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
464
465 BOOST_DEDUCED_TYPENAME traits::bits a;
466 traits::get_bits(x,a);
467 a &= traits::exponent | traits::significand;
468 return a == traits::exponent;
469 }
470
471 template<class T>
472 inline bool isinf_impl(T x, ieee_copy_leading_bits_tag const&)
473 {
474 typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
475
476 BOOST_DEDUCED_TYPENAME traits::bits a;
477 traits::get_bits(x,a);
478 a &= traits::exponent | traits::significand;
479 if(a != traits::exponent)
480 return false;
481
482 traits::set_bits(x,0);
483 return x == 0;
484 }
485
486#if defined(BOOST_MATH_USE_STD_FPCLASSIFY) && defined(BOOST_MATH_NO_NATIVE_LONG_DOUBLE_FP_CLASSIFY)
487inline bool isinf_impl BOOST_NO_MACRO_EXPAND(long double t, const native_tag&)
488{
489 return ndnboost::math::detail::isinf_impl(t, generic_tag<true>());
490}
491#endif
492
493} // namespace detail
494
495template<class T>
496inline bool (isinf)(T x)
497{
498 typedef typename detail::fp_traits<T>::type traits;
499 typedef typename traits::method method;
500 // typedef typename ndnboost::is_floating_point<T>::type fp_tag;
501 typedef typename tools::promote_args<T>::type value_type;
502 return detail::isinf_impl(static_cast<value_type>(x), method());
503}
504
505#ifdef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
506template<>
507inline bool (isinf)(long double x)
508{
509 typedef detail::fp_traits<long double>::type traits;
510 typedef traits::method method;
511 typedef ndnboost::is_floating_point<long double>::type fp_tag;
512 typedef long double value_type;
513 return detail::isinf_impl(static_cast<value_type>(x), method());
514}
515#endif
516
517//------------------------------------------------------------------------------
518
519namespace detail {
520
521#ifdef BOOST_MATH_USE_STD_FPCLASSIFY
522 template<class T>
523 inline bool isnan_impl(T x, native_tag const&)
524 {
525 return (std::isnan)(x);
526 }
527#endif
528
529 template<class T>
530 inline bool isnan_impl(T x, generic_tag<true> const&)
531 {
532 return std::numeric_limits<T>::has_infinity
533 ? !(x <= std::numeric_limits<T>::infinity())
534 : x != x;
535 }
536
537 template<class T>
538 inline bool isnan_impl(T x, generic_tag<false> const&)
539 {
540#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
541 if(std::numeric_limits<T>::is_specialized)
542 return isnan_impl(x, generic_tag<true>());
543#endif
544 (void)x; // warning supression
545 return false;
546 }
547
548 template<class T>
549 inline bool isnan_impl(T x, ieee_copy_all_bits_tag const&)
550 {
551 typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
552
553 BOOST_DEDUCED_TYPENAME traits::bits a;
554 traits::get_bits(x,a);
555 a &= traits::exponent | traits::significand;
556 return a > traits::exponent;
557 }
558
559 template<class T>
560 inline bool isnan_impl(T x, ieee_copy_leading_bits_tag const&)
561 {
562 typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
563
564 BOOST_DEDUCED_TYPENAME traits::bits a;
565 traits::get_bits(x,a);
566
567 a &= traits::exponent | traits::significand;
568 if(a < traits::exponent)
569 return false;
570
571 a &= traits::significand;
572 traits::set_bits(x,a);
573 return x != 0;
574 }
575
576} // namespace detail
577
578template<class T>
579inline bool (isnan)(T x)
580{ //!< \brief return true if floating-point type t is NaN (Not A Number).
581 typedef typename detail::fp_traits<T>::type traits;
582 typedef typename traits::method method;
583 // typedef typename ndnboost::is_floating_point<T>::type fp_tag;
584 return detail::isnan_impl(x, method());
585}
586
587#ifdef isnan
588template <> inline bool isnan BOOST_NO_MACRO_EXPAND<float>(float t){ return ::ndnboost::math_detail::is_nan_helper(t, ndnboost::true_type()); }
589template <> inline bool isnan BOOST_NO_MACRO_EXPAND<double>(double t){ return ::ndnboost::math_detail::is_nan_helper(t, ndnboost::true_type()); }
590template <> inline bool isnan BOOST_NO_MACRO_EXPAND<long double>(long double t){ return ::ndnboost::math_detail::is_nan_helper(t, ndnboost::true_type()); }
591#elif defined(BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS)
592template<>
593inline bool (isnan)(long double x)
594{ //!< \brief return true if floating-point type t is NaN (Not A Number).
595 typedef detail::fp_traits<long double>::type traits;
596 typedef traits::method method;
597 typedef ndnboost::is_floating_point<long double>::type fp_tag;
598 return detail::isnan_impl(x, method());
599}
600#endif
601
602} // namespace math
603} // namespace ndnboost
604
605#endif // BOOST_MATH_FPCLASSIFY_HPP
606