为什么uniform_int_distribution关闭范围但uniform_real_distribution是半开放范围?

use*_*211 6 c++ random c++11

uniform_int_distribution有间隔[a, b]uniform_real_distribution有间隔[a, b).一个天真的方法是做一些类似的事情 b + 0.1,但是你开始进入无穷小...幸运的是,正确的方法很简单:

std::uniform_real_distribution<> dis(start, std::nextafter(stop, DBL_MAX));
Run Code Online (Sandbox Code Playgroud)

但为什么这有必要呢?更具体地说,这两者的不同之处是什么?

Chr*_*eck 7

统一的实际分布[a, b)几乎在统计上与分布无法区分[a, b].

这两个分布之间的统计距离非常接近于除以a和之间的浮点数的数量b.

也就是说,没有统计测试返回任何给定样本01任何给定样本,使得1用第一分布观察a的概率1与用第二分布观察a的概率大于2^{-32}.(假设您正在驾驶,例如std::uniform_real_distribution<float>使用纯熵std::random_device.)

因此,在大多数实际应用中,没有有意义的差异.

如果你想做类似的事情,有一个范围(a, b]而不是为了防止(非常不可能)除以零错误或其他东西,你可以测试你是否准确,a并替换它,b如果它是某种关键系统.


还有FWIW我怀疑你的"下一个b后"的解决方案并不总能按照你的想法 - 大多数时候,将要发生的是,适配器将计算b - a为浮点数,然后取样从熵源中,将其转换0-1为静态强制转换范围内的浮点数,然后乘以因子b-a,添加a并返回结果.

b如果ab不是完全相同的比例,则ε变化可能会在浮点减法中丢失,然后更改将无效.

这不是一个错误的原因是标准不要求分发适配器产生完全指定的分布,只是它在近似意义上收敛到目标.

该标准很难保证分布不会产生超出其声明范围的内容:

26.5.8.1一般[rand.dist.general]
1.从本节26.5.8中指定的类模板实例化的每个类型都满足随机数分布(26.5.1.6)类型的要求.
...
3.用于生成每个指定分布的算法是实现定义的.
4. 本节中规定的每个概率密度函数p(z)和每个离散概率函数的P (z i )0在其声明的域之外的任何地方都是如此.

但是,该标准还说明了统一随机数生成器:

26.5.3.1 [rand.req.urng]
1.一种均匀的随机数生成器 g型的G是一个功能对象返回无符号整数值,使得在可能的结果范围内的每个值具有(理想情况下)的返回相等概率.[注意:g结果接近理想的程度通常在统计上确定. - 结束说明]

既然[a, b)并且[a, b + epsilon)基本上在统计上无法区分,你不应该认为它是一个错误,即使你的b + epsilon伎俩仍然没有b在输出中看到一个,即使你穷尽地尝试每一个可能的种子.

如果这不是标准的立场,那么所有这些适配器都必须经过精心编写,以便它们始终可以在每个架构上获得完全正确的分布,并且它们必须运行得慢得多.在大多数应用中,像这样的微小采样误差是可以容忍的,并且提高效率更重要.


Ulr*_*rdt 2

让我提供一个基本原理:使用整数时,有时会使用它们来实现选择。所以你有 N 个值,每个值的可能性都必须相等。有时,最高可能值甚至可能是该整数类型可表示的最高值,因此 N+1 会超出范围并溢出。

对于浮点值,您通常无法表示范围的限制(例如0.1),并且由于通常不比较数字是否相等(例如1.0/10.0可能比较也可能不等于0.1),因此您忽略了限制值不等于的事实不会发生。