C++11随机数生成

23

我需要生成随机数,但希望尽可能宽的范围(至少64位)。我不在乎分布是否完美,所以std::rand() 可以工作,但它只返回一个 int。我知道 c++11 有一些可以生成任意大小数字的随机数生成能力,但使用起来非常复杂。有人可以发布一个简单的示例,说明如何尽可能简单地使用它获取所需功能(64位或更多随机数),其实现方式与 std::rand() 类似吗?

3个回答

37

以下是如何使用C++11的随机数生成器来实现此目的(修改自http://en.cppreference.com/w/cpp/numeric/random/uniform_int_distribution):

#include <random>
#include <iostream>
int main()
{
  /* Initialise. Do this once (not for every
     random number). */
  std::random_device rd;
  std::mt19937_64 gen(rd());

  /* This is where you define the number generator for unsigned long long: */
  std::uniform_int_distribution<unsigned long long> dis;

  /* A few random numbers: */    
  for (int n=0; n<10; ++n)
    std::cout << dis(gen) << ' ';
  std::cout << std::endl;
  return 0;
}

使用cstdint中的std::uintmax_t,而不是unsigned long long,可以获取最大的整数范围(无需使用实际的大整数库)。


1
这对于几乎所有的用途来说已经足够好了,但请注意,它只为种子提供sizeof(unsigned)字节的熵。如果您需要更多,请在mt19937的构造函数中传递std::seed_seq,以传递尽可能多的随机字节。 - Jeffrey Yasskin
1
假设您只需要一个64位的u_long,它与mt19937_64的输出类型相同,在这种情况下使用uniform_int_distribution是否有任何理由? - HammeIAm
1
@HammeIAm 不,我认为可以不用 uniform_int_distribution,因为梅森旋转器本身就会努力产生均匀分布。 - jogojapan

15

我们可以很容易地将一个随机数生成器引擎封装成类似于 srand/rand 的方法,如下所示:

#include <random>
#include <iostream>

struct MT19937 {
private:
    static std::mt19937_64 rng;
public:
    // This is equivalent to srand().
    static void seed(uint64_t new_seed = std::mt19937_64::default_seed) {
        rng.seed(new_seed);
    }

    // This is equivalent to rand().
    static uint64_t get() {
        return rng();
    }
};

std::mt19937_64 MT19937::rng;


int main() {
    MT19937::seed(/*put your seed here*/);

    for (int i = 0; i < 10; ++ i)
        std::cout << MT19937::get() << std::endl;
}

(就像srandrand一样,此实现不关心线程安全性。)

封装函数非常简单,您可以直接使用引擎。

#include <random>
#include <iostream>

static std::mt19937_64 rng;

int main() {
    rng.seed(/*put your seed here*/);

    for (int i = 0; i < 10; ++ i)
        std::cout << rng() << std::endl;
}

2
不幸的是,std::mt19937_64::default_seed 被标准化为 5489u,因此您的示例程序将始终生成相同的输出序列。 - Jeffrey Yasskin
4
是的,就像在srand()中一样,你需要提供自己的种子才能获得不同的随机数序列。 - kennytm

3

不是C++11,但足够简单

((unsigned long long)rand() << 32) + rand() 在这里我们将int64生成为两个int32的部分

正如JasonD所指出的那样,它假设rand()生成32位整数。可以使用异或运算符rand() << xrand() << (2*x)rand() << (3*x)等来生成rand()数字中产生的位数小于等于x的数字。这也应该没问题。


15
假设rand()函数返回一个32位的数字,但实际上可能只有31位或15位。请注意,这里只要求翻译内容,不得添加解释或其他内容。 - JasonD
2
@JasonD 是的,@RiaD 应该检查 RAND_MAX 来确定这一点。 - user152949
1
在Microsoft cl中,直到当前的19.x版本,RAND_MAX为0x7FFF,即15位。 - kkm

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接