std::uniform_real_distribution 总是 returns 无限
std::uniform_real_distribution always returns infinity
当我运行这段代码时:
double getRandomDouble() {
static std::mt19937 entropy_ = std::mt19937();
std::uniform_real_distribution<double> distribution;
distribution.param(typename decltype(distribution)::param_type(std::numeric_limits<double>::lowest(),
std::numeric_limits<double>::max()));
return distribution(entropy_);
}
它总是return无穷大(至少在 GCC8.1 和 clang 11.0.1 中是这样。在 MSVC 14.16.27023 中它断言)
Here is a working demonstration in GodBolt
我希望此函数 return 任何随机双精度值,这里发生了什么?
你有一个数字问题:分布使用概率函数:1 / (b - a)
,在这种情况下 b - a
超出了 double
的范围(这意味着 inf
,所以所有的数字都是inf
)。您可以通过降低限制来修复它,如下例所示。
此外,您一直在使用新的随机数生成器,并且由于种子相同,所以生成的随机数始终相同。您可以将生成器置于函数外部,以便它继续生成新数字,或者更好地关联一个随机设备。
#include <random>
#include <iostream>
double getRandomDouble() {
std::random_device rd; // <<
std::mt19937 entropy_ = std::mt19937(rd()); // <<
std::uniform_real_distribution<double> distribution;
using param = typename decltype(distribution)::param_type;
distribution.param(param(std::numeric_limits<double>::lowest() / 2,
std::numeric_limits<double>::max() / 2));
return distribution(entropy_);
}
int main()
{
for (int i = 0; i < 10; ++i) {
std::cout << "Random number: " << getRandomDouble() << "\n";
}
return 0;
}
你可以测试一下here。
uniform_real_distribution
的强制执行基本上是在[0,1)
中统一分配然后映射到[a,b)
乘以(b-a)
然后加上a
。
这是一个很好的面向速度的实现,但是当应用于极端情况时它会失败。在您的情况下,计算 b-a
会导致无穷大,随后整个计算都会失败。
参数的选择违反了std::uniform_real_distribution
的前提条件(c.f。§26.6.9.2.2.2)。
先决条件是 a ≤ b
和 b - a ≤ numeric_limits<T>::max()
,其中 a
和 b
是分布的最小值和最大值。使用 numeric_limits<double>::lowest()
和 numeric_limits<double>::max()
会违背这一点。
根据的建议,使用a = -max()/2.0
、b = max()/2.0
会是更好的选择。
当我运行这段代码时:
double getRandomDouble() {
static std::mt19937 entropy_ = std::mt19937();
std::uniform_real_distribution<double> distribution;
distribution.param(typename decltype(distribution)::param_type(std::numeric_limits<double>::lowest(),
std::numeric_limits<double>::max()));
return distribution(entropy_);
}
它总是return无穷大(至少在 GCC8.1 和 clang 11.0.1 中是这样。在 MSVC 14.16.27023 中它断言)
Here is a working demonstration in GodBolt
我希望此函数 return 任何随机双精度值,这里发生了什么?
你有一个数字问题:分布使用概率函数:1 / (b - a)
,在这种情况下 b - a
超出了 double
的范围(这意味着 inf
,所以所有的数字都是inf
)。您可以通过降低限制来修复它,如下例所示。
此外,您一直在使用新的随机数生成器,并且由于种子相同,所以生成的随机数始终相同。您可以将生成器置于函数外部,以便它继续生成新数字,或者更好地关联一个随机设备。
#include <random>
#include <iostream>
double getRandomDouble() {
std::random_device rd; // <<
std::mt19937 entropy_ = std::mt19937(rd()); // <<
std::uniform_real_distribution<double> distribution;
using param = typename decltype(distribution)::param_type;
distribution.param(param(std::numeric_limits<double>::lowest() / 2,
std::numeric_limits<double>::max() / 2));
return distribution(entropy_);
}
int main()
{
for (int i = 0; i < 10; ++i) {
std::cout << "Random number: " << getRandomDouble() << "\n";
}
return 0;
}
你可以测试一下here。
uniform_real_distribution
的强制执行基本上是在[0,1)
中统一分配然后映射到[a,b)
乘以(b-a)
然后加上a
。
这是一个很好的面向速度的实现,但是当应用于极端情况时它会失败。在您的情况下,计算 b-a
会导致无穷大,随后整个计算都会失败。
参数的选择违反了std::uniform_real_distribution
的前提条件(c.f。§26.6.9.2.2.2)。
先决条件是 a ≤ b
和 b - a ≤ numeric_limits<T>::max()
,其中 a
和 b
是分布的最小值和最大值。使用 numeric_limits<double>::lowest()
和 numeric_limits<double>::max()
会违背这一点。
根据a = -max()/2.0
、b = max()/2.0
会是更好的选择。