Question

I am trying to use a template in VS2010 for random number creation based on type. I am using the code below:

template<class BaseT>
struct distribution
{ // general case, assuming T is of integral type
    typedef std::tr1::uniform_int<BaseT> dist_type;
};

template<>
struct distribution<float>
{ // float case
    typedef std::tr1::uniform_real<float> dist_type;
};

template<>
struct distribution<double>
{ // double case
    typedef std::tr1::uniform_real_distribution<double> dist_type;
};

template<class BaseT>
class BaseTypeRandomizer
{
public:
    BaseTypeRandomizer() : mEngine(std::time(0))
    {
    }
    void CreateValues(std::vector<BaseT>& Values, size_t nValues)
    {
        typedef typename distribution<BaseT>::dist_type distro_type;
        std::random_device Engine;
        distro_type dist(std::numeric_limits<BaseT>::min(), std::numeric_limits<BaseT>::max());

        for (size_t iVal = 0; iVal < nValues; ++iVal)
        {
            Values[iVal] = dist(Engine);
        }
    }
};

Unfortunately, creating objects of BaseTypeRandomizer for char/int/long etc. (integral types) returns numbers that cover the entire range, but for floats and doubles they don't. Floats all come between 1e+37 to 9e+38, and doubles are 1e+307 to 2e+308 (or at least all are in that neighborhood). Checking the dist object in the VS debugger shows the limits there are correct, but the Values vector gets filled with a much smaller range of numbers.

Does anyone have an idea on why are the limits not working correctly?

Was it helpful?

Solution

You are generating a value between numeric_limits<T>::min() and numeric_limits<T>::max(). But numeric_limits<T>::min() is probably not what you expect it to be: For floating-point types, it is the minimum positive normalized value, which is very close to zero. So your code can only get positive floating-point numbers. For float, this would be numbers up to about 3.4e38. The vast majority of these numbers are more than 1e37, so it makes sense that those are most of the results you get.

To get possible finite values, you'd need to use the range from numeric_limits<T>::lowest() to numeric_limits<T>::max(). But this would lead to undefined behavior because the size of the range passed to uniform_real_distribution must be up to numeric_limits<RealType>::max().

So you'd need to generate the number in a different way. For example, you can generate a non-negative number between 0 and numeric_limits<T>::max(), and generate its sign separately.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top