https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82554

            Bug ID: 82554
           Summary: uniform_real_distribution can generate the upper
                    endpoint
           Product: gcc
           Version: 8.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: libstdc++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: b.r.longbons at gmail dot com
  Target Milestone: ---

This is related to #64351 and #63176, for which a totally-bogus fix was
applied.

There is actually a defect in the standard: it requires `generate_canonical` to
return at *least* `bits` (e.g. 53), but correct operation is only possible when
it generates *exactly* `bits` since floating-point math rounds rather than
truncating like integer math.

Furthermore, when `std::uniform_real_distribution`'s parameters have different
exponents, the difference must be *subtracted* from the number of bits
requested (not possible since `bits` is only a template parameter).

I have not considered *all* the details when uniform_real_distribution crosses
0 or its parameters are not exact powers of 2, but the principle of requesting
less-than-53 bits certainly still applies.

Consider the following horrible, but valid RNG (for easy testing):

#include <iomanip>
#include <iostream>
#include <limits>
#include <random>


int main()
{
    // seed with -2 instead of -1 because it returns the post-advance state
    // produces -1, 0, 1, 2, ...
    std::linear_congruential_engine<uint64_t, 1, 1, 0> engine(-2ULL);

    std::cout << std::setprecision(std::numeric_limits<double>::max_digits10);

    std::uniform_real_distribution<double> dist(1.0, 2.0);

    for (int i = 0; i < 2; ++i)
        std::cout << dist(engine) << std::endl;
    // just to prove that yes, they are exact, here are the next values
    // the different discards are because 1.0 has a different exponent
    engine.discard(1 << 11);
    std::cout << dist(engine) << std::endl;
    engine.discard(1 << 12);
    std::cout << dist(engine) << std::endl;
}

Reply via email to