[Bug libstdc++/65723] uniform_real_distribution isn't uniform.

art at blahonga dot org gcc-bugzilla@gcc.gnu.org
Fri Apr 10 09:36:00 GMT 2015


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

--- Comment #6 from art at blahonga dot org ---
(In reply to Jonathan Wakely from comment #1)
> I think this is WONTFIX. If you use from=0, to=2 then it works fine, so use
> those as the distribution parameters and then add 0x1p52 to the result.

It doesn't work fine. For any range. the 0x1p52 isn't the problem here.

new test hack.

#include <random>
#include <iostream>

#include <stdio.h>
#include <assert.h>

int
main(int argc, char **argv)
{
    std::default_random_engine gen;
    double from, step, to;
    int range = 3;

    switch (argc) {
    case 1:
        from = 1.0;
        break;
    default:
    case 3:
        range = atoi(argv[2]);
    case 2:
        from = atof(argv[1]);
        break;
    }

    /*
     * Calculate the nearest representable number after from.
     * add 1.0 to deal with from being 0 (shouldn't cause overflow
     * because at that range 1.0 means nothing).
     */
    step = nextafter(from, (from + 1.0) * 2.0) - from;
    /*
     * uniform_real_distribution should return [from,to), but they
     * all return [from,to], so that's why 1 is subtracted from range.
     */
    to = from + step * (range - 1);

    printf("%e %e %e %d\n", from, to, step, range);

    std::uniform_real_distribution<double> dis(from, to);
    int bucket[range];
    int i;

    for (i = 0; i < range; i++) {
        bucket[i] = 0;
    }

    for (i = 0; i < 100 * range; i++) {
        double r = dis(gen);
        unsigned int b = (int)((r - from)/step);
        if (b >= range) {
            printf("foo: %d %f\n", b, r);
        }
        assert(b < range);
        bucket[b]++;
    }

    for (i = 0; i < range; i++) {
        printf("%d\n", bucket[i]);
    }
    return 0;
}

$ c++ -std=c++11 -o foo urd.cxx && ./foo
1.000000e+00 1.000000e+00 2.220446e-16 3
77
154
69
$ c++ -std=c++11 -o foo urd.cxx && ./foo 1.0 10000 | head -5
1.000000e+00 1.000000e+00 2.220446e-16 10000
46
107
119
102
$ c++ -std=c++11 -o foo urd.cxx && ./foo 0.0 100000 | head -5
0.000000e+00 4.940607e-319 4.940656e-324 100000
49
105
97
84
$ c++ -std=c++11 -o foo urd.cxx && ./foo 1000.5 555 | head -5
1.000500e+03 1.000500e+03 1.136868e-13 555
57
98
120
97



More information about the Gcc-bugs mailing list