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 
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  // NORMAL cases
155  if (std::isnormal(maxval))
156  return diff <= std::numeric_limits<NumT>::epsilon() * (ulp * maxval);
157  // SUBNORMAL cases
158  if (std::isfinite(maxval))
159  return diff <= std::numeric_limits<NumT>::denorm_min() * ulp;
160  // NAN and INF cases: Two NANs or (a xor b is (-)INF) or (INF, -INF pair)
161  return false;
162 }
163 
195 template<class NumT>
196 constexpr const NumT& clamp(const NumT& v, const NumT& lo, const NumT& hi) {
197  return std::max(lo, std::min(v, hi)); // usually more optimized than actually using operator<()
198 }
222 template<class NumT, class Compare>
223 constexpr const NumT& clamp(const NumT& v, const NumT& lo, const NumT& hi, Compare comp) {
224  if (comp(v, lo))
225  return lo;
226  if (comp(hi, v))
227  return hi;
228  return v;
229 }
230 
231 } // namespace gul14
232 
233 #endif
234 
235 // 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:196