Pregunta ¿Por qué no hay uniform_distribution?


Tenemos uniform_int_distribution y uniform_real_distribution, no sería posible tener una uniform_distribution , que se especializa en float / double e int / ..., cuando se especifica?


13
2017-08-14 07:48


origen


Respuestas:


AFAIU, los comentarios de arriba por @ user877329 y @revolver_ocelot explican esto correctamente, y la otra respuesta es completamente incorrecta.

Es incorrecto unificar las interfaces de uniform_int y uniform_real, no porque se implementen de manera diferente (lo que se puede resolver mediante la especialización de plantillas), sino porque las interfaces significan cosas diferentes.

Supongamos que unificamos las interfaces (usando una variación de la sugerencia en la otra respuesta), así:

template <typename T>
using uniform_distribution =
    typename std::conditional<
        std::is_integral<T>::value,
        std::uniform_int_distribution<T>,
        std::uniform_real_distribution<T>
    >::type;

Entonces si definimos uniform_distribution<some_type> u(0, 9), el significado es muy diferente:

  • Si some_type es integral, entonces obtendrá 9 aproximadamente 1/10 de las veces.

  • Si some_type no es, entonces u será Nunca salida 9.

El siguiente código (cuyo resultado es true y entonces false) ilustra esto:

#include <random>
#include <iostream>
#include <type_traits>                                         

template <typename T>
using uniform_distribution =
    typename std::conditional<
        std::is_integral<T>::value,
        std::uniform_int_distribution<T>,
        std::uniform_real_distribution<T>
    >::type;

int main()
{
    std::random_device rd;
    std::mt19937 gen(rd());

    {
        uniform_distribution<int> u(0, 9);
        bool over_found = false;
        for(size_t i = 0; i < 99999; ++i)
            over_found = over_found || u(gen) >= 9;
        std::cout << std::boolalpha << over_found << std::endl;
    }

    {
        uniform_distribution<float> u(0, 9);
        bool over_found = false;
        for(size_t i = 0; i < 99999; ++i)
            over_found = over_found || u(gen) >= 9;
        std::cout << std::boolalpha << over_found << std::endl;
    }
}

Este código ilustra que escribir código genérico usando esta clase es peligroso. Por ejemplo, si escribe una función genérica calculando un histograma de los resultados en los subintervalos: [0, 1), [1, 2), ..., [8, 9), los resultados serían incompatibles.


Como señala @revolver_ocelot, la biblioteca estándar [inclusive-begin, exclusive_end) convención no se puede usar para enteros uniformes (porque sería imposible especificar un generador de números aleatorios enteros uniformes que genere también el valor máximo de uint), haciendo de esto una firma excepcional.


14
2017-08-14 10:05