I'm trying to print random float(32-bit) values. I tried using uniform_real_distribution
for this purpose. I wrote the following code,
int main()
{
std::random_device rd{};
std::mt19937 gen{rd()};
std::uniform_real_distribution<float> dist(-1e18,1e18);
float random_val = dist(gen);
printf("%.20f\n", random_val);
return 0;
}
Now, the output is strange. All I get is very big numbers (always near the upper or lower bound) with no fractions. Following are some of the outputs I saw,
-149399166081040384.00000000000000000000
128349565723082752.00000000000000000000
-323890424458510336.00000000000000000000
802221481969844224.00000000000000000000
817395979383734272.00000000000000000000
They are always like these, and it doesn't matter if I change the bounds. What is wrong here?
float
is usually IEEE Single-precision floating-point format, which works like scientific notation, which has 1 sign bit, 8 exponent bits, and 23+1 fraction bits.
So 817395979383734272.0 is stored as 1.41795599 * 2^59 in memory. That fractional part is only ~8 decimal digits, because that's all the precision it can squeeze into that ~24 bits. Mark Ransom reminds me that as a result, all float
s greater than ~100,000,000 will be integers, simply becauase they're's not enough bits to also store any fractional parts.
Since there's ~24 bits for the fractional part, that means it can hold 7.2 decimal digits of precision. So the first 7 decimal digits are accurate, the 8th decimal digit is semi-accurate, and subsequent decimal digits are practically random when rendering float
as text.
817395979383734272.0
^ ^^
| |basically random
| semi-accurate
accurate
For double
(using IEEE Double-precision floating-point format), it uses 1 sign bit, 11 exponent bits, and 52+1 fraction bits. This stores 15.9 decimal digits accurately, so can still hold fractional parts until values are greater than ~1,000,000,000,000,000.
David Shwartz also points out that it's common to assume that random floats will have some small numbers and some large numbers, but mathematically, almost all uniformly randomly generated floats will be within two magnitudes of the maximum. In your case, that's >1e16 and <-1e16. This is mathematically correct, but can also factor into your confusion.