为什么没有uniform_distribution?

mik*_*ike 13 c++

我们有,uniform_int_distribution并且uniform_real_distribution不可能有一个包含uniform_distribution,专门用于float/double和int/...,当指定时?

Ami*_*ory 14

AFAIU,@ user877329和@revolver_ocelot上面的评论正确解释了这一点,另一个答案是完全错误的.

这是错误的,统一的接口uniform_intuniform_real,而不是因为它们是不同的实现方式(这可以通过模板特来解决),但由于接口意味着不同的事情.

假设我们统一接口(使用另一个答案中的建议的变体),如下所示:

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;
Run Code Online (Sandbox Code Playgroud)

然后,如果我们定义uniform_distribution<some_type> u(0, 9),意义是非常不同的:

  • 如果some_type是积分,那么你将输出9大约1/10的时间.

  • 如果some_type不是,那么u永远不会输出9.

以下代码(其输出是true然后false)说明了这一点:

#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;
    }
}
Run Code Online (Sandbox Code Playgroud)

此代码说明使用此类编写通用代码很危险.例如,如果您要编写一个泛型函数来计算子范围中结果的直方图:[0,1),[1,2,...,[8,9],那么结果将是不兼容的.


正如@revolver_ocelot指出的那样,标准库的[inclusive-begin,exclusive_end]约定不能用于统一整数(因为不可能指定一个整数随机数生成器生成最大uint值),这使得这是一个特殊的签名.

  • 包容性或排他性范围没有区别,因为获得特定实数(例如9)的概率无论如何都是0,所以永远不会看到9.在数学意义上,授予的双打和浮点数不是实数,但考虑到我们在谈论随机数和浮点数,这种差异可以忽略不计,而且双数只是对于实数的近似值. (2认同)
  • @nwp:"获得特定实数的概率,例如9,无论如何都是0" - 这是不真实的,因为尽管名称`uniform_real_distribution`不是实数上的连续分布.它是有理数的有限子集上的离散分布,由"RealType"(默认为"double")表示.因此包括或排除端点*确实*有所作为. (2认同)