2010-05-05 120 views
6

我找了一个随机数发生器,可以有偏差。例如,假设我想1-5之间的随机数,与概率之中:偏置随机数发生器

1:出现20%的时间
2:出现10%的时间
3:出现40时间
4%:出现25%的时间
5:出现5%的时间

是否有标准库什么,或其他图书馆,在那里,将做到这一点?或者,有没有一种有效的方法来做到这一点?

+10

希望你不是在为赌场写软件! – Alan 2010-05-05 18:01:01

+2

哈哈不,我敢肯定赌场会聘请一个更聪明的人。 – cmptrer 2010-05-05 18:05:02

+1

从昨天:http://stackoverflow.com/questions/2772882/c-picking-a-random-item-based-on-probabilities,这是一堆相同问题的早期版本的重复(我是懒得找)。您在搜索时可能缺少的词是“离散的”,这一点很重要,因为下面的一些答案更适用于连续分布。 – dmckee 2010-05-05 20:06:46

回答

9

Boost随机数字库提供了为您的生成器指定不同形状分布的能力。这是一个很棒的图书馆 - 见http://www.boost.org/doc/libs/1_42_0/libs/random/index.html

+1

是的,不要重新发明轮子! – 2010-05-05 18:18:24

+5

有一天我会开始使用Boost。有一天。 – 2010-05-05 18:20:32

+0

它只是缺乏一个适当的文件...将很高兴知道什么引擎和分布所需的概念,以便能够自己设计,而无需逆向工程库:( – 2010-05-05 18:26:45

15

对于您的问题,随便挑一个随机元素从这个名单一致:

[1, 1, 1, 1, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5] 

一般情况下,检查这个答案:Weighted random numbers


在TR1和C++ 0x中,有<random> header其中包含discrete_distribution class以产生这些数字等等。

您可能还想查看GSL,其中包含比标准<random>库更多的random distributions(和随机数生成器)。 (但请注意,GSL使用GPLv3的。)

+2

也许我应该解释我的实际情况好一点。我真正需要的是一个介于1-50,000之间的随机数。创建一个很长的列表似乎是不必要的,并且不需要。对困惑感到抱歉。 – cmptrer 2010-05-05 18:01:35

+6

这就是为什么好的工程需要适当的一套要求。你问了简单的情况,你得到了(正确的)简单的答案。 – 2010-05-05 18:05:26

12

最好的办法可能是只取正常无偏随机生成然后返回基于它的值落入区间。

只是一个if语句,让1为0:0.2,2为0.2:0.3,3 0.3:0.7,4为0.7:0.95和5 0.95:1。最好做出包含区间的上限或下限,以及其他排除。

int biasedRandom(){ 
double i = randomNumber(); 
if(i<= 0.2){return 1;} 
else if(i <= 0.3){return 2;} 
else if(i <= 0.7){return 3;} 
else if(i <= 0.95){return 4;} 
else{return 5;} 
} 

类似的东西。

+2

如果您有很多需要检查的时间间隔,您应该做的是创建一个累积分布数组(不知道该怎么称呼它),并且每次都进行二进制搜索以找到数字产生。 – 2010-05-05 18:07:48

+2

看起来像这个发电机总是会返回5。除非randomNumber()返回值0-1,否则需要双/浮点数和其他一些数学运算。 – Xorlev 2010-05-05 18:25:59

+0

是的你是对的,它每次都会给5次,并不意味着让我成为一个整数,这是一个错误。感谢您指出。 – AaronM 2010-05-05 18:32:38

0

你为什么不只是使用普通的随机数生成器0.0和1.0之间返回号码,并与根据您的要求返回一个数字,另一个函数把它包装?

double biased (double seed) { 
if (seed >= 0.0 && seed <0.2) return 1; 
else if ... 
} 
+2

我不会使用'seed'作为一个随机生成的数字的标识符,这是令人困惑的... – 2010-05-05 18:01:38

+0

为什么不呢? C rand函数也需要一个种子,大多数情况下是系统时间。所以有偏见是一个函数,它会根据种子生成一个随机数。 – DaClown 2010-05-06 12:38:19

0

扔在[0,1]的随机实数x,if 0< x<0.2 return 1if 0.2<x <0.3 return 2

here参见为一般问题。

0

肯尼给为您量身打造特定的频率分配一个合适的答案。

更一般的答案适用于CDF - 累积分布函数 - 用于数据,并使用统一的随机数来选择分布内的值。

5

你所描述的是一个随机数发生器,从一个特定的概率分布绘制的实现。例如,来自高斯分布的绘图数字应绘制随机数字,使得特定绘制的概率与alt text http://upload.wikimedia.org/math/1/8/4/184fa5540b76903b1653d9f83912265d.png成比例。

一般来说,该方法是从统一的随机分布中提取出来,然后在该位置选取期望分布的累积分布函数(CDF)的值。在正态高斯情况下,从均匀分布(这是标准随机数发生器应该给出的值)中绘制一个随机数x,然后选择alt text作为随机高斯分布值。对于你的情况,你描述的CDF是一个分段连续的阶梯函数,可以使用你已经收到的许多(正确的)答案中的任何一个来实现。

当然,这都是琐事。 应该正在做的是使用一个已经为你处理这个问题的库。统计和随机数字的生成并不是微不足道的,不需要重新发明轮子。查看Neil的答案(并查看Boost random number库)。

4

晚会到这一方。这里是C++ 0x中回答:

#include <iostream> 
#include <random> 
#include <iterator> 

int main() 
{ 
    // Set up distribution 
    double interval[] = {1, 2, 3, 4, 5, 6}; 
    double weights[] = { .2, .1, .4, .25, .05}; 
    std::piecewise_constant_distribution<> dist(std::begin(interval), 
               std::end(interval), 
               std::begin(weights)); 
    // Choose generator 
    std::mt19937 gen; // seed as wanted 
    // Demonstrate by pouring into avg[rand-1] 
    const unsigned N = 1000000; 
    double avg[sizeof(weights)/sizeof(weights[0])] = {0}; 
    for (unsigned i = 0; i < N; ++i) 
     avg[static_cast<unsigned>(dist(gen)) - 1]++; 
    // Comute averages 
    for (double* i = std::begin(avg); i < std::end(avg); ++i) 
     *i /= N; 
    // Display 
    for (unsigned i = 1; i <= sizeof(avg)/sizeof(avg[0]); ++i) 
     std::cout << "avg[" << i << "] = " << avg[i-1] << '\n'; 
} 

这对我来说输出:

avg[1] = 0.199779 
avg[2] = 0.100002 
avg[3] = 0.400111 
avg[4] = 0.250257 
avg[5] = 0.049851 
+0

+1优秀的答案! – 2012-11-26 23:56:42

0
#include <boost/random/discrete_distribution.hpp> 
#include <boost/random/mersenne_twister.hpp> 
#include <boost/random/variate_generator.hpp> 

#include <iostream> 

int main() 
{ 

    unsigned int seed = 42; 
    boost::mt19937 generator(seed); 

    // return 0 with probability 10% 
    //  1     40% 
    //  2     50% 
    boost::random::discrete_distribution<int> custom_dist{1,4,5}; 

    boost::variate_generator<boost::mt19937&, 
    boost::random::discrete_distribution<int> > rndn(generator, custom_dist); 

    for (unsigned int i = 0; i<10000; i++) { 
    std::cout << rndn() << std::endl; 
    } 

    return 0; 

} 

这里是结果的一个情节:

Output