我目前正致力于重要性抽样,出于测试目的,我需要能够生成uniform_real_distribution<float>
可能为区间[0,1]生成的所有可能值(是的,它也从右侧关闭) )。我的想法是生成整数,然后我可以转换为浮点数。从我进行的测试看来,[0,1]中的均匀单精度浮点数和[0,2 ^ 24]中的整数之间存在完美的双射(我有点担心它不是[0] ,2 ^ 24-1]我仍在试图找出原因,我最好的猜测是0对于浮点数来说是特殊的,1到2 ^ 24都会导致具有相同指数的浮点数)。我的问题是,以这种方式生成的浮点数是否恰好是可以从uniform_real_distribution<float>
生成的浮点数。你可以找到我的整数&lt; - &gt;浮动测试如下:
void floatIntegerBitsBijectionTest()
{
uint32 two24 = 1 << 24;
bool bij24Bits = true;
float delta = float(1.0) / float(two24);
float prev = float(0) / float(two24);
for (uint32 i = 1; i <= two24; ++i)
{
float uintMap = float(i) / float(two24);
if (uintMap - prev != delta || uint32(uintMap*float(two24)) != i)
{
std::cout << "No bijection exists between uniform floats in [0,1] and integers in [0,2^24].\n";
bij24Bits = false;
break;
}
prev = uintMap;
}
if(bij24Bits) std::cout << "A bijection exists between uniform floats in [0,1] and integers in [0,2^24].\n";
std::cout << "\n";
uint32 two25 = 1 << 25;
bool bij25Bits = true;
delta = float(1.0) / float(two25);
prev = float(0) / float(two25);
for (uint32 i = 1; i <= two25; ++i)
{
float uintMap = float(i) / float(two25);
if (uintMap - prev != delta || uint32(uintMap*float(two25)) != i)
{
std::cout << "No bijection exists between uniform floats in [0,1] and integers in [0,2^25].\n";
if (i == ((1 << 24) + 1)) std::cout << "The first non-uniformly distributed float corresponds to the integer 2^24+1.\n";
bij25Bits = false;
break;
}
prev = uintMap;
}
if (bij25Bits) std::cout << "A bijection exists between uniform floats in [0,1] and integers in [0,2^25].\n";
std::cout << "\n";
bool bij25BitsS = true;
delta = 1.0f / float(two24);
prev = float(-two24) / float(two24);
for (int i = -two24+1; i <= two24; ++i)
{
float uintMap = float(i) / float(two24);
if (uintMap - prev != delta || int(uintMap*float(two24)) != i)
{
std::cout << i << " " << uintMap - prev << " " << delta << "\n";
std::cout << "No bijection exists between uniform floats in [-1,1] and integers in [-2^24,2^24].\n";
bij25BitsS = false;
break;
}
prev = uintMap;
}
if (bij25BitsS) std::cout << "A bijection exists between uniform floats in [-1,1] and integers in [-2^24,2^24].\n";
}
编辑:
有点相关:
http://xoroshiro.di.unimi.it/random_real.c
https://lemire.me/blog/2017/02/28/how-many-floating-point-numbers-are-in-the-interval-01/
编辑2:
我最终设法找出uniform_real_distribution<float>
在与mt19937
引擎一起使用时与其默认模板参数一起使用时的作用(我正在讨论VS2017附带的实现)。遗憾的是,它只是在[0,2 ^ 32-1]中生成一个随机整数,将其转换为浮动,然后将其除以2 ^ 32。不用说,这会产生非均匀分布的浮点数。但是,我猜测,这适用于大多数实际用途,除非一个人在生成的数字之间接近增量的精度。
答案 0 :(得分:2)
我将假设C ++实现使用float
的IEEE-754 32位基本二进制格式。在这种格式中,[1,2]中可表示的浮点值有规律地间隔,距离为2 -23 。
使用以下内容定义x
std::uniform_real_distribution<float> x(1, 2);
然后,假设uniform_real_distribution
已得到很好的实施并且使用了正确的引擎,x(engine) - 1
将生成等于 n / 2 23 的值[0,2 23 )中的整数 n ,均匀分布。
我对C ++中uniform_real_distribution
的规范有疑虑。它是根据实际算术定义的。它以恒定概率密度返回值的要求需要一组连续的数字,浮点格式不提供这些数字。另外,我不确定实现将如何处理端点。
由于分布必须是离散的,因此也可以使用uniform_int_distribution
并将样本乘以2 -23 (可用numeric_limits<float>::epsilon()
)。根据需要,它有利于澄清端点并轻松支持[0,1)或[0,1]的间隔。
即使C ++标准不使用IEEE-754,[1,2]中的可表示值也应均匀分布,因为C ++标准中浮点值的描述由a中的某些数字表示。一定的基数,乘以基数提升到某种力量。对于功率零,1到2的值将根据格式中最低有效数字的值间隔开。如上所述,该距离为numeric_limits<float>::epsilon()
。
1 C ++标准使用遗留术语“尾数”,但首选术语是“有效数字”。
答案 1 :(得分:1)
你可以强迫这个问题。滚动你自己的随机漂浮发生器。
编辑:我刚刚发现了std::generate_canonical<float>()
,它做了同样的事情,但不依赖于幻数24.它可以从std::numerical_limits<float>::digits
等处理出来......
#include <random>
static const unsigned long big = 1 << 24;
static std::default_random_engine re;
static std::uniform_int_distribution<unsigned long> uint(0, big - 1);
float rand_float() {
return uint(re) / static_cast<float>(big);
}