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)
6 #ifndef BOOST_MATH_RELATIVE_ERROR
7 #define BOOST_MATH_RELATIVE_ERROR
9 #include <boost/math/special_functions/fpclassify.hpp>
10 #include <boost/math/tools/promotion.hpp>
11 #include <boost/math/tools/precision.hpp>
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)
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;
23 #ifdef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
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:
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)()));
36 result_type min_val = tools::min_value<result_type>();
37 result_type max_val = tools::max_value<result_type>();
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))
42 // Screen out infinites:
46 return (a < 0) == (b < 0) ? 0 : max_val; // one infinity is as good as another!
48 return max_val; // one infinity and one finite value implies infinite difference
50 else if(fabs(a) > max_val)
51 return max_val; // one infinity and one finite value implies infinite difference
54 // If the values have different signs, treat as infinite difference:
56 if(((a < 0) != (b < 0)) && (a != 0) && (b != 0))
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:
69 return (std::max)(fabs((a - b) / a), fabs((a - b) / b));
72 #if defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
74 inline boost::math::tools::promote_args<double, double>::type relative_difference(const double& arg_a, const double& arg_b)
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:
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>());
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))
91 // Screen out infinites:
95 return 0; // one infinity is as good as another!
97 return max_val; // one infinity and one finite value implies infinite difference
99 else if(fabs(a) > max_val)
100 return max_val; // one infinity and one finite value implies infinite difference
103 // If the values have different signs, treat as infinite difference:
105 if(((a < 0) != (b < 0)) && (a != 0) && (b != 0))
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:
118 return (std::max)(fabs((a - b) / a), fabs((a - b) / b));
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)
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>();