General Utility Library for C++14  2.8
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 
86 template<typename NumT, typename OrderT,
87  typename = std::enable_if_t<
88  std::is_arithmetic<NumT>::value
89  and std::is_arithmetic<OrderT>::value
90  >>
91 bool within_orders(const NumT a, const NumT b, const OrderT orders) noexcept(false) {
92  // std::pow() is not noexcept, which might or might not be true
93  auto difference = gul14::abs(a - b);
94  if (difference == NumT{ 0 })
95  return true;
96  auto maximum = std::max(gul14::abs(a), gul14::abs(b));
97  auto limit = maximum / std::pow(static_cast<std::decay_t<NumT>>(10.0), orders);
98  return difference < limit;
99 }
100 
112 template<typename NumT>
113 bool within_abs(NumT a, NumT b, NumT tol) noexcept {
114  tol = gul14::abs(tol); // Negative diff does not make sense
115  bool ret{};
116  if (a > b) {
117  if (std::is_floating_point<NumT>::value)
118  ret = a - tol <= b; // different formula needed because of inf/-inf and subnormal values
119  else
120  ret = a - b <= tol;
121  } else {
122  if (std::is_floating_point<NumT>::value)
123  ret = b - tol <= a;
124  else
125  ret = b - a <= tol;
126  }
127  return ret;
128 }
129 
146 template<typename NumT,
147  typename = std::enable_if_t<std::is_floating_point<NumT>::value>>
148 bool within_ulp(NumT a, NumT b, unsigned int ulp)
149 {
150  if (a == b)
151  return true;
152  auto diff = std::abs(a - b);
153  auto maxval = std::max(std::abs(a), std::abs(b));
154 
155  // NORMAL cases
156  if (std::isnormal(maxval))
157  {
158  return diff <= std::numeric_limits<NumT>::epsilon()
159  * static_cast<NumT>(ulp) * maxval;
160  }
161 
162  // SUBNORMAL cases
163  if (std::isfinite(maxval))
164  return diff <= std::numeric_limits<NumT>::denorm_min() * static_cast<NumT>(ulp);
165 
166  // NAN and INF cases: Two NANs or (a xor b is (-)INF) or (INF, -INF pair)
167  return false;
168 }
169 
201 template<class NumT>
202 constexpr const NumT& clamp(const NumT& v, const NumT& lo, const NumT& hi) {
203  return std::max(lo, std::min(v, hi)); // usually more optimized than actually using operator<()
204 }
228 template<class NumT, class Compare>
229 constexpr const NumT& clamp(const NumT& v, const NumT& lo, const NumT& hi, Compare comp) {
230  if (comp(v, lo))
231  return lo;
232  if (comp(hi, v))
233  return hi;
234  return v;
235 }
236 
237 } // namespace gul14
238 
239 #endif
240 
241 // vi:ts=4:sw=4:et
Definition of macros used internally by GUL.
Namespace gul14 contains all functions and classes of the General Utility Library.
Definition: doxygen.h:26
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
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:113
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:148
auto maximum(ContainerT const &container, Accessor accessor=ElementAccessor< ElementT >()) -> DataT
Return the maximum element value in a container.
Definition: statistics.h:308
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:91
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:202