]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/math/special_functions/relative_difference.hpp
update sources to v12.2.3
[ceph.git] / ceph / src / boost / boost / math / special_functions / relative_difference.hpp
1 // (C) Copyright John Maddock 2006, 2015
2 // Use, modification and distribution are subject to the
3 // Boost Software License, Version 1.0. (See accompanying file
4 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5
6 #ifndef BOOST_MATH_RELATIVE_ERROR
7 #define BOOST_MATH_RELATIVE_ERROR
8
9 #include <boost/math/special_functions/fpclassify.hpp>
10 #include <boost/math/tools/promotion.hpp>
11 #include <boost/math/tools/precision.hpp>
12
13 namespace boost{
14 namespace math{
15
16 template <class T, class U>
17 typename boost::math::tools::promote_args<T,U>::type relative_difference(const T& arg_a, const U& arg_b)
18 {
19 typedef typename boost::math::tools::promote_args<T, U>::type result_type;
20 result_type a = arg_a;
21 result_type b = arg_b;
22 BOOST_MATH_STD_USING
23 #ifdef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
24 //
25 // If math.h has no long double support we can't rely
26 // on the math functions generating exponents outside
27 // the range of a double:
28 //
29 result_type min_val = (std::max)(
30 tools::min_value<result_type>(),
31 static_cast<result_type>((std::numeric_limits<double>::min)()));
32 result_type max_val = (std::min)(
33 tools::max_value<result_type>(),
34 static_cast<result_type>((std::numeric_limits<double>::max)()));
35 #else
36 result_type min_val = tools::min_value<result_type>();
37 result_type max_val = tools::max_value<result_type>();
38 #endif
39 // Screen out NaN's first, if either value is a NaN then the distance is "infinite":
40 if((boost::math::isnan)(a) || (boost::math::isnan)(b))
41 return max_val;
42 // Screen out infinites:
43 if(fabs(b) > max_val)
44 {
45 if(fabs(a) > max_val)
46 return (a < 0) == (b < 0) ? 0 : max_val; // one infinity is as good as another!
47 else
48 return max_val; // one infinity and one finite value implies infinite difference
49 }
50 else if(fabs(a) > max_val)
51 return max_val; // one infinity and one finite value implies infinite difference
52
53 //
54 // If the values have different signs, treat as infinite difference:
55 //
56 if(((a < 0) != (b < 0)) && (a != 0) && (b != 0))
57 return max_val;
58 a = fabs(a);
59 b = fabs(b);
60 //
61 // Now deal with zero's, if one value is zero (or denorm) then treat it the same as
62 // min_val for the purposes of the calculation that follows:
63 //
64 if(a < min_val)
65 a = min_val;
66 if(b < min_val)
67 b = min_val;
68
69 return (std::max)(fabs((a - b) / a), fabs((a - b) / b));
70 }
71
72 #if defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
73 template <>
74 inline boost::math::tools::promote_args<double, double>::type relative_difference(const double& arg_a, const double& arg_b)
75 {
76 BOOST_MATH_STD_USING
77 double a = arg_a;
78 double b = arg_b;
79 //
80 // On Mac OS X we evaluate "double" functions at "long double" precision,
81 // but "long double" actually has a very slightly narrower range than "double"!
82 // Therefore use the range of "long double" as our limits since results outside
83 // that range may have been truncated to 0 or INF:
84 //
85 double min_val = (std::max)((double)tools::min_value<long double>(), tools::min_value<double>());
86 double max_val = (std::min)((double)tools::max_value<long double>(), tools::max_value<double>());
87
88 // Screen out NaN's first, if either value is a NaN then the distance is "infinite":
89 if((boost::math::isnan)(a) || (boost::math::isnan)(b))
90 return max_val;
91 // Screen out infinites:
92 if(fabs(b) > max_val)
93 {
94 if(fabs(a) > max_val)
95 return 0; // one infinity is as good as another!
96 else
97 return max_val; // one infinity and one finite value implies infinite difference
98 }
99 else if(fabs(a) > max_val)
100 return max_val; // one infinity and one finite value implies infinite difference
101
102 //
103 // If the values have different signs, treat as infinite difference:
104 //
105 if(((a < 0) != (b < 0)) && (a != 0) && (b != 0))
106 return max_val;
107 a = fabs(a);
108 b = fabs(b);
109 //
110 // Now deal with zero's, if one value is zero (or denorm) then treat it the same as
111 // min_val for the purposes of the calculation that follows:
112 //
113 if(a < min_val)
114 a = min_val;
115 if(b < min_val)
116 b = min_val;
117
118 return (std::max)(fabs((a - b) / a), fabs((a - b) / b));
119 }
120 #endif
121
122 template <class T, class U>
123 inline typename boost::math::tools::promote_args<T, U>::type epsilon_difference(const T& arg_a, const U& arg_b)
124 {
125 typedef typename boost::math::tools::promote_args<T, U>::type result_type;
126 result_type r = relative_difference(arg_a, arg_b);
127 if(tools::max_value<result_type>() * boost::math::tools::epsilon<result_type>() < r)
128 return tools::max_value<result_type>();
129 return r / boost::math::tools::epsilon<result_type>();
130 }
131 } // namespace math
132 } // namespace boost
133
134 #endif