Reputation: 183
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.
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.
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
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
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
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 int
s differ by exactly one.
So if both your min
and max
are of the same sign, then you can convert them to int
s 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