rava
rava

Reputation: 183

How to enumerate all floating point values in between min and max

for an efficient random number generator for unique floating point values I'd like to know more about floating point values. I'm going to split my question in two parts.

  1. How do I find out how many floats lie in between min and max (including both)?

I'm looking for a implementation of the method:

size_t numOfFloats(const float min, const float max);

Which considers all possible float values given the maximum precision of the data type.

  1. How do I enumerate all possible float values in between min and max (including both)?

I'm looking for a implementation of the method:

vector<float> enumAllFloats(const float min, const float max);

The size of the vector returned shall always be equal to the return value of the method my first question.

C++11 is allowed if required.

Upvotes: 2

Views: 755

Answers (3)

johan d
johan d

Reputation: 2863

You can use the ieee754 representation of floats to map them to int. Then, do the maths with ints.

Note that the following code is not adapted to negative numbers, and do not take into account special floats values (NaN, infinities...)

size_t numOfFloats(const float min, const float max){
    // assert 0 <= min <= max
    // assert sizeof(float) == sizeof(int32_t)
    const int32_t min_i = *reinterpret_cast<const int32_t*>(&min);
    const int32_t max_i = *reinterpret_cast<const int32_t*>(&max);
    return max_i-min_i+1;
}

Also, you can easily list them when you know the mapping with ints:

void print_successive_floats(const float min, const float max){
    const int32_t min_i = *reinterpret_cast<const int32_t*>(&min);
    const int32_t max_i = *reinterpret_cast<const int32_t*>(&max);
    for(int32_t i = min_i; i<=max_i; ++i){
        float f = *reinterpret_cast<float*>(&i);
        std::cout << f << std::endl;
    }
}

For completeness, in order to match your API:

vector<float> enumAllFloats(const float min, const float max){
    vector<float> out;
    out.reserve(numOfFloats(min, max));
    const int32_t min_i = *reinterpret_cast<const int32_t*>(&min);
    const int32_t max_i = *reinterpret_cast<const int32_t*>(&max);
    for(int32_t i = min_i; i<=max_i; ++i){
        float f = *reinterpret_cast<float*>(&i);
        out.push_back(f);
    }
    return out;
}

Beware of huge vectors =)

Upvotes: 4

stgatilov
stgatilov

Reputation: 5533

You can use nextafterf to enumerate all representable floats:

vector<float> enumAllFloats(const float tmin, const float tmax) {
  vector<float> res;
  for (float x = tmin; x < tmax; x = nextafterf(x, tmax))
    res.push_back(x);
  res.push_back(tmax);
  return res;
}

Upvotes: 9

Petr
Petr

Reputation: 9997

I assume your target architecture uses the standard IEEE representation for floats (IEEE754, if I am not mistaken).

One of properties of this representations is that adjacent floats of the same sign have adjacent representations, that is if you treat the (32-bit) binary representation of some float as a (32-bit) int, that adjacent floats of the same sign will have the corresponding ints differ by exactly one.

So if both your min and max are of the same sign, then you can convert them to ints and then do a simple loop.

Something like (code adapted from here, which I also suggest as a source for more information):

/* See
https://randomascii.wordpress.com/2012/01/11/tricks-with-the-floating-point-format/
for the potential portability problems with the union and bit-fields below.
*/
union Float_t
{
    int32_t i;
    float f;
};

vector<float> enumAllFloats(const float min, const float max) {
    std::vector<float> result;
    Float_t fl;
    fl.f = min;
    result.push_back(fl.f);
    for (; fl.f <= max; fl.i++)
        result.push_back(fl.f);
    return result;
}

If min and max can have different signs, you will have to loop separately over positive and negative parts of the range. Also, maybe you will have to swap min and max for the code above if both are negative.


However, if you indeed want to use it for RNG, be careful, because those floats will not be distributed evenly in the [min, max] range.

Upvotes: 3

Related Questions