在整个范围内均匀生成随机数

时间:2008-11-13 23:27:49

标签: c++ random

我需要在指定的时间间隔内生成随机数,[max; min]。

此外,随机数应该在区间内均匀分布,而不是位于特定点。

Currenly我正在生成:

for(int i=0; i<6; i++)
{
    DWORD random = rand()%(max-min+1) + min;
}

从我的测试中,只有一个点生成随机数。

Example
min = 3604607;
max = 7654607;

生成随机数:

3631594
3609293
3630000
3628441
3636376
3621404

从下面的答案:好的,RAND_MAX是32767.我在C ++ Windows平台上。有没有其他方法来生成具有均匀分布的随机数?

17 个答案:

答案 0 :(得分:129)

为什么rand是个坏主意

您在此获得的大多数答案都使用了rand函数和模数运算符。该方法may not generate numbers uniformly(取决于RAND_MAX的范围和值),因此不鼓励。

C ++ 11和范围内的生成

使用C ++ 11,其他多个选项已经上升。其中一个符合您的要求,用于生成范围内的随机数,非常好:std::uniform_int_distribution。这是一个例子:

const int range_from  = 0;
const int range_to    = 10;
std::random_device                  rand_dev;
std::mt19937                        generator(rand_dev());
std::uniform_int_distribution<int>  distr(range_from, range_to);

std::cout << distr(generator) << '\n';

here是正在运行的例子。

其他随机发电机

<random> header提供了无数其他随机数生成器,它们具有不同类型的分布,包括Bernoulli,Poisson和normal。

如何将容器洗牌?

标准提供std::shuffle,可按如下方式使用:

std::vector<int> vec = {4, 8, 15, 16, 23, 42};

std::random_device random_dev;
std::mt19937       generator(random_dev());

std::shuffle(vec.begin(), vec.end(), generator);

该算法将随机重新排序元素,具有线性复杂性。

Boost.Random

如果您无法访问C ++ 11 +编译器,另一种方法是使用Boost.Random。它的界面与C ++ 11非常相似。

答案 1 :(得分:58)

[edit] 警告:请勿将rand()用于统计,模拟,加密或任何严重的事情。

对于一个典型的人来说,匆忙使数字看起来已经足够了,不再需要了。

有关更好的选项,请参阅@Jefffrey's reply;有关加密安全随机数,请参阅this answer


通常,高位显示比低位更好的分布,因此为简单目的生成范围随机数的推荐方法是:

((double) rand() / (RAND_MAX+1)) * (max-min+1) + min

注意:确保RAND_MAX + 1不会溢出(感谢Demi)!

除法在区间[0,1]中生成随机数;将其“拉伸”到所需的范围。只有当max-min + 1接近RAND_MAX时,你需要一个像Mark Ransom发布的“BigRand()”函数。

这也避免了因模数造成的切片问题,这会使你的数字更加恶化。


内置随机数发生器无法保证具有统计模拟所需的质量。数字对人类来说“随机”是可以的,但对于严肃的应用,你应该采取更好的方法 - 或者至少检查它的属性(均匀分布通常是好的,但值往往是相关的,序列是确定的)。 Knuth对随机数生成器有一个很好的(如果难以阅读)论文,我最近发现LFSR非常好并且实现起来很简单,因为它的属性对你来说还可以。

答案 2 :(得分:14)

我希望通过对2015年最新技术水平的简短概述来补充“愤怒的鞋子”和彼得的优秀答案:

一些不错的选择

randutils

randutils(presentation)是一个有趣的新奇事物,提供简单的界面和(声明的)强大的随机功能。它的缺点在于它增加了对项目的依赖性,而且新的,它还没有经过广泛的测试。无论如何,免费(麻省理工学院许可证)和仅限标题,我认为值得一试。

最小样本:掷骰子

#include <iostream>
#include "randutils.hpp"
int main() {
    randutils::mt19937_rng rng;
    std::cout << rng.uniform(1,6) << "\n";
}

