在C++中生成随机数的问题

3
我使用了以下代码(从网上复制而来),成功生成了一些随机数的数组。
std::default_random_engine generator;
std::uniform_real_distribution<double> distribution(0,1);

int N;
std::cout<< "Please enter the number of disks to be generated: ";
std::cin>> N;

// generates N pairs of coordinates
double** R;
R = new double* [N];
for (int i=0; i<N; i++) {
    R[i] = new double [3];
    for (int j=0; j<3; j++) {
        R[i][j] = distribution(generator);
    }
}

问题在于输出总是相同的,所以我认为它没有被适当地种子化。然后我从网上找到了下面的代码,但它在我的计算机上不起作用(我总是得到运行时错误)。
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_real_distribution<> dis(1, 2);
for (int n = 0; n < 10; ++n) {
    std::cout << dis(gen) << ' ';
}
std::cout << '\n';

上述代码有什么问题?如何使我的代码具有随机性,以便每次运行时得到不同的输出?此外,对于第一个代码,是否使用了线性同余算法?如何使用“更好”的算法,比如Mersenne Twister (mt19937)?
谢谢。

1
第二个片段对我有效。错误在其他地方。 - Ivan Aksamentov - Drop
@Drop 在 gcc 上可以正常工作,但在其他平台/编译器上可能无法运行。 - ForEveR
@Tino Didriksen 如果我使用向量,它不是一维的吗?我只是想让它变成二维的,这样对我来说“看起来”更好。 - Physicist
1
@Physicist std::vector<std::vector<double> > 是一个二维向量。 - ForEveR
2D向量在可以使用1D和一些简单的数学计算时有点丑陋,但仍然比嵌套new[]好。或者,您可以使用Boost.Multi_array。 - Tino Didriksen
显示剩余5条评论
3个回答

4

default_random_engine是实现定义的。这意味着它使用的算法未指定。

您收到哪个runtime_error?它应该可以正常工作,但作为解决方法,您可以像srand一样使用当前时间来种子化mt19937

std::mt19937 gen(static_cast<std::mt19937::result_type>(std::time(nullptr)));

谢谢,现在它可以工作了,但您介意详细解释一下“static_caststd::mt19937::result_type”吗? - Physicist
@Physicist mt19937 构造函数接收类型为 result_type 的参数。time 函数将返回 time_t 类型。因此,只需将其强制转换为 result_type 类型即可。 - ForEveR

3

您需要在构造函数中明确用诸如以下内容显式地对随机数生成器进行初始化(此示例使用系统时钟来唯一地对生成器进行初始化):

  // obtain a seed from the timer
  unsigned seed = myclock::now().count();
  //construct the generator
  std::default_random_engine generator(seed);

0

在随机数生成器中,您需要提供一个随机种子。(顺便说一句,默认情况下,在生成器中产生相同的数字是为了测试结果可以预测)。我使用系统时间作为种子,正如其他人所展示的那样。

有一种方法我没有看到被提及,那就是std::seed_seq,它处理了这个问题。输入几个整数,它就会产生一个不错的种子序列:

#include <random>
#include <vector>
#include <array>
#include <iostream>
#include <iomanip>
#include <chrono>

unsigned long
system_now()
{
  std::chrono::system_clock::time_point now{std::chrono::system_clock::now()};
  std::chrono::system_clock::duration epoch{now.time_since_epoch()};
  return static_cast<unsigned long>(now.time_since_epoch().count());
}

int
main()
{
    // ...
    auto N = 500;

    std::vector<std::array<double, 3>> R(N);

    std::seed_seq seq{1, 2, 3, 4, 5};
    std::vector<std::uint32_t> seeds(1000);
    seq.generate(seeds.begin(), seeds.end());

    std::mt19937 generator(seeds[system_now() % seeds.size()]);
    std::uniform_real_distribution<double> distribution{0.0, 1.0};

    for (auto & V : R)
        for (auto & C : V)
            C = distribution(generator);

    for (const auto & V : R)
    {
        std::cout << '(';
        for (const auto & C : V)
            std::cout << ' ' << std::setw(10) << C;
        std::cout << " )\n";
    }
}

警告!种子序列也是可重复的 - 使用相同的输入将返回相同的输出!此外,使用1000个种子,您最终会再次设置相同的数字。同样的种子,生成相同的数字。


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