2013/04/14

The trickery that is std::numeric_limits::min()

Pop quiz: what is wrong with the following C++ code:

#include <limits>
#include <algorithm>

template<typename T>
class MaxValue
{
 public:
  MaxValue():
   val(std::numeric_limits<T>::min())
  {
  }

  void operator()(const T& v)
  {
   val = std::max(val, v);
  }
 
  T get() const
  {
   return val; 
  }
 private:
  T val;
};

template<typename T>
class MinValue
{
 public:
  MinValue():
   val(std::numeric_limits<T>::max())
  {
  }

  void operator()(const T& v)
  {
   val = std::min(val, v);
  }
 
  T get() const
  {
   return val; 
  }
 private:
  T val;
};

It seems okay right, initialise to the lowest possible value (or highest) and then always take the maximum of the current value and the new value (or minimum). Well, enter the mess that is std::numeric_limits<T>::min(). The description on cplusplus.com reads as follows:

Minimum finite value.
For floating types with denormalization (variable number of exponent bits): minimum positive normalized value.

Read that again, it does say minimum positive (normalized) value. That's right, if you use double's numeric limits, the value min() returns is 2.22507e-308 on my machine, which is pretty close to zero. On the other hand, if you call the same function but with the also-signed int as template parameter, it returns the expected value of -2147483648. Who thought it was a good idea for a function called "min" to return something other than the minimum?

Instead of using min(), you should either use the lowest() function defined on the same class if you're lucky enough to be using C++11, or use minus std::numeric_limits<T>::max() and pray your underlying floating point type is symmetrical as not to cause an underflow...

No comments:

Post a Comment