blob: 4e8472425d9614cab467cdfd51fa43a1caf16104 [file] [log] [blame]
/* ----------------------------------------------------------------------- *//**
*
* @file Math.hpp
*
*//* ----------------------------------------------------------------------- */
#ifndef MADLIB_MATH_HPP
#define MADLIB_MATH_HPP
#include <boost/utility/enable_if.hpp>
#include <boost/math/special_functions/fpclassify.hpp>
namespace madlib {
namespace utils {
/**
* @brief Return the smallest power of 2 that is greater or equal to a number
*
* This implementation is for integers only.
*/
template <class T>
typename boost::enable_if_c<std::numeric_limits<T>::is_integer, T>::type
nextPowerOfTwo(T inValue) {
if (std::numeric_limits<T>::is_signed && inValue == 0)
return 1;
inValue--;
for (int i = 1; i < std::numeric_limits<T>::digits; i <<= 1)
// Note: No overflow can occur in the following line
inValue = static_cast<T>(inValue | (inValue >> i));
return static_cast<T>(inValue + 1);
}
/**
* @brief Return if two floating point numbers are almost equal.
*
* If either of \c inX or \c inY is infinity, the other value has to be infinity
* as well in order to be considered equal (irrespective of the units in the
* last place).
*/
template<class T>
typename boost::enable_if_c<!std::numeric_limits<T>::is_integer, bool>::type
almostEqual(T inX, T inY, int inULP) {
// The machine epsilon has to be scaled to the magnitude of the larger value
// and multiplied by the desired precision in ULPs (units in the last place)
return (
std::fabs(inX - inY)
<= std::numeric_limits<T>::epsilon()
* std::max(std::fabs(inX), std::fabs(inY))
* inULP
) || (
boost::math::isinf(inX) && boost::math::isinf(inY)
&& ((inX < 0) == (inY < 0))
);
}
/**
* @brief Test if value is negative
*
* This is the implementation for unsigned T. We use SFINAE because
* otherwise the compiler would warn that a comparison < 0 is always false
* for unsigned types.
*/
template <class T>
inline
typename boost::enable_if_c<
std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed,
bool
>::type
isNegative(const T&) {
return false;
}
template <class T>
inline
typename boost::enable_if_c<
!std::numeric_limits<T>::is_integer || std::numeric_limits<T>::is_signed,
bool
>::type
isNegative(const T& inValue) {
return inValue < static_cast<T>(0);
}
} // namespace utils
} // namespace regress
#endif