即使一个人对图书馆不感兴趣,网站(http://www.pcg-random.org/)也提供了很多关于随机数生成主题的有趣文章,特别是C ++库。

Boost.Random

Boost.Random (documentation)是启发C ++ 11 <random>的图书馆,与其共享大部分界面。虽然理论上也是一种外部依赖,但Boost现在具有“准标准”的地位。库及其随机模块可以作为优质随机数生成的经典选择。它具有两个与C ++ 11解决方案相关的优点:

  • 它更易于移植,只需要编译器支持C ++ 03
  • random_device使用系统特定的方法提供高质量的播种

唯一的小缺陷是提供random_device的模块不是仅限标题,必须编译并链接boost_random

最小样本:掷骰子

#include <iostream>
#include <boost/random.hpp>
#include <boost/nondet_random.hpp>

int main() {
    boost::random::random_device                  rand_dev;
    boost::random::mt19937                        generator(rand_dev());
    boost::random::uniform_int_distribution<>     distr(1, 6);

    std::cout << distr(generator) << '\n';
}

虽然最小样本可以很好地运行,但真正的程序应该使用一对改进:

  • 使mt19937成为thread_local:生成器非常丰满(> 2 KB),最好不要在堆栈上分配
  • 具有多个整数的
  • 种子mt19937:Mersenne Twister具有较大的状态,可以在初始化期间获得更多的熵

一些不那么好的选择

C ++ 11库

尽管<random>库是最惯用的解决方案,但即使对于基本需求,std::random_device库也没有提供太多交换其界面的复杂性。该缺陷在entropy()中:标准不要求其输出具有任何最低质量(只要0返回4),并且截至2015年,MinGW(不是最常用的编译器) ,但几乎不是一个深奥的选择)将始终在最小样本上打印#include <iostream> #include <random> int main() { std::random_device rand_dev; std::mt19937 generator(rand_dev()); std::uniform_int_distribution<int> distr(1, 6); std::cout << distr(generator) << '\n'; }

最小样本:掷骰子

#include <iostream>
#include <random>

int main() {
    std::cout << std::randint(1,6);
}

如果实施没有腐烂,这个解决方案应该等同于Boost,并且适用相同的建议。

<2>戈多的解决方案

最小样本:掷骰子

randint

这是一个简单,有效和简洁的解决方案。只有缺陷,编译需要一段时间 - 大约两年,提供C ++ 17按时发布,实验#include <cstdlib> #include <ctime> #include <iostream> int main() { std::srand(std::time(nullptr)); std::cout << (std::rand() % 6 + 1); } 功能被批准进入新标准。也许到那个时候,播种质量的保证也会有所改善。

worse-is-better解决方案

最小样本:掷骰子

#include <iostream>

int main() {
    std::cout << 9;   // http://dilbert.com/strip/2001-10-25
}

旧的C解决方案被认为是有害的,并且有充分的理由(请参阅此处的其他答案或this detailed analysis)。尽管如此,它还是有它的优点:简单,便携,快速和诚实,从某种意义上说,人们知道随机数字很难得到,因此人们不会试图将它们用于严肃的目的。

会计巨魔解决方案

最小样本:掷骰子

