我想获得该范围内的随机浮点数[0.0,1.0],因此大多数这些数字都应该是0.5.因此我提出了以下功能:
static std::random_device __randomDevice;
static std::mt19937 __randomGen(__randomDevice());
static std::normal_distribution<float> __normalDistribution(0.5, 1);
// Get a normally distributed float value in the range [0,1].
inline float GetNormDistrFloat()
{
float val = -1;
do { val = __normalDistribution(__randomGen); } while(val < 0.0f || val > 1.0f);
return val;
}
Run Code Online (Sandbox Code Playgroud)
但是,调用该函数1000次会导致以下分布:
0.0 - 0.25 : 240 times
0.25 - 0.5 : 262 times
0.5 - 0.75 : 248 times
0.75 - 1.0 : 250 times
Run Code Online (Sandbox Code Playgroud)
我期待该范围的第一个和最后一个季度显示比上面显示的少得多.所以看来我在这里做错了.
有任何想法吗?
Beg*_*ner 13
简答:不要砍掉正常分布的尾巴.
答案很长:问题是如果标准差为1,则在区间[0,1]内有大多数值.如果你看看正态分布:
您正在使用的部件位于中心,您需要更多样本来检测差异.只切割超出范围的值绝对不会给你一个正常的分布式样本.
您可以看到累积的密度函数在您使用的[0,1]区间内几乎是线性的:
用wolfram alpha生成的图片.
在此缩放中,分布的形状几乎是三角形,您可以在此处检查输出以获取更多样本:
#include <iostream>
#include <random>
using namespace std;
static std::random_device __randomDevice;
static std::mt19937 __randomGen(__randomDevice());
static std::normal_distribution<float> __normalDistribution(0.5, 1);
// Get a normally distributed float value in the range [0,1].
inline float GetNormDistrFloat()
{
float val = -1;
do { val = __normalDistribution(__randomGen); }
while(val < 0.0f || val > 1.0f);
return val;
}
int main() {
int count1=0;
int count2=0;
int count3=0;
int count4=0;
for (int i =0; i< 1000000; i++) {
float val = GetNormDistrFloat();
if (val<0.25){ count1++; continue;}
if (val<0.5){ count2++; continue;}
if (val<0.75){ count3++; continue;}
if (val<1){ count4++; continue;}
}
std::cout<<count1<<", "<<count2<<", "<<count3<<", "<<count4<<std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
成功时间:0.1内存:16072信号:0
241395,258131,258275,242199
第一个选项(由Caleth建议):使用()逻辑函数1 /(1 + exp(-x)),它具有域(-∞,+∞)和范围[0,1].这样,您实际上可以获得完全正态分布.
另一种选择:它不像上面那样在数学上很好,但可能更快.您可以使用标准正态分布,其均值为0,偏差为1,然后重新映射到[0,1]更大的范围,例如+/- 4标准偏差.现在你有一个问题,你的积分的重量不再是1而是少一点.它实际上不再是随机变量.
如果你想得到1的权重,你可以通过不重新滚动来分配剩余的尾部(4个标准之外),但是通过从[0,1]间隔获得均匀分布的随机值,这种情况:
val = NormalRand(0,1);
if abs(val) < 4 return val/8 + 0.5
else return UniformRand(0,1)
Run Code Online (Sandbox Code Playgroud)
另一种选择(由interjay建议):简单地减少标准偏差.