#ifndef VTR_MATH_H #define VTR_MATH_H #include #include #include "vtr_assert.h" namespace vtr { /*********************** Math operations *************************************/ int ipow(int base, int exp); template Y linear_interpolate_or_extrapolate(const std::map* xy_map, X requested_x); constexpr int nint(float val) { return static_cast(val + 0.5); } //Returns a 'safe' ratio which evaluates to zero if the denominator is zero template T safe_ratio(T numerator, T denominator) { if (denominator == T(0)) { return 0; } return numerator / denominator; } template double median(InputIterator first, InputIterator last) { auto len = std::distance(first, last); auto iter = first + len / 2; if (len % 2 == 0) { return (*iter + *(iter + 1)) / 2; } else { return *iter; } } template double median(Container c) { return median(std::begin(c), std::end(c)); } template double geomean(InputIterator first, InputIterator last, double init = 1.) { //Compute the geometric mean of the elments in range [first, last) // //To avoid potential round-off issues we transform the standard formula: // // geomean = ( v_1 * v_2 * ... * v_n) ^ (1/n) // //by taking the log: // // geomean = exp( (1 / n) * (log(v_1) + log(v_2) + ... + log(v_n))) double log_sum = std::log(init); size_t n = 0; for (auto iter = first; iter != last; ++iter) { log_sum += std::log(*iter); n += 1; } VTR_ASSERT(n > 0.); return std::exp((1. / n) * log_sum); } template double geomean(Container c) { return geomean(std::begin(c), std::end(c)); } template double arithmean(InputIterator first, InputIterator last, double init = 0.) { double sum = init; size_t n = 0; for (auto iter = first; iter != last; ++iter) { sum += *iter; n += 1; } VTR_ASSERT(n > 0.); return sum / n; } template double arithmean(Container c) { return arithmean(std::begin(c), std::end(c)); } //Return the greatest common divisor of x and y // Note that T should be an integral type template static T gcd(T x, T y) { static_assert(std::is_integral::value, "T must be integral"); //Euclidean algorithm if (y == 0) { return x; } return gcd(y, x % y); } //Return the least common multiple of x and y // Note that T should be an integral type template T lcm(T x, T y) { static_assert(std::is_integral::value, "T must be integral"); if (x == 0 && y == 0) { return 0; } else { return (x / gcd(x, y)) * y; } } constexpr double DEFAULT_REL_TOL = 1e-9; constexpr double DEFAULT_ABS_TOL = 0; template bool isclose(T a, T b, T rel_tol, T abs_tol) { if (std::isinf(a) && std::isinf(b)) return (std::signbit(a) == std::signbit(b)); if (std::isnan(a) && std::isnan(b)) return false; T abs_largest = std::max(std::abs(a), std::abs(b)); return std::abs(a - b) <= std::max(rel_tol * abs_largest, abs_tol); } template bool isclose(T a, T b) { return isclose(a, b, DEFAULT_REL_TOL, DEFAULT_ABS_TOL); } } // namespace vtr #endif