ERROR 2015-12-16 09:59:42,893 [[epsilon-adobe].HTTP_Listener_Configuration.worker.01] org.mule.exception.CatchMessagingExceptionStrategy: 
********************************************************************************
Message               : Error reading XMLStreamReader.. Message payload is of type: NullPayload
Type                  : org.mule.module.ws.consumer.SoapFaultException
Code                  : MULE_ERROR--2
JavaDoc               : http://www.mulesoft.org/docs/site/current3/apidocs/org/mule/module/ws/consumer/SoapFaultException.html
Payload               : {NullPayload}
********************************************************************************
Exception stack is:
1. Error reading XMLStreamReader.. Message payload is of type: NullPayload (org.mule.module.ws.consumer.SoapFaultException)
  org.mule.module.ws.consumer.WSConsumer$1:196 (http://www.mulesoft.org/docs/site/current3/apidocs/org/mule/module/ws/consumer/SoapFaultException.html)
********************************************************************************
Root Exception stack trace:
org.mule.module.ws.consumer.SoapFaultException: Error reading XMLStreamReader.. Message payload is of type: NullPayload
    at org.mule.module.ws.consumer.WSConsumer$1.processNext(WSConsumer.java:196)
    at org.mule.processor.AbstractRequestResponseMessageProcessor.processBlocking(AbstractRequestResponseMessageProcessor.java:56)
    at org.mule.processor.AbstractRequestResponseMessageProcessor.process(AbstractRequestResponseMessageProcessor.java:47)
    at org.mule.execution.ExceptionToMessagingExceptionExecutionInterceptor.execute(ExceptionToMessagingExceptionExecutionInterceptor.java:24)
    at org.mule.execution.MessageProcessorNotificationExecutionInterceptor.execute(MessageProcessorNotificationExecutionInterceptor.java:107)
    at org.mule.execution.MessageProcessorExecutionTemplate.execute(MessageProcessorExecutionTemplate.java:44)
    at org.mule.processor.BlockingProcessorExecutor.executeNext(BlockingProcessorExecutor.java:88)
    at org.mule.processor.BlockingProcessorExecutor.execute(BlockingProcessorExecutor.java:59)
    at org.mule.execution.ExceptionToMessagingExceptionExecutionInterceptor.execute(ExceptionToMessagingExceptionExecutionInterceptor.java:24)
    at org.mule.execution.MessageProcessorNotificationExecutionInterceptor.execute(MessageProcessorNotificationExecutionInterceptor.java:107)
    at org.mule.execution.MessageProcessorExecutionTemplate.execute(MessageProcessorExecutionTemplate.java:44)
    at org.mule.module.ws.consumer.WSConsumer.process(WSConsumer.java:107)
    at org.mule.execution.ExceptionToMessagingExceptionExecutionInterceptor.execute(ExceptionToMessagingExceptionExecutionInterceptor.java:24)
    at org.mule.execution.MessageProcessorNotificationExecutionInterceptor.execute(MessageProcessorNotificationExecutionInterceptor.java:107)
    at org.mule.execution.MessageProcessorExecutionTemplate.execute(MessageProcessorExecutionTemplate.java:44)
    at org.mule.processor.BlockingProcessorExecutor.executeNext(BlockingProcessorExecutor.java:88)
    at org.mule.processor.BlockingProcessorExecutor.execute(BlockingProcessorExecutor.java:59)
    at org.mule.execution.ExceptionToMessagingExceptionExecutionInterceptor.execute(ExceptionToMessagingExceptionExecutionInterceptor.java:24)
    at org.mule.execution.MessageProcessorExecutionTemplate.execute(MessageProcessorExecutionTemplate.java:44)
    at org.mule.processor.BlockingProcessorExecutor.executeNext(BlockingProcessorExecutor.java:98)
    at org.mule.processor.BlockingProcessorExecutor.execute(BlockingProcessorExecutor.java:59)
    at org.mule.processor.AsyncInterceptingMessageProcessor.process(AsyncInterceptingMessageProcessor.java:102)
    at org.mule.execution.ExceptionToMessagingExceptionExecutionInterceptor.execute(ExceptionToMessagingExceptionExecutionInterceptor.java:24)
    at org.mule.execution.MessageProcessorNotificationExecutionInterceptor.execute(MessageProcessorNotificationExecutionInterceptor.java:107)
    at org.mule.execution.MessageProcessorExecutionTemplate.execute(MessageProcessorExecutionTemplate.java:44)
    at org.mule.processor.BlockingProcessorExecutor.executeNext(BlockingProcessorExecutor.java:98)
    at org.mule.processor.BlockingProcessorExecutor.execute(BlockingProcessorExecutor.java:59)
    at org.mule.construct.DynamicPipelineMessageProcessor.process(DynamicPipelineMessageProcessor.java:55)
    at org.mule.execution.ExceptionToMessagingExceptionExecutionInterceptor.execute(ExceptionToMessagingExceptionExecutionInterceptor.java:24)
    at org.mule.execution.MessageProcessorNotificationExecutionInterceptor.execute(MessageProcessorNotificationExecutionInterceptor.java:107)
    at org.mule.execution.MessageProcessorExecutionTemplate.execute(MessageProcessorExecutionTemplate.java:44)
    at org.mule.processor.BlockingProcessorExecutor.executeNext(BlockingProcessorExecutor.java:88)
    at org.mule.processor.BlockingProcessorExecutor.execute(BlockingProcessorExecutor.java:59)
    at org.mule.execution.ExceptionToMessagingExceptionExecutionInterceptor.execute(ExceptionToMessagingExceptionExecutionInterceptor.java:24)
    at org.mule.execution.MessageProcessorExecutionTemplate.execute(MessageProcessorExecutionTemplate.java:44)
    at org.mule.processor.BlockingProcessorExecutor.executeNext(BlockingProcessorExecutor.java:98)
    at org.mule.processor.BlockingProcessorExecutor.execute(BlockingProcessorExecutor.java:59)
    at org.mule.interceptor.AbstractEnvelopeInterceptor.processBlocking(AbstractEnvelopeInterceptor.java:58)
    at org.mule.processor.AbstractRequestResponseMessageProcessor.process(AbstractRequestResponseMessageProcessor.java:47)
    at org.mule.execution.ExceptionToMessagingExceptionExecutionInterceptor.execute(ExceptionToMessagingExceptionExecutionInterceptor.java:24)
    at org.mule.execution.MessageProcessorNotificationExecutionInterceptor.execute(MessageProcessorNotificationExecutionInterceptor.java:107)
    at org.mule.execution.MessageProcessorExecutionTemplate.execute(MessageProcessorExecutionTemplate.java:44)
    at org.mule.processor.BlockingProcessorExecutor.ex...
********************************************************************************

INFO  2015-12-16 09:59:49,194 [[epsilon-adobe].HTTP_Listener_Configuration.worker.01] org.mule.api.processor.LoggerMessageProcessor: Errorrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrpayload : null

虽然9对于普通模具来说有点不同寻常,但人们不得不钦佩这种解决方案中优质品质的完美结合,这种解决方案可以成为最快,最简单,最便于缓存和最便携的解决方案。通过用4代替9得到一个完美的生成器,用于任何类型的龙与地下死,同时仍然避免符号载荷的值1,2和3.唯一的小缺陷就是,因为Dilbert的脾气不好。会计巨魔,这个程序实际上会产生不明确的行为。

答案 3 :(得分:11)

如果RAND_MAX为32767,则可以轻松地将位数加倍。

int BigRand()
{
    assert(INT_MAX/(RAND_MAX+1) > RAND_MAX);
    return rand() * (RAND_MAX+1) + rand();
}

答案 4 :(得分:9)

如果可以,请使用Boost。我对他们的random library祝你好运。

uniform_int应该做你想做的事。

答案 5 :(得分:8)

如果您担心随机性而不是速度,则应使用安全的随机数生成方法。有几种方法可以做到这一点......最简单的方法是使用OpenSSL's Random Number Generator

您也可以使用加密算法(如AES)编写自己的算法。通过选择种子和IV,然后不断重新加密加密函数的输出。使用OpenSSL更容易,但不那么有男子气概。

答案 6 :(得分:5)

您应该查看特定编译器/环境的RAND_MAX。 我想如果rand()产生一个随机的16位数字,你会看到这些结果。 (您似乎假设它将是一个32位数字。)

我不能保证这是答案,但请发布您的RAND_MAX值,并详细了解您的环境。

答案 7 :(得分:3)

检查系统中的RAND_MAX是什么 - 我猜它只有16位,而且你的范围太大了。

除此之外,请参阅以下讨论:Generating Random Integers within a Desired Range以及使用(或不使用)C rand() function的说明。

答案 8 :(得分:2)

这不是代码,但这个逻辑可以帮到你。

static double rnd(void)
{
return (1.0/(RAND_MAX+1.0)*((double)(rand())) );
}

static void InitBetterRnd(unsigned int seed)
{
register int i;
srand( seed );
for( i=0; i<POOLSIZE; i++){
pool[i]= rnd();
}
}

 static double rnd0_1(void)
 {  // This function returns a number between 0 and 1
static int i=POOLSIZE-1;
double r;

i = (int)(POOLSIZE*pool[i]);
r=pool[i];
pool[i]=rnd();
return (r);
}

答案 9 :(得分:2)

如果您希望数字在该范围内均匀分布,则应将您的范围分成若干相等的部分,以表示您需要的点数。然后获得每个部分的最小/最大随机数。

另外注意,你可能不应该使用rand(),因为它实际上并不是很好地生成随机数。我不知道你正在运行什么平台,但可能有一个更好的功能,你可以像random()一样调用。

答案 10 :(得分:1)

只要整个范围小于RAND_MAX,这应该在[low, high)范围内提供均匀分布而不使用浮点数。

uint32_t rand_range_low(uint32_t low, uint32_t high)
{
    uint32_t val;
    // only for 0 < range <= RAND_MAX
    assert(low < high);
    assert(high - low <= RAND_MAX);

    uint32_t range = high-low;
    uint32_t scale = RAND_MAX/range;
    do {
        val = rand();
    } while (val >= scale * range); // since scale is truncated, pick a new val until it's lower than scale*range
    return val/scale + low;
}

对于大于RAND_MAX的值,您需要类似

的内容
uint32_t rand_range(uint32_t low, uint32_t high)
{
    assert(high>low);
    uint32_t val;
    uint32_t range = high-low;
    if (range < RAND_MAX)
        return rand_range_low(low, high);
    uint32_t scale = range/RAND_MAX;
    do {
        val = rand() + rand_range(0, scale) * RAND_MAX; // scale the initial range in RAND_MAX steps, then add an offset to get a uniform interval
    } while (val >= range);
    return val + low;
}

这大致是std :: uniform_int_distribution的工作方式。

答案 11 :(得分:0)

man 3 rand给出1到10之间的数字的解决方案是:

j = 1 + (int) (10.0 * (rand() / (RAND_MAX + 1.0)));

在你的情况下,它将是:

j = min + (int) ((max-min+1) * (rand() / (RAND_MAX + 1.0)));

当然,这不是完美的随机性或一致性,正如其他一些消息所指出的那样,但这对大多数情况来说已经足够了。

答案 12 :(得分:0)

就其性质而言,随机数的一小部分样本不必均匀分布。毕竟,它们是随机的。我同意,如果一个随机数生成器生成的数字始终显示为分组,那么它可能有问题。

但请记住,随机性不一定是均匀的。

编辑:我添加了“小样本”以澄清。

答案 13 :(得分:0)

@Solution ((double) rand() / (RAND_MAX+1)) * (max-min+1) + min

警告:不要忘记由于拉伸和可能的精度错误(即使RAND_MAX足够大),您也只能生成均匀分布的“分档”而不是所有数字[最小值,最大值]。


@Solution:Bigrand

警告:请注意,这会使这些位加倍,但仍然无法生成您范围内的所有数字,也就是说,BigRand()不一定会生成所有数字数字介于其范围内。


信息:只要rand()的范围超出您的间隔范围且rand()为“uniform”,您的方法(modulo)就会“很好”。最多第一个最大 - 最小数字的误差是1 /(RAND_MAX +1)。

另外,我建议在C ++ 11中切换到新的random package e,它提供了比rand()更好和更多种类的实现。

答案 14 :(得分:0)

当然,以下代码不会为您提供随机数,而是伪随机数。 使用以下代码

#define QUICK_RAND(m,n) m + ( std::rand() % ( (n) - (m) + 1 ) )

例如:

int myRand = QUICK_RAND(10, 20);

您必须致电

srand(time(0));  // Initialize random number generator.

否则数字将不会是随机的。

答案 15 :(得分:0)

这是我想出的解决方案:

#include "<stdlib.h>"

int32_t RandomRange(int32_t min, int32_t max) {
    return (rand() * (max - min + 1) / (RAND_MAX + 1)) + min;
}

这是一个存储桶解决方案,在概念上类似于使用rand() / RAND_MAX来获得0-1之间的浮点范围然后将其舍入到存储桶中的解决方案。但是,它使用纯整数数学运算,并利用整数除法底限将值四舍五入到最接近的存储桶。

进行一些假设。首先,假设RAND_MAX * (max - min + 1)始终适合int32_t内。如果RAND_MAX是32767,并且使用32位int计算,则最大范围是32767。如果您的实现具有更大的RAND_MAX,则可以通过使用更大的整数(例如{{1} })进行计算。其次,如果使用int64_tint64_t仍为32767,则在大于RAND_MAX的范围内,您可能会在可能的输出数字中发现“空洞”。对于缩放RAND_MAX衍生的任何解决方案,这可能都是最大的问题。

尽管如此,对大量迭代进行测试仍然表明,该方法对于较小的范围非常统一。但是,从数学上讲,这可能会(并且可能)具有一些小的偏差,并且当范围接近rand()时可能会产生问题。自己进行测试,然后确定它是否满足您的需求。

答案 16 :(得分:-3)

我刚刚在互联网上找到了这个。这应该有效:

DWORD random = ((min) + rand()/(RAND_MAX + 1.0) * ((max) - (min) + 1));