我正在尝试为所有可表示的有限值生成具有大致相等概率的随机 double 。我相信这类似于随机签名的 exponential_distribution
,uniform_distribution
将不起作用,因为可表示的 double 不是均匀分布的。我有这个 hacky 代码,似乎可以做我想做的事:
#include <cmath>
#include <iostream>
#include <random>
template < class GEN >
double double_distribution (GEN& generator)
{
using gen_type = typename GEN::result_type;
static_assert (sizeof (gen_type) == sizeof (double), "");
union {gen_type g; double f;} result;
do {
result.g = generator();
} while (!std::isfinite (result.f));
return result.f;
}
int main() {
std::mt19937_64 mt ((std::random_device())());
for (int n = 0; n < 10; ++n) {
std::cout << double_distribution (mt) << ' ';
}
std::cout << '\n';
}
但我想知道是否有一种更简单的方法可以使用 STL 现有的 RandomNumberDistribution 类之一来对此进行近似?
最佳答案
如果您假设一个 64 位 IEEE double ,这里有一个方法。 (对于 double 的不同表示,您应该能够修改此基本方法。)
64位分为1位符号,11位指数,52位小数。像 NaN 和 inf 这样的特殊值由指数位的特殊值表示。您在这里有两个基本选择:
从所有可能的 64 位组合的集合中生成一个随机数(就像在适当大小的整数类型上的统一),并从中设置你的 double 。在这种情况下,您有时会绘制一个对应于例如 NaN 的数字。您需要丢弃它们并重新绘制或接受它们,具体取决于您是否希望返回 NaN。 (听起来你的情况可能不是这样。)
在一次绘制中生成符号和小数部分的位,然后分别绘制指数。如果你这样做,你应该能够修改你的绘图,这样你就不会拉出 NaN 值 - 特殊值似乎对应于指数的极值,所以这相当于改变你的绘图范围整数,我认为许多软件包都可以轻松支持它。在这种情况下,您不必“重新绘制”来避免特殊值,但您可能会在每次绘制时得到一些“额外”位,因为您可能最终会从整数类型的分布中提取(位数为 8 的倍数),但符号 + 分数使用 53,指数仅使用 11。您可能会做一些聪明的事情来节省这些位,以便在下一次抽取中使用一次绘制中“丢弃”的位。您必须仔细考虑以确保这不会在您的绘图之间引入依赖性,但我认为这应该没问题。
如果效率对您来说不是什么大问题,那么#1 看起来更易于实现。如果您需要效率,那么 #2 可能会更好,尽管可能以更复杂的代码为代价。
关于c++ - 分布在 -DBL_MAX 和 DBL_MAX 之间的随机 double ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42163618/