General Utility Library for C++14  2.7
num_util.h
Go to the documentation of this file.
1 
23 #ifndef GUL14_NUM_UTIL_H_
24 #define GUL14_NUM_UTIL_H_
25 
26 #include <algorithm>
27 #include <cmath>
28 #include <limits>
29 #include <type_traits>
30 
31 #include "gul14/internal.h"
32 
33 namespace gul14 {
34 
46 template<typename ValueT>
47 constexpr auto abs(ValueT n) noexcept -> std::enable_if_t<std::is_unsigned<ValueT>::value, ValueT>
48 {
49  return n;
50 }
51 
55 template<typename ValueT>
56 constexpr auto abs(ValueT n) noexcept -> std::enable_if_t<not std::is_unsigned<ValueT>::value, ValueT>
57 {
58  return std::abs(n);
59 }
60 
85 template<typename NumT, typename OrderT,
86  typename = std::enable_if_t<
87  std::is_arithmetic<NumT>::value
88  and std::is_arithmetic<OrderT>::value
89  >>
90 bool within_orders(const NumT a, const NumT b, const OrderT orders) noexcept(false) {
91  // std::pow() is not noexcept, which might or might not be true
92  return gul14::abs(a - b)
93  < (std::max(gul14::abs(a), gul14::abs(b)) / std::pow(static_cast<std::decay_t<NumT>>(10.0), orders));
94 }
95 
107 template<typename NumT>
108 bool within_abs(NumT a, NumT b, NumT tol) noexcept {
109  tol = gul14::abs(tol); // Negative diff does not make sense
110  bool ret{};
111  if (a > b) {
112  if (std::is_floating_point<NumT>::value)
113  ret = a - tol <= b; // different formula needed because of inf/-inf and subnormal values
114  else
115  ret = a - b <= tol;
116  } else {
117  if (std::is_floating_point<NumT>::value)
118  ret = b - tol <= a;
119  else
120  ret = b - a <= tol;
121  }
122  return ret;
123 }
124 
141 template<typename NumT,
142  typename = std::enable_if_t<std::is_floating_point<NumT>::value>>
143 bool within_ulp(NumT a, NumT b, unsigned int ulp)
144 {
145  if (a == b)
146  return true;
147  auto diff = std::abs(a - b);
148  auto maxval = std::max(std::abs(a), std::abs(b));
149  // NORMAL cases
150  if (std::isnormal(maxval))
151  return diff <= std::numeric_limits<NumT>::epsilon() * (ulp * maxval);
152  // SUBNORMAL cases
153  if (std::isfinite(maxval))
154  return diff <= std::numeric_limits<NumT>::denorm_min() * ulp;
155  // NAN and INF cases: Two NANs or (a xor b is (-)INF) or (INF, -INF pair)
156  return false;
157 }
158 
190 template<class NumT>
191 constexpr const NumT& clamp(const NumT& v, const NumT& lo, const NumT& hi) {
192  return std::max(lo, std::min(v, hi)); // usually more optimized than actually using operator<()
193 }
217 template<class NumT, class Compare>
218 constexpr const NumT& clamp(const NumT& v, const NumT& lo, const NumT& hi, Compare comp) {
219  if (comp(v, lo))
220  return lo;
221  if (comp(hi, v))
222  return hi;
223  return v;
224 }
225 
226 } // namespace gul14
227 
228 #endif
229 
230 // vi:ts=4:sw=4:et
gul14::abs
constexpr auto abs(ValueT n) noexcept -> std::enable_if_t< std::is_unsigned< ValueT >::value, ValueT >
Compute the absolute value of a number.
Definition: num_util.h:47
gul14::clamp
constexpr const NumT & clamp(const NumT &v, const NumT &lo, const NumT &hi)
Coerce a value to be within a given range.
Definition: num_util.h:191
gul14::within_ulp
bool within_ulp(NumT a, NumT b, unsigned int ulp)
Determine if two numbers are almost equal, allowing for a difference of a given number of units-in-th...
Definition: num_util.h:143
gul14::within_abs
bool within_abs(NumT a, NumT b, NumT tol) noexcept
Determine if two numbers are almost equal, allowing for an absolute difference.
Definition: num_util.h:108
internal.h
Definition of macros used internally by GUL.
gul14
Namespace gul14 contains all functions and classes of the General Utility Library.
Definition: doxygen.h:26
gul14::within_orders
bool within_orders(const NumT a, const NumT b, const OrderT orders) noexcept(false)
Determine if two numbers are almost equal, comparing only some significant digits.
Definition: num_util.h